DEV Community

Cover image for How to Handle Relationships with Django
Ishan Tiwari
Ishan Tiwari

Posted on

How to Handle Relationships with Django

Relationships become really tricky if you have a data managing backend with scores of data to handle with interconnections. This post tends to remove that jargon from your head.

There are a lot of ways to do handle a thing in django. One is the opinionated way and other ways are potholes to look our for. So, we will discuss the use cases for using these relationships as well. Let's go.

Foreign keys and reverse accessors.

If you must have seen a error during this type of code in Django.

   class Post(models.Model):
      sender = models.ForeignKey(User, on_delete=models.CASCADE)
      receiver = models.ForeignKey(User, on_delete=models.CASCADE)
Enter fullscreen mode Exit fullscreen mode

The error should say that, "Reverse accessor for 'Post.sender' clashes with reverse accessor for 'Post.receiver'."

The thing is that django does not know how to access a users created posts(i.e the posts they are a sender of) and how to access their received posts (i.e the posts they are a receiver of).

To solve this confusion it is best to add a related_name argument. This let's you access a users received and sent posts.

   class Post(models.Model):

      sender = models.ForeignKey(User, on_delete=models.CASCADE, related_name='sentposts')
      receiver = models.ForeignKey(User, on_delete=models.CASCADE, related_name='receivedposts')
Enter fullscreen mode Exit fullscreen mode

This way you can access the sent and received posts via

alan = User.objects.get(pk=1) #Got the user
posts_sent = alan.sentposts #Got the posts!!
Enter fullscreen mode Exit fullscreen mode

more about that here

One to One relationships and illegal accounts

Suppose you have a nice twitter like app you want add more functionality to the user perhaps give him his own profile picture a bio and all that you want to have a profile for him. So you do this -:

class Profile(models.Model):
     user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="profile")
     bio = models.CharField(max_length=400)
Enter fullscreen mode Exit fullscreen mode

Everything just looks fine here, but this is a big mistake.
This mistake marks the difference between all these joins.
Here, you not only want a Profile to be associated with a user but a unique user. Here, at least theoretically a user can have another Profile which is just as much his. You can stop that in the Frontend but what's the point if you can stop that in the backend. For a user to have a profile you can do.

class Profile(models.Model):
     user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
     bio = models.CharField(max_length=400)
Enter fullscreen mode Exit fullscreen mode

This saves your time your brain and your app.

More about this here

Many to Many Fields and Technical Jargon

Suppose you want a book library app. A book can be written by many authors and an author can also write many books. One To One relationship won't at all work, so will Foreign Key because after all it is just a property like a post can have a single sender and a receiver that's clear what many people do is have an intermediary like this -:

class Author_list(models.Model):
     Author1 = models.ForeignKey(User, related_name="author1")
     Author2 = models.ForeignKey(User, related_name="author2"

class Book(models.Model):
     author = models.ForeignKey(Author_list)
Enter fullscreen mode Exit fullscreen mode

As you can see this method can just accommodate a few authors and what do you do if a book has just one? Maybe set a few things to a null able value and then try. This method can is vulnerable to a lot of scale related issues. Instead just user the Many To Many relationship.

All that is different between this and Foreign Key is that Foreign stores one value as column in your database and this stores a whole list of them. Think of it as a list of users who have written their masterpiece.


class Book(models.Model):
     author = models.ManyToMany(User, related_name="books")
Enter fullscreen mode Exit fullscreen mode

More information on that here

Conclusion

Hope you enjoyed reading the post. Many many happy wishes for your relationship with django.

Cover Image by Tú Anh from Pixabay

Top comments (0)