9 minutes read

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)

In this example, the 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:

  1. How many entities of the first can relate to an entity of the second?
  2. 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.CASCADE deletes a record from the primary model, deletes all the records from the secondary model;
  • models.PROTECT prohibits removing a record from the primary model if it is used in the secondary model (generates an exception);
  • models.SET_NULL sets the foreign key value to NULL for the corresponding secondary model records when the primary model record is deleted;
  • models.SET_DEFAULT same as SET_NULL, instead of NULL, it sets the default value, defined through a ForeignKey
  • models.SET() same, only sets a custom value.
  • models.DO_NOTHING deletes 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!

15 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo