Unique together constraint including specific field value

后端 未结 3 1744
面向向阳花
面向向阳花 2021-02-15 10:25

For one of my models, I need to ensure the unicity of some rows, but only in a certain case. Only the \"validated\" rows should follow this constraint.

Basically, I\'

相关标签:
3条回答
  • 2021-02-15 10:47

    You can use UniqueConstraint in case you're using Django 2.2+ Here is an example

    class MyModel(models.Model):
        field_a = models.CharField()
        field_b = models.CharField()
        validated = models.BooleanField(default=False)
    
        class Meta:
            constraints = [
                UniqueConstraint(fields=['field_a', 'field_b'], condition=Q(validated=True), name='unique_field_a_field_b_validated')
            ]
    

    here is the source

    0 讨论(0)
  • 2021-02-15 10:51

    (at time of writing, in Django < 2.2)

    You can't do that with unique_together in Django, presumably because not all db backends would be able to support it.

    You can do it in the application layer with model validation instead:
    https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects

    eg

    class MyModel(models.Model):
        field_a = models.CharField()
        field_b = models.CharField()
        validated = models.BooleanField(default=False)
    
        def clean(self):
            if not self.validated:
                return
            existing = self.__class__.objects.filter(field_a=self.field_a,
                                                     field_b=self.field_b).count()
            if existing > 0:
                raise ValidationError(
                    "field_a and field_b must be unique if validated=True"
                )
    

    Note that you will probably have to call the model validation manually, i.e.

    instance.clean()
    instance.save()
    

    It is not done automatically when saving the model. On the other hand it is done automatically when using a ModelForm, i.e.

    if form.is_valid():
        instance = form.save()
    
    0 讨论(0)
  • 2021-02-15 11:07

    In addition to the previous answer you can overwrite the save() method. It would be something like this:

    def save(self, **kwargs):
        try:
            self.objects.get(field_a=self.field_a, field_b=self.field_b, validated=True)
    
            # The object already exist therefore throw an exception
            raise ValidationError(
                "field_a and field_b must be unique if validated=True"
            ) 
    
        except self.__class__.DoesNotExist:  # Save the model
            super(MyModel, self).save(**kwargs)  # inherit and call the save method
    

    Now you don't need to call the clean() method.

    0 讨论(0)
提交回复
热议问题