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?