Inheritance 如何更改Django模型子类中的字段参数?

Inheritance 如何更改Django模型子类中的字段参数?,inheritance,django-models,default-value,Inheritance,Django Models,Default Value,假设我有一个Django模型,它是一个抽象基类: class Foo(models.Model): value=models.IntegerField() class Meta: abstract = True 它有两个派生类,我希望每个子类的字段的默认值是不同的。我不能简单地覆盖这个字段 class Bar(Foo): value=models.IntegerField(default=9) 因为Django不允许覆盖子类中的字段。我看过一些关于尝

假设我有一个Django模型,它是一个抽象基类:

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

    class Meta:
        abstract = True
它有两个派生类,我希望每个子类的字段的默认值是不同的。我不能简单地覆盖这个字段

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

因为Django不允许覆盖子类中的字段。我看过一些关于尝试更改可用选项的帖子,但在这种情况下,我最关心的是更改默认值。有什么建议吗?

我认为你想做的是不可能的,至少在Django是不可能的。您必须将Django中的继承视为超类的外键(基本上就是这样),并且不能更改FK关系中属性的默认值

因此,最好的方法是重新定义
save()
方法。可能是这样的:

def save(self, *args, **kwargs):
    if not self.value:
        self.value = 9
    super(Bar, self).save(*args, **kwargs)
在Foo(超级课堂)中:


避免数据库出现非空问题。

另一个答案中建议重新定义保存方法的问题是,在保存模型对象之前,不会设置值。 另一个没有这个问题的选项是在子类(Bar类)中重新定义
\uuuuu init\uuuu

这定义了一个(和一个基类),它为所有子类提供一个给定类型的字段,默认值可以在子类中设置,但不必是:

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的要求进行操作。

请参见:

实际上,您可以按如下方式执行此操作:

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...

如果我只是为基类中的所有元素定义默认值,那么我们是否可以覆盖所有子类的save方法,或者基类中定义的默认值是否会导致实例变量永远不为空?(也就是说,如果我在父类中定义了一个默认值,那么该默认值是在保存或初始化对象时添加的吗?),因为该字段实际上不是来自子类,而是来自超类。我想你的意思是
Message.\u meta.get\u字段('is\u public')。默认值=True
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')
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...