Django UniqueConstraint - PullRequest
       42

Django UniqueConstraint

0 голосов
/ 07 мая 2019

Контекст

У меня есть модели AppVersion, App & DeployApp. В модели AppVersion пользователи могут загружать файлы APK в файловую систему. Я использую сигнал pre_save, чтобы предотвратить загрузку файлов APK с таким же version_code для определенного App, например:

@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 ]

1 голос
/ 07 мая 2019

Решено благодаря Медведю Брауну за его предложение.Я удалил сигнал и добавил UniqueConstraint к модели AppVersion следующим образом:

class Meta:
    db_table = 'app_version'
    constraints = [
        models.UniqueConstraint(fields=['app_uuid', 'version_code'], name='unique appversion')
    ]
0 голосов
/ 07 мая 2019

Как сделать так, чтобы исключение происходило только при создании нового AppVersion и не происходит при добавлении или редактировании Экземпляр DeployApp?

Существующие экземпляры AppVersion заполнили поля первичного ключа. Вы можете вернуться из сигнала, когда экземпляры pk не None, что означает, что экземпляр редактируется, а не создается.

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

(Извините, у меня недостаточно представителей для комментариев. Надеюсь, это поможет).

...