Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django非主键自动字段_Python_Django_Django Models - Fatal编程技术网

Python Django非主键自动字段

Python Django非主键自动字段,python,django,django-models,Python,Django,Django Models,我们正在迁移并对Oracle数据库进行必要的更改,一个主要的更改是我们将添加一个UUIDField作为所有模型的主键(对客户端隐藏),并(尝试添加)一个常规的自动字段 我们发现直接向我们的客户显示主键不是一个好的设计,但他们也要求显示一个ID字段以更容易地引用对象,但Django通过不允许AutoField不是主键来限制这一点 有解决这个问题的方法吗?我认为可行的方法是使用一个整型字段(与自动字段在引擎盖下使用的方法差不多),并在模型第一次保存时(将其放入数据库之前)增加该值 我在下面编写了一个

我们正在迁移并对Oracle数据库进行必要的更改,一个主要的更改是我们将添加一个
UUIDField
作为所有模型的主键(对客户端隐藏),并(尝试添加)一个常规的
自动字段

我们发现直接向我们的客户显示主键不是一个好的设计,但他们也要求显示一个ID字段以更容易地引用对象,但Django通过不允许
AutoField
不是主键来限制这一点


有解决这个问题的方法吗?

我认为可行的方法是使用一个
整型字段
(与
自动字段
在引擎盖下使用的方法差不多),并在模型第一次保存时(将其放入数据库之前)增加该值

我在下面编写了一个示例模型来说明这一点

来自django.db导入模型的

类MyModel(models.Model):
#这是保存时要增加的值
#将该值默认为1作为起点
display\u id=models.IntegerField(默认值=1)
#其余的模型数据
def保存(自身、*args、**kwargs):
#这意味着模型尚未保存到数据库中
如果是自我状态,则添加:
#从数据库中获取最大显示id值
last_id=self.objects.all().aggregate(最大值=models.Max('display_id'))['maxist']
#聚合可以返回无!先检查一下。
#如果不是none,只需使用指定的最后一个ID(应该是最大的)并向其中添加一个
如果last_id不是None:
self.display\u id=last\u id+1
超级(MyModel,self).save(*args,**kwargs)

从理论上讲,这只是复制了
AutoField
的功能,只是使用了不同的模型字段。

您也可以使用count作为自动增量。在我的项目中,我是这样使用的

def ids():
    no = Employee.objects.count()
    if no == None:
        return 1
    else:
        return no + 1
emp_id = models.IntegerField(('Code'), default=ids, unique=True, editable=False)

假设所选DBMS中没有序列支持,解决方案是创建一个模型:

class Counter(models.Model):
    count = models.PositiveIntegerField(default=0)

    @classmethod
    def get_next(cls):
        with transaction.atomic():
            cls.objects.update(count=models.F('count') + 1)
            return cls.objects.values_list('count', flat=True)[0]

并在数据迁移中创建一个实例。如果您使用事务管理,这可能会产生一些影响,但它(如果您的DBMS支持事务)保证始终返回下一个数字,而不管事务开始时有多少个对象,以及是否有任何对象已被删除。

是什么使它仅在模型第一次保存时触发?@Mojimi,我只是更新了我的答案,因为另一个在某种程度上有问题。检查主键是否不存在可用于
AutoField
主键,但不用于
UUIDField
。但在Django本身中,它包含一个带有添加字段的
\u状态
。如果正在创建且未更新此对象,则返回
True
,这意味着首先保存/创建模型。对此表示歉意:)过了一段时间,我在想,是否可以用另一种方法来实现,将默认值分配给一个与您上面的代码几乎相同的函数,并使用lambda将模型作为参数传递,这样就不需要覆盖每个函数的save方法model@Mojimi是的,那也行。此时,您只需将该字段的默认值设置为您所说的,一个代码基本相同的函数。@Tinfoilboy这不是最好的方法,因为在以下情况下不起作用。1.如果同时添加两个项目,并且在一个事务中完成,那么最终两个项目将看到相同的最大值并获得相同的编号。2.如果你删除了最后一个项目,下一个项目的编号将与你的相同(可能是,也可能不是你需要的编号)。对整个表执行聚合请求是非常浪费的。一个更好的解决方案是创建一个专用的计数器模型,或者查看DBMS的本机序列支持(如果有的话)。删除一名员工会如何处理?新的计数将与上一个员工的id相同。啊!。。。是的,对不起,我的错。如果是这样,我有另一个解决办法。我们可以使用(aggergate)def id():no=Employee.objects.all().aggregate(最大=models.Max('emp_id'))['magnet']print(“Object”,no),如果no==None:return 1 else:return no+1 emp_id=models.IntegerField('Code'),default=id,unique=True,editable=False)不仅如此,对于任何大型数据库来说,速度都会非常慢@phihag如果你的DBMS不支持事务(比如SQLite或MySQL和一些引擎),你可能会遇到这个问题,这就是为什么我说:“这(几乎)是有保证的”。哦,我的错。你是对的;正在更新数据库行。我以前的话是胡说八道。我的编辑正确吗?@phihag不太正确。如果删除计数器表中用于计数的第一个对象,显然会丢失序列。我也不认为向表中添加其他对象有什么好处。虽然这里有两个很好的答案,但这里有另一个潜在的解决方案: