Relational databases store data in multiple tables (one table per entity type) with relationships between the tables as required.
In Django, we define relationships by including a OneToOne, ForeignKey or ManyToMany field on the model. The field we need depends on what type of relationship exists between the two tables.
This post will focus on the implementation of foreign keys, but first, let’s recap when we’d use each type of relationship:
One To One
A user can have one profile and a profile can only belong to one user.
One To Many / Many to One
A post can have one author but an author can have multiple posts.
A post can have multiple comments but a comment can only belong to one post.
Many To Many
A blog post can have multiple tags and a tag can have multiple blog posts.
The table below summarises what field you need for each kind of relationship. Today, we are going to focus on how to use a Foreign Key, the field used for One-to-Many and Many-to-One relationships.
Case Study: blog
Below is a schema for a blog with users.
Users can publish posts and they can leave comments on the posts of other users.
How to Use Foreign Keys in Django Models
Let’s turn this into code. Here is
So what goes into a Foreign Key?
The first thing we must set is which model we are setting the relationship with. A comment can have one post, so we set a Foreign Key on the Comment model and point it to the Post model.
post = models.ForeignKey(to=Post, ...)
on_delete argument specifies what should happen when the referenced object is deleted. In a One-to-Many or Many-to-One relationship, it is asking what do you do with the Many when the One is deleted. In our example, it is asking what to do with the comments when their post is deleted.
Your options include
We have used
CASCADE for the foreign key on Comment to Post. This means, when we delete the post, we will also delete the comments.
If we were to use
PROTECT , then we would be unable to delete the post until we have deleted the comments.
When you define a relationship between models, the Foreign Key only goes on one of the models, never both. It always goes on the model of Many and reference the model of the One.
related_name argument lets you specify how to access the reverse relationship.
The Comment model has a ForeignKey to the Post model. However, you still might want to find all the comments for a given post.
What you must not do is add a new attribute to the Post model called ‘comments’. Instead, you set the related name on the Foreign Key of the Comment model. By setting the related name to “comments”, you can access all the comments belonging to one post through
Model is not defined
You might get errors saying something along the lines of
"Post" is not defined.
This happens when the model you’re pointing your Foreign Key at is defined later on in the file. So if your Comment model has a Foreign Key pointing at the Post model, you must define your Post model before defining Comment.
If you get this error, it means that there is a Foreign Key in your models that hasn’t set a value for
on_delete . Set it to either
TypeError: __init__() missing 1 required positional argument: 'on_delete'
Foreign keys are used to define relationships between tables when there is a one-to-many or many-to-one relationship between the tables.
One example is the relationship between a blog post and comments. A post can have multiple comments but a comment can only belong to one post.
Foreign Keys are always defined on the model that can only have one of the other. This means we set the Foreign Key on the Comment model, not the Post model.
By setting the “related_name”, you can access all comments for a given post without adding anything to the Post model.
Django has a rule where you have to set the “on_delete” attribute of Foreign Keys. Here, you are instructing Django what to do with the comments when the linked post is deleted (delete them or keep them).