我想在从抽象模型继承的所有字段上将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
属性,您应该能够从许多基类中实现,但请选择要清除哪个字段。