Django - 关于外键的AutoField

时间:2010-10-21 20:04:09

标签: python django django-models

我有一个带有唯一整数的模型,需要针对外键增加,以下代码是我当前处理它的方式:

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)

我对此有以下问题:

  1. 多人可以在互联网上为同一MyModel创建business个实例。 2个人是否可以同时创建MyModel个实例,而.count()同时为这两个实例返回500个,然后两个人同时尝试基本设置self.number = 501(引发IntegrityError)?答案似乎很明显“是的,它可能会发生”,但我不得不问。
  2. 我可以使用快捷方式或“最佳方法”(也许是处理此问题的SuperAutoField)?
  3. 我不能只打一个while model_not_saved: try:except IntegrityError:,因为模型中的其他限制可能导致无限循环,而且比切尔诺贝利更糟糕的灾难(可能不是非常糟糕的。)

1 个答案:

答案 0 :(得分:2)

您希望在数据库级别使用该约束。否则你最终会遇到你讨论过的并发问题。解决方案是将整个操作(读取,增量,写入)包装在事务中。

为什么不能使用AutoField代替PositiveIntegerField?

number = models.AutoField()

然而,在这种情况下,数字几乎肯定会等于yourmodel.id,那么为什么不使用呢?

修改

哦,我知道你想要什么。除非有MyModel.business个实例,否则您希望数字字段不会增加。

如果可以,我仍然建议您只使用id字段,因为它肯定是唯一的。如果你绝对不想这样做(也许你正在向用户显示这个数字),那么你需要在事务中包装你的save方法。

您可以在文档中阅读有关交易的更多信息:

http://docs.djangoproject.com/en/dev/topics/db/transactions/

如果您只是使用它来计算MyModel有多少FK到Business的实例,那么您应该将其作为查询而不是尝试存储计数。