This tutorial assumes a basic knowledge of PYTHON and Django. Also it assumes you know how to create models, and manipulate them with basic querysets. If you are not confident about the aforementioned topics then this might help you.
Generic Relations are a special type of relation that Django supports where the relationship (foriegn key) is not bound to one particular table. Thus with minimal coding (or hacking, in some cases) we could have a relationship that can handle cases like Likes and Follows in social media apps, where a post, page, person or group could be liked or followed.
Before getting on to an example and syntax, let's understand the concept of Content Types.
Content types are Django's way of identifying database tables. Every Database table is represented as a row in the content type table which is created and maintained by Django. There are many operations and manipulations that you could do to a model using this Content Type module, but we will only be discussing here the portion that deals with Generic Relationships.
Since we have a Database representation of tables in these Content Type table, what Django does is use this to reference a table and then add an integer field to link to an id of that particular table, thus accomplishing a relationship coz we now the table, and its id.
Enough discussing the concept and let's delve into an example ans see the syntax along with it
In the example let's try implementing the Like functionality of a typical social media app. The like can be associated with a Page, a Post, or a Comment. We assume the models for all these are implemented and not concern us with implementing them except the Like model.
First and foremost we should include the content type module to use them in our generic relation. So add the following in INSTALLED_APPS in settings.py
# Python code # settings.py INSTALLED_APPS = [ ... 'django.contrib.contenttypes', ... ]
Lets's first look at the Like model and define the Generic Relations in it and then look at its explanation.
# Python code from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class Like(models.Model): liked_by = models.ForeignKey(User) created_at = models.DateTimeField(auto_now_add=True) # Listed below are the mandatory fields for a generic relation content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey()
content_type is the reference to the content type or the table used for the relation. The
object_id is used to store the id of the row, or kind of like a foreign key (not a foreign key though!). The
content_object property on the other hand is used as a direct reference to the object to which the like enty is related to. This
content_object field is actually just a property for the Like object for easy reference, and not stored in the database.
Once the Like model is done we need to specify which models can have a generic relation with a Like object. In our case we want the Post, Page and Comment models to be able to have generic relations to Like. So we insert the following lines of code into its' models.
# Python Code from django.db import models from django.contrib.contenttypes.fields import GenericRelation class Post(models.Model): ... likes = GenericRelation(Like) class Page(models.Model): ... likes = GenericRelation(Like) class Comment(models.Model): ... likes = GenericRelation(Like)
Now let's see how to add likes for a post. We can do it in different ways:
# Get the post object post = Post.objects.get(pk=1) # Add a like for the post post.likes.create(liked_by=request.user) # Or in a similar way using the Like model to add the like Like.objects.create(content_object=post, liked_by=request.user)
You could make your life easier by adding a reverse reference or reverse_query_name as Django calls it, to the
GenericRelation definition. And query the Like model using this reverse query name as a lookup in the queryset.
# Python Code from django.db import models from django.contrib.contenttypes.fields import GenericRelation class Post(models.Model): ... posted_by = models.ForeignKey(User) likes = GenericRelation(Like, related_query_name='post')) ... ... ... Like.objects.filter(post__posted_by__first_name='Bob')
For detailed information on
reverse_query_name refer the official Django Documentation
We develop web applications to our customers using python/django/angular.
Contact us at firstname.lastname@example.org