You probably know that one of the main advantages of databases is the ability to store data in a set of related tables. In practice, it is often necessary to have several tables in a project. In turn, these tables can be linked to each other. There are three types of relationships in relational databases: one-to-one, one-to-many, many-to-many. All of them can be described with Django ORM.
One-to-one
Suppose you want to create a blog. Our site is sure to have a user model and a blog model. Our site has a rule that one user can only have one blog. That is, there is a relationship of one user — one blog.
The models.OneToOneField constructor can create this relationship. The first parameter of the constructor specifies which model the entity will be associated with (in our case, the association is the blog model). In addition, you must specify the second parameter on_delete that will tell the model what to do if the data is deleted. For example, you can pass models.CASCADE as a value of this parameter, which means that the data of the current model (user) will be removed if the associated object of the main model (blog) is removed. For now, we will use this mode in our examples.
In models.py, it would look like this:
class Blog(models.Model):
title = models.CharField(max_length=64)
class User(models.Model):
name = models.CharField(max_length=64)
blog_id = models.OneToOneField(Blog, on_delete=models.CASCADE)
This type of relationship is rare; you're likely to deal with the other two types.
Moreover, a one-to-one relationship is easily modeled in a single table. Table entries contain data that are in a one-to-one relationship with a primary key or record. In rare cases, a one-to-one relationship is modeled using two tables. This option is sometimes necessary to increase performance (speeding up the search of the parent table).
One-to-many
Now, let's say users can express their emotions and feelings in their articles. To accomplish this, it is necessary to create a table that will store the articles. In there, each article refers to a certain blog. In this case, the table with blogs will be the parent, and the table with articles is the child table. That is, one blog — many articles.
To create this type of relation, use the models.ForeignKey constructor. This constructor also accepts two obligatory arguments — the first is the model we are associating with, and the second is the on_delete option, which sets the constraints for deleting an external record (in our case it is deleting from blog). So, the article model will have the blog_id field that will store the blog ID to which the article belongs. We will define this field using a ForeignKey. The model file will look something like this:
class Blog(models.Model):
title = models.CharField(max_length=64)
class Article(models.Model):
title = models.CharField(max_length=64)
text = models.TextField()
blog_id = models.ForeignKey(Blog, on_delete=models.CASCADE)
article model in the code is lower than the blog model. If it were otherwise, the article model would refer to blog, which is below, so there would be an error when making migrations. To fix this, you need to write blog instead of just Blog in the ForeignKey constructor.This type of relationship is the most popular. How can you identify it? If you have two, ask yourself:
- How many entities of the first can relate to an entity of the second?
- How many entities of the second can relate to the entity of the first?
If the answer to one question is many, and the answer to the other question is one, then you are dealing with a one-to-many relation.
Many-to-many
Last, but not least, is the many-to-many relationship. Suppose the site has different tags that users can add to their articles. Then several tags can be defined for one article, and one tag can be defined for several articles.
Django also has a constructor models.ManyToManyField for this case. However, now you are not required to use on_delete; set the model to which the current model belongs. This makes sense because if we remove a tag, we don't want all articles with that tag to be removed. Similarly, when you delete an article, we don't want to lose all the tags. The on_delete option can be set if there is a need to erase records according to some rule. For an example, it might look like this:
class Article(models.Model):
title = models.CharField(max_length=64)
text = models.TextField()
blog_id = models.ForeignKey(Blog, on_delete=models.CASCADE)
class Tags(models.Model):
tag = models.CharField(max_length=32)
articles = models.ManyToManyField(Article)
Below is the code for all the models that have been reviewed. Note that the article model is higher than the blog model, so the ForeignKey in the constructor specifies Blog.
class Article(models.Model):
title = models.CharField(max_length=64)
text = models.TextField()
blog_id = models.ForeignKey('Blog', on_delete=models.CASCADE)
class Tags(models.Model):
tag = models.CharField(max_length=32)
articles = models.ManyToManyField(Article)
class Blog(models.Model):
title = models.CharField(max_length=64)
class User(models.Model):
name = models.CharField(max_length=64)
blog_id = models.OneToOneField(Blog, on_delete=models.CASCADE)Deleting
It is also necessary to tell you that the on_delete option can only cover certain values, depending on the rule you apply:
models.CASCADEdeletes a record from the primary model, deletes all the records from the secondary model;models.PROTECTprohibits removing a record from the primary model if it is used in the secondary model (generates an exception);models.SET_NULLsets the foreign key value toNULLfor the corresponding secondary model records when the primary model record is deleted;models.SET_DEFAULTsame asSET_NULL, instead ofNULL, it sets the default value, defined through aForeignKeymodels.SET()same, only sets a custom value.models.DO_NOTHINGdeletes a record in the primary model. It causes no additional actions in the secondary models.
Conclusion
You've learned all kinds of relationships in relational databases and how to describe them in Django. In short, there are:
- One-to-one relations for speed;
- One-to-many relations for strict parent-child dependency;
- Many-to-many relations for independent relations.
Choose one or another type of relationship depending on the task and models in your projects. Try to create your own models with relationships between them!