Home > Net >  Can you make sure only one object related to another object has a certain field set?
Can you make sure only one object related to another object has a certain field set?

Time:04-06

I have a model called Video, and it has related objects on another model called Label. Example here:

class Video(models.Model):
    pass


class Label(models.Model):
    video = models.ForeignKey(Video, related_name="labels")
    current = models.NullBooleanField()

I need to be able to find the current label on a video by doing something like my_video.labels.filter(current=True), and this query should only ever return one label, so only one label on the video should have that field set to True.

Is there a way of ensuring this on the model/db?

Thanks

EDIT: The answer given below has achieved exactly this. Adding some django tests below for anyone else reading as some proof:

class TestLabelIntegrity(TestCase):
    def test_a_video_can_have_only_one_current_label(self):
        video = Video.objects.create()
        label_1 = Label.objects.create(
            video=video,
            current=True
        )
        with self.assertRaises(IntegrityError):
            label_2 = Label.objects.create(
                video=video,
                current=True
            )

    def test_two_different_videos_can_each_have_current_layers(self):
        """ No assertions needed, just need to make sure no integrity errors are raised"""
        video_1 = Video.objects.create()
        label_1 = Label.objects.create(
            video=video_1,
            current=True
        )
        video_2 = Video.objects.create()
        label_2 = Label.objects.create(
            video=video_2,
            current=True
        )

CodePudding user response:

I believe you can solve this using UniqueConstraint. Using this, you can restrict that a Video only have a single label that current == True

You can define the UniqueConstraint in the models Meta. You’ll get a database integrity error on save() if the condition fails.

See the documentation for this here:

https://docs.djangoproject.com/en/4.0/ref/models/constraints/

class Label(models.Model):
    ...
    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["current", "video"],
                condition=Q(current=True),
                name="unique_current_label",
            ),
        ]
  • Related