Django唯一约束

41

背景

我有三个模型:AppVersionAppDeployApp。在 AppVersion 模型中,用户可以将 APK 文件上传到文件系统。我使用 pre_save 信号来防止为特定的 App 上传具有相同 version_code 的 APK 文件,代码如下:

@receiver(pre_save, sender=AppVersion)
def prevent_duplicate_version_code(sender, instance, **kwargs):
    qs = AppVersion.objects.filter(app_uuid=instance.app_uuid, version_code=instance.version_code)
    if qs.exists():
        raise FileExistsError("Version code has to be unique for a specific app")

这个信号功能正常,但是在我尝试在桥接表DeployApp中创建对象时也会引发错误。

模型

# models.py

class App(models.Model):
    app_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    app_name = models.CharField(max_length=100)


class AppVersion(models.Model):
    app_version_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    app_uuid = models.ForeignKey(App, on_delete=models.CASCADE, related_name='app_versions')
    app_version_name = models.CharField(max_length=100)
    version_code = models.IntegerField(blank=True, null=True, editable=False)
    source = models.FileField(upload_to=get_app_path, storage=AppVersionSystemStorage()) 


class DeployApp(models.Model):
    deploy_app_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    app_version = models.ForeignKey(AppVersion, on_delete=models.CASCADE)
    device_group = models.ForeignKey(DeviceGroup, on_delete=models.CASCADE)
    release_date = UnixDateTimeField()

我的猜测是,在创建DeployApp对象时,相关的AppVersion也被保存了,因此会调用pre_save信号并引发异常。
我还尝试重写AppVersion模型的save()方法,但结果相同。
如何确保只有在创建新的AppVersion实例时才会出现异常,而在添加或编辑DeployApp实例时不会出现异常?

3
为什么不使用 https://docs.djangoproject.com/en/2.2/ref/models/options/#unique-together 中的 unique_together = ['app_uuid', 'app_version_name']? - Brown Bear
1
不,如果相关模型已经存在并且您只是创建一个“DeployApp”对象,则不会保存该模型。这是不可能的。您的代码中必须有明确保存“AppVersion”对象的内容。 - dirkgroten
8
unique_together 很快就会过时。请查看 UniqueConstraint - zar3bski
1个回答

96

多亏了Bear Brown的建议,我解决了这个问题。我移除了信号(signal),并像下面这样在AppVersion模型中添加了UniqueConstraint

class Meta:
    db_table = 'app_version'
    constraints = [
        models.UniqueConstraint(fields=['app_uuid', 'version_code'], name='unique appversion')
    ]

在模型中使用UniqueConstraint()时,我遇到了这个问题:(models.W044) SQL Server不支持对表达式的唯一约束。你能帮忙解决一下吗? - sodmzs1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接