Основанное на классе значение по умолчанию для поля в иерархии наследования модели Django - PullRequest
5 голосов
/ 24 сентября 2010

Как можно достичь значения по умолчанию на основе классов в следующей схеме? Я имею в виду, что я хотел бы, чтобы унаследованные классы устанавливали значение по умолчанию для «числа» по-другому:

class OrderDocumentBase(PdfPrintable):
    number = models.PositiveIntegerField(default=self.create_number())

    @classmethod
    def create_number(cls):
        raise NotImplementedError

class Invoice(OrderDocumentBase):
    @classmethod
    def create_number(cls):
        return 1

class CreditAdvice(OrderDocumentBase):
    @classmethod
    def create_number(cls):
        return 2

Я посмотрел на этот вопрос о стековом потоке , но он не решает ту же проблему. Единственное, что я думал, что это сработает, это перегрузка OrderDocumentBase __init__ метода, подобного этому:

def __init__(self, *args, **kwargs):
    """
    Overload __init__ to enable dynamic set of default to number
    """
    super(OrderDocumentBase, self).__init__(*args, **kwargs)
    number_field = filter(lambda x: x.name == 'number', self._meta.fields)[0]
    number = self.__class__.create_number()
    number_field.default = number

Это работает, но только частично и ведет себя довольно странно. В административном интерфейсе я вижу настройки по умолчанию только после обновления второй или последней страницы. С первой попытки устанавливается None: (

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

Может кто-нибудь помочь?

Ответы [ 2 ]

5 голосов
/ 06 марта 2012

Приятно делать это по умолчанию =, но все, что вы там используете, не имеет возможности добраться до вашего класса или конкретной модели.Чтобы он правильно отображался в таких местах, как администратор, вы можете установить его в init () вместо save ().

class OrderDocumentBase(PdfPrintable):
    number = models.PositiveIntegerField()

    def __init__(self, *args, **kwargs):
        super(OrderDocumentBase, self).__init__(*args, **kwargs)
        if not self.pk and not self.number:
            self.number = self.DEFAULT_NUMBER

class Invoice(OrderDocumentBase):
    DEFAULT_NUMBER = 2

class CreditAdvice(OrderDocumentBase):
    DEFAULT_NUMBER = 3
2 голосов
/ 24 сентября 2010

Здесь есть пара проблем. Во-первых, self.method не будет работать. Нет self в контексте тела класса, где вы объявляете PositiveIntegerField.

Во-вторых, передача вызываемого не будет работать, так как вызываемый объект связывается во время компиляции и не изменяется во время выполнения. Так что, если вы определите, скажем,

class OrderDocumentBase(PdfPrintable):
    create_number = lambda: return 0
    number = models.PositiveIntegerField(default=create_number)

class Invoice(OrderDocumentBase):
    create_number = lambda: return 1

Все Invoice экземпляры все равно получат 0 в качестве значения по умолчанию.

Один из способов решения этой проблемы - переопределить метод save(). Вы можете проверить, не был ли указан number, и установить его по умолчанию перед сохранением.

class OrderDocumentBase(PdfPrintable):
    number = models.PositiveIntegerField()

    def save(self, *args, **kwargs):
        if not self.number:
            self.number = self.DEFAULT
        super(OrderDocumentBase, self).save(*args, **kwargs)

class Invoice(OrderDocumentBase):
    DEFAULT = 2

class CreditAdvice(OrderDocumentBase):
    DEFAULT = 3

Я протестировал вышеупомянутое с небольшим изменением (сделал OrderDocumentBase абстрактным, так как у меня не было PdfPrintable), и это сработало, как и ожидалось.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...