Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django model constraint for related objects

I have the following code for models:

class Tag(models.Model):
    user = models.ForeignKey('auth.User', on_delete=models.CASCADE)

class Activity(models.Model):
    user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag, through='TagBinding')

class TagBinding(models.Model):
    tag = models.ForeignKey(Tag)
    activity = models.ForeignKey(Activity)

I want to write a database constraint on the TagBinding model using a new Django 2.2 syntax. This constraint should check that tag and activity fields of the TagBinding model have the same user. What I've tried to do:

class TagBinding(models.Model):
    tag = models.ForeignKey(Tag)
    activity = models.ForeignKey(Activity)

    class Meta:
        constraints = [
            models.CheckConstraint(
                name='user_equality',
                check=Q(tag__user=F('activity__user')),
            )
        ]

But this doesn't work because Django doesn't allow to use joins inside of the F function. Also Subquery with OuterRef didn't work for me because models that were referenced in a query were not registered.

Is there any way I can implement this constraint using a new syntax without raw SQL?

Update

It seems like some SQL backends don't support joins in constraints definition, so the question now: is it even possible to implement this behavior in the relational database?

like image 320
Andrey Volkov Avatar asked Mar 19 '19 13:03

Andrey Volkov


People also ask

How does Django implement one to many relationship?

To define a one to many relationship in Django models you use the ForeignKey data type on the model that has the many records (e.g. on the Item model).

What is ForeignKey in Django?

Introduction to Django Foreign Key. A foreign key is a process through which the fields of one table can be used in another table flexibly. So, two different tables can be easily linked by means of the foreign key. This linking of the two tables can be easily achieved by means of foreign key processes.

What is UniqueConstraint in Django?

UniqueConstraint. condition. A Q object that specifies the condition you want the constraint to enforce. For example: UniqueConstraint(fields=['user'], condition=Q(status='DRAFT'), name='unique_draft_user')

What is model relationship Django?

Django models operate by default on relational database systems (RDBMS) and support relationships. Django Follows the 3 model Relationships: 1- One-To-One Relationship. 2- One-To-Many Relationship. 3- Many-To-Many Relatiosnship.


1 Answers

In Postgres, there are two types of constraints (other than things like unique and foreign key constraints), CHECK CONSTRAINTS and EXCLUDE constraints.

Check constraints can only apply to a single row.

Exclusion constraints can only apply to a single table.

You will not be able to use either of these to enforce the constraint you want, which crosses table boundaries to ensure consistency.

What you could use instead are trigger-based constraints, that can perform other queries in order to validate the data.

For instance, you could have a BEFORE INSERT OR UPDATE trigger on the various tables that checks the users match. I have some similar code that runs on same self-relation tree code that ensures a parent and child both have the same "category" as one another.

In this case, it's going to be a bit trickier, because you would need some mechanism of preventing the check until all tables involved have been updated.

like image 130
Matthew Schinckel Avatar answered Oct 01 '22 03:10

Matthew Schinckel