Django的UniqueConstraint

时间:2019-05-07 13:44:26

标签: python django unique-constraint

上下文

我有模型AppVersionAppDeployApp。在AppVersion模型中,用户可以将APK文件上传到文件系统。我正在使用pre_save信号来阻止为特定的version_code上传具有相同App的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信号将被调用并引发异常。

我还尝试为save()模型覆盖AppVersion方法,但结果是相同的。

如何确保异常仅在创建新的AppVersion实例时发生,而在添加或编辑DeployApp实例时不会发生?

2 个答案:

答案 0 :(得分:1)

感谢贝尔·布朗的建议,解决了这个问题。我删除了信号,然后将UniqueConstraint添加到AppVersion模型中,如下所示:

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

答案 1 :(得分:0)

  

如何确保仅在创建新的异常时发生   AppVersion实例,添加或编辑   DeployApp实例?

现有的AppVersion实例已填充主键字段。当实例pk不为None时,您可能会从信号返回,这意味着实例将被编辑而不是创建。

@receiver(pre_save, sender=AppVersion)
def prevent_duplicate_version_code(sender, instance, **kwargs):
    if instance.pk is None: return
    # ...

(对不起,我没有足够的评论来发表评论。希望这会有所帮助)。