Как изменить аргументы поля в подклассах модели Django? - PullRequest
15 голосов
/ 25 октября 2011

Допустим, у меня есть некоторая модель Django, которая является абстрактным базовым классом:

class Foo(models.Model):
    value=models.IntegerField()

    class Meta:
        abstract = True

, и у нее есть два производных класса, где я хотел бы, чтобы значение поля по умолчанию было разным для каждого дочернего элемента.классы.Я не могу просто переопределить поле

class Bar(Foo):
    value=models.IntegerField(default=9)

, потому что Django не позволит вам переопределить поля в подклассах.Я видел сообщения о попытке изменить доступные варианты, но в этом случае меня больше всего интересует изменение значения по умолчанию.Любой совет?

Ответы [ 4 ]

8 голосов
/ 21 июля 2012

Проблема с переопределением метода сохранения, как предлагается в другом ответе, заключается в том, что ваше значение не будет установлено до тех пор, пока вы не сохраните объект модели. Другой вариант, у которого нет этой проблемы, - переопределить __init__ в дочернем классе (класс Bar):

def __init__(self, *args, **kwargs):
    if 'value' not in kwargs:
        kwargs['value'] = 9
    super(Bar, self).__init__(*args, **kwargs)
2 голосов
/ 11 ноября 2011

Я думаю, что то, что вы пытаетесь сделать, невозможно, по крайней мере, в Джанго. Вы должны видеть наследование в Django как ForeignKey для суперкласса (и это почти так), и вы не можете изменить значение атрибута по умолчанию в отношении FK.

Итак, лучшее, что вы можете сделать, это переопределить метод save(). Это было бы что-то вроде:

def save(self, *args, **kwargs):
    if not self.value:
        self.value = 9
    super(Bar, self).save(*args, **kwargs)

А, в Фу (супер-класс):

    value = models.IntegerField(blank=True)

, чтобы избежать проблем NOT NULL с базой данных.

1 голос
/ 12 августа 2015

См. https://stackoverflow.com/a/6379556/15690:

Вы можете сделать это следующим образом:

class BaseMessage(models.Model):
    is_public = models.BooleanField(default=False)
    # some more fields...

    class Meta:
        abstract = True

BaseMessage._meta.get_field('is_public').default = True

class Message(BaseMessage):
    # some fields...
1 голос
/ 21 апреля 2015

Это определяет метакласс (и базовый класс), который предоставляет всем подклассам поле данного типа со значениями по умолчанию, которые могут быть установлены в подклассе, но не должны быть:

from django.db import models
class DefaultTextFieldMetaclass(models.base.ModelBase):
    DEFAULT_TEXT = 'this is the metaclass default'

    def __new__(mcs, name, parents, _dict):
        if not (('Meta' in _dict) and hasattr(_dict['Meta'], 'abstract') and _dict['Meta'].abstract):
            # class is concrete
            if 'DEFAULT_TEXT' in _dict:
                default = _dict['DEFAULT_TEXT']
            else:       # Use inherited DEFAULT_TEXT if available
                default_set = False
                for cls in parents:
                    if hasattr(cls, 'DEFAULT_TEXT'):
                        default = cls.DEFAULT_TEXT
                        default_set = True
                if not default_set:
                    default = mcs.DEFAULT_TEXT
            _dict['modeltext'] = models.TextField(default=default)
        return super(DefaultTextFieldMetaclass, mcs).__new__(mcs, name, parents, _dict)


class BaseTextFieldClass(models.Model):
    class Meta(object):
        abstract = True
    __metaclass__ = DefaultTextFieldMetaclass
    DEFAULT_TEXT = 'superclass default'


class TextA(BaseTextFieldClass):
    DEFAULT_TEXT = 'A default for TextA'

class TextB(BaseTextFieldClass):
    DEFAULT_TEXT = 'The default for TextB'
    number = models.IntegerField(default=43)

class TextC(BaseTextFieldClass):
    othertext = models.TextField(default='some other field')

Если у вас нет подклассов и / или нескольких методов / атрибутов и предположений, которые связаны с BaseTextFieldClass, это, вероятно, излишне ... но он должен делать то, что запрашивал OP.

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