如何覆盖抽象模型的空字段和空白字段属性



我想在从抽象模型继承的所有字段上将null和空白设置为true。

我目前的尝试遵循类似的问题,例如覆盖ABC和覆盖父模型的属性上的"默认"属性,这是可能的。从Python控制台初始化对象时,我会得到所需的运行时行为,但是在迁移文件或数据库中没有反映。

上下文:

我有一个系统模型,我希望能够在某些数据上创建特定于客户端的覆盖。我有以下模型:

  • 抽象底座系统 - 定义填充的字段
  • 混凝土系统 - 包含部分覆盖的记录
  • 混凝土系统 - 包含"完整"系统记录。

在SystemOverride null/blank = true中进行所有字段很重要,以便只有初始化的字段(由客户端(覆盖相关的系统对象。

代码:

class BaseSystem(models.Model):
    class Meta:
        abstract = True
    def __init__(self, *args, **kwargs):
        super(BaseSystem, self).__init__(args, kwargs)
        # Mark all fields with 'override' attribute
        for field in self._meta.get_fields():
            field.override = True
    name = models.CharField(max_length=128)

class System(BaseSystem):
    pass

class SystemOverride(BaseSystem):
    def __init__(self, *args, **kwargs):
        super(SystemOverride, self).__init__(args, kwargs)
        # Set all overridable fields to null/blank = True. 
        for field in self._meta.get_fields():
            if(hasattr(field, 'override') and field.override):
                field.null = True
                field.blank = True
    # Override-specific fields
    system = models.ForeignKey(System)

makemigrations的结果:

class Migration(migrations.Migration):
    initial = True
    dependencies = [
    ]
    operations = [
        migrations.CreateModel(
            name='System',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=128)),
            ],
            options={
                'abstract': False,
            },
        ),
        migrations.CreateModel(
            name='SystemOverride',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=128)),
                ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='overide.System')),
            ],
            options={
                'abstract': False,
            },
        ),
    ]

null = true and blank = true尚未添加到Systemoveride中的名称字段中。

这不能在类的 init 中完成。Makemigrations永远不会看到它。您需要在Metaclass级别进行。

您可以创建一个抽象的Charfield类:

class AbstractCharField(models.CharField):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.null = True
        self.blank = True
    class Meta:
        abstract = True

# usage
name = AbstractCharField(max_length=128)

我最近正在寻找类似的东西,但找不到解决方案。但是,我确实找到了这篇文章。这是我最终提出的解决方案:

from django.db.models.base import ModelBase

class NullableInheritanceMeta(ModelBase):
    def __new__(mcs, name, bases, attrs, **kwargs):
        cls = super().__new__(mcs, name, bases, attrs, **kwargs)
        null_fields_from = cls.null_parent_fields_classes
        for parent in null_fields_from:
            for field in parent._meta.fields:
                cls._meta.get_field(field.name).null = True
        return cls

我使用了一个元素,因为我真的希望它干燥和重复使用。您可以使用此方法的方式是:

class AbstractPermissions(models.Model):
    permission1 = models.BooleanField()
    permission2 = models.BooleanField()
    permission3 = models.BooleanField()
    class Meta:
        abstract = True

class Plan(AbstractPermissions):
    pass

class PlanOverride(AbstractPermissions, metaclass=NullableInheritanceMeta):
    null_parent_fields_classes = [PermissionMixin]

多亏了null_parent_fields_classes属性,您应该能够从许多基类中实现,但请选择要清除哪个字段。

最新更新