如何在django中支持AutoField(primary_key=False)



我需要添加一个autoinc字段,该字段不是主键。我正在将一个使用自动递增字段的大型生产数据库迁移到models.UUIDField。我一直在进行分段迁移,现在我的所有关系都与这两种字段类型重复。我已经准备好进行主键交换了,但不幸的是,我仍然需要为旧客户端保留自动递增整数字段,因为它已被弃用。

由于django不允许我用primary_key=False定义自动字段(即使这在数据库层完全支持),我正在寻找一个简单的解决方案。我最初的策略是简单地将字段更改为models.BigIntegerField('GUID', db_index=True, null=True, unique=True),然后使用migrations.RunSQL手动设置默认的nextval('my_guid_seq'::regclass)。到目前为止还不错,只是不是。事实证明,由于我的null=True声明,ORM层的django将接管并插入null,这将不允许数据库层的默认值完成它的工作。

核心开发人员很快就因为糟糕的设计而拒绝了这个请求,我完全同意这一点,但也有像这样非常有效的用例。https://code.djangoproject.com/ticket/8576

我是一个非常弱的django开发人员,所以我不想在ORM层进行杂草元编程。根据定义,这是一个破解,所以我正在寻找最不复杂、最有创意的解决方案,让我绕过的限制

您可以将AutoField子类化并覆盖_check_primary_key()deconstruct()方法。

from django.db.models.fields import AutoField
from django.db.models.fields import checks

class AutoFieldNonPrimary(AutoField):
def _check_primary_key(self):
if self.primary_key:
return [
checks.Error(
"AutoFieldNonPrimary must not set primary_key=True.",
obj=self,
id="fields.E100",
)
]
else:
return []
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs["primary_key"] = False
return name, path, args, kwargs

请参阅此处的AutoField源代码。

我知道,将主键更改为UUID非常痛苦。因此,我想到的简单而更好的解决方案是添加另一个自然自动递增的整数字段。

这是我的解决方案:

class ModelName(models.Model):
auto_inc_id = models.IntegerField()

然后覆盖保存模型:

def save(self, *args, **kwargs):
self.object_list = ModelName.objects.order_by('auto_inc_id')
if len(self.object_list) == 0:  # if there are no objects
self.auto_inc_id = 1
else:
self.auto_inc_id = self.object_list.last().auto_inc_id + 1
super(ModelName, self).save()

无法将其格式化为注释,但修改@Abhimanyu的答案以使保存方法更简洁(并且只发出一个查询)。同型号属性:

class ModelName(models.Model):
auto_inc_id = models.IntegerField()

下面是模型的保存方法:

def save(self, *args, **kwargs):
self.auto_inc_id = ModelName.objects.all().count() + 1
super(ModelName, self).save()

最新更新