1

As I was searching the ways of adding the model validation I found more than one way to achieve it. For eg if my model is as follows:

from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()


class ChatThread(models.Model):
    user1 = models.ForeignKey(User, on_delete=models.CASCADE)
    user2 = models.ForeignKey(User, on_delete=models.CASCADE)
    

I want to validate such that user1 & user2 are different. Then I could have following options:

  • override the save method
  • implement clean or full_clean method
  • use signals pre_save
  • ...

What would be the best approach for these kind of task ??

4
  • 2
    For this simple validation, I would use the unique_together attribute of the Meta class of your ChatThread model. Commented Mar 17, 2021 at 13:14
  • thanks @May.D, unique_together attribute would be suitable here Commented Mar 17, 2021 at 14:39
  • 1
    @May.D adding a unique constraint is probably a good idea, however it doesn't solve the validation requirement in question. For example, inserting ChatThread(user1_id=1, user2_id=1) would pass the unique constraint, but result in identical users in the same instance. Commented Mar 17, 2021 at 15:42
  • Indeed you are right, in fact I just tested it and unique_together doesnt work for foreign keys, as explained here : stackoverflow.com/a/38081616/8237838 (see also comments). My mistake. Commented Mar 17, 2021 at 16:30

1 Answer 1

4

I would add a database level check constraint to your model, which can be done with the following:

from django.db.models import Q, F

class ChatThread(models.Model):
    user1 = models.ForeignKey(User, on_delete=models.CASCADE)
    user2 = models.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        constraints = [
            models.CheckConstraint(check=(
                ~Q(user1=F('user2'))
            ), name='check_users_not_equal')
        ]

The line Q(user1=F('user2')) checks that the user1 field is equal to the user2 field, and the tilde ~, checks that the preceding Q object is not true.

Is a database level check constraint better/more effective than the conventional methods shown above?

The general argument in favor of application-level validation is the DRY Principle. For example, if you have a model with an email field, and a database-level constraint verifying that the input is a valid email, you would end up writing the validation logic twice; once for the database-constraint, and once in the client-side code. You could forgo the client-side validation, but that would result in your users receiving generic error messages anytime they enter an invalid email.

In your specific case, I would strongly recommend database-level validation over application-level validation. If a piece of logic violates this rule (ie. user1 != user2), then it is almost guaranteed to be the result of broken code, and not user-input, which means the end user will receive a generic error message in either case.

There are more pros and cons to each approach that I didn't mention. If you want to read more on this topic, I'd start here: Should you enforce constraints at the database level as well as the application level?

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for showing this approach. Is database level check constraint is better/effective than the conventional methods shown above??
@AbishekBashyal good question! See my update on why I'd prefer a constraint in this case.
ok thnx!... really appreciate for your time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.