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

时间:2016-06-08 17:31:00

标签: django autofield

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

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

核心开发人员很快拒绝这个请求,因为设计不好,我最绝对同意,但是有非常有效的用例,比如这个。 https://code.djangoproject.com/ticket/8576

我是一个非常弱的django开发者,所以我不想在ORM层进入杂草元编程。根据定义,这是一个黑客攻击,所以我正在寻找能够解决这个限制的最简单,最有创意的解决方案

3 个答案:

答案 0 :(得分:3)

您可以继承AutoField并覆盖_check_primary_key方法。

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 []

请参阅AutoField源代码here

答案 1 :(得分:0)

我知道,将主键更改为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.sheets) is 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()

答案 2 :(得分:0)

无法将其格式化为评论,但修改@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()