Django - 外键的 AutoField 处理
我有一个模型,它有一个独特的整数,这个整数需要根据一个外键来递增。以下是我目前处理这个问题的代码:
class MyModel(models.Model):
business = models.ForeignKey(Business)
number = models.PositiveIntegerField()
spam = models.CharField(max_length=255)
class Meta:
unique_together = (('number', 'business'),)
def save(self, *args, **kwargs):
if self.pk is None: # New instance's only
try:
highest_number = MyModel.objects.filter(business=self.business).order_by('-number').all()[0].number
self.number = highest_number + 1
except ObjectDoesNotExist: # First MyModel instance
self.number = 1
super(MyModel, self).save(*args, **kwargs)
关于这个问题,我有以下几个疑问:
- 很多人可以在网上同时为同一个
business
创建MyModel
实例。假设有两个人同时在创建MyModel
实例,假如这时.count()
返回的都是500,那么两个人都试图把self.number = 501
,这样会不会导致冲突(引发一个叫做IntegrityError的错误)?答案看起来显而易见是“是的,这种情况可能会发生”,但我还是想问一下。 - 有没有什么快捷的方法,或者说“最佳方式”来处理这个问题?比如说有没有一个
SuperAutoField
可以帮我解决这个问题?
我不能简单地用 while model_not_saved:
try:
和 except IntegrityError:
这样的方式来处理,因为模型中的其他限制可能会导致无限循环,这样的后果可能比切尔诺贝利还要糟糕(虽然可能没有那么严重)。
1 个回答
2
你希望在数据库层面上设置这个限制。否则,你最终会遇到你之前提到的并发问题。解决办法是把整个操作(读取、增加、写入)放在一个事务中。
为什么不能用AutoField来代替PositiveIntegerField呢?
number = models.AutoField()
不过,在这种情况下,数字几乎肯定会等于yourmodel.id
,那为什么不直接用这个呢?
编辑:
哦,我明白你想要什么了。你想要一个数字字段,只有在MyModel.business
有多个实例时才会增加。
如果可以的话,我还是建议你直接使用id
字段,因为它肯定是唯一的。如果你绝对不想这样做(也许你是要把这个数字展示给用户),那么你就需要把保存的方法放在一个事务中。
你可以在文档中了解更多关于事务的内容:
http://docs.djangoproject.com/en/dev/topics/db/transactions/
如果你只是想统计有多少个MyModel
实例关联到Business
,那么你应该通过查询来实现,而不是试图存储一个计数。