Специальный код экземпляра модели Django - PullRequest
2 голосов
/ 20 октября 2010

в одной из моих моделей Django я должен добавить определенный код для каждого экземпляра модели.Теперь мне интересно, что было бы хорошим способом реализовать это.Моя текущая попытка приводит к большому, трудно читаемому оператору if.

Рассмотрим следующую модель:

class Foo(models.Model):
    name = models.CharField(max_length=255)

    def do_instance_specific_stuff(self, arg):
        if self.id == 1:
            do_X(arg)
        elif self.id == 2:
            do_Y(arg)
        else:
            do_Z()

Прямо сейчас есть пользовательский код для примерно 20 экземпляров модели, и он останетсяв этой величине.Любые идеи или шаблоны, как это можно реализовать чистым, читабельным способом?

Спасибо за любую помощь.

Ответы [ 2 ]

3 голосов
/ 20 октября 2010

Я бы добавил другое поле к вашей модели, vendor.Затем добавьте методы для каждого поставщика в вашу модель и вызовите их с помощью getattr:

class Foo(models.Model):
    name = models.CharField(max_length=255)
    vendor = models.CharField(max_length=50)

    def vendor_fedex(self, arg):
        blah blah

    def vendor_ups(self, arg):
        blah blah

    def vendor_usps(self, arg):
        blah blah

    def do_instance_specific_stuff(self, arg):
        fn = getattr(self, "vendor_"+self.vendor, None)
        if not fn:
            raise Exception("Uh-oh, bad vendor")
        fn(arg)

В зависимости от конкретных значений id кажется очень хрупкимВ вашей модели данных каждая строка поставщика будет отображаться только один раз, но она будет читаемой и изменяемой.Вы можете решить, что хотите сделать, если getattr не может найти код поставщика.

1 голос
/ 20 октября 2010

Обычным примером является использование dict:

stuff_per_id = {1 : do_X, 2 : do_Y, ...}
def do_instance_specific_stuff(arg):
    try:
        stuff_per_id[self.id](arg)
    except KeyError:
        do_Z()

Хотя вы действительно не должны этого делать.Гораздо лучше добавить в вашу модель дополнительное поле, которое указывает, какой код должен быть запущен на arg для этого экземпляра.В этом случае шаблон dict может по-прежнему использоваться.

Редактировать : если какая-либо из функций, специфичных для вашего экземпляра, может вызывать KeyError, то вышеприведенное выполнение do_ZЕсли вы не хотите этого, добавьте неиспользуемый аргумент в do_Z и используйте следующее:

def do_instance_specific_stuff(arg):
    try:
        f = stuff_per_id[self.id]
    except KeyError:
        f = do_Z
    f(arg)
...