[Fixed]-When to use one-to-one relationships in Django models?

19👍

Imagine you have a company and make intranet tool listing all employees, their positions, offices, departments, salaries, etc. You would make in Django models.py a class Employee, maybe something like this:

class Employee(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    position = models.CharField(max_length=255)
    office = models.CharField(max_length=20)
    salary = models.IntegerField()
    department = models.ForeignKey(Department, related_name='employees')

But for some reasons you don’t want the salary to be accessible to all employees, maybe there are many people with redactor status in the admin area, and decide to outsource it to its own model and change the model Employee:

class Employee(models.Model):
    # above attributes
    salary = models.OneToOneField(Salary)

There are certainly other ways to hide this information, but one possibility is to divide the information in two tables even though it is just plain 1:1 relation.

Your company is a software company and you introduce pair programming. Every employee has a pair programming partner. It can be just one programming partner. So you adapt your model again:

class Employee(models.Model):
    # above attributes
    pair_programmer = models.OneToOneField('self')

This would be a recursive one-to-one relation.

One-to-one relations are not very common and hard to find in beginners’ tutorials, but if there are some specific requirements, you find yourself creating 1:1 relation for solving the problem.

Here is a real life example from my work. I’m bioinformatician and make software for microorganisms. They are classed in genera and species. Every genus may contain one or more species, but a species can belong to only one genus. That is a clear 1:n relation. But now, a genus has a type species, only one and just one. And the type species can belong to one genus. Here I put models.OneToOneField, besides the models.ForeignKey.

Don’t worry a lot about 1:1 relations in advance. When you come to some specific problem, then you’ll figure out if you need 1:1 relation.

👤cezar

4👍

The django documentation gives a great answer:

For example, if you were building a database of “places”, you would
build pretty standard stuff such as address, phone number, etc. in the
database. Then, if you wanted to build a database of restaurants on
top of the places, instead of repeating yourself and replicating those
fields in the Restaurant model, you could make Restaurant have a
OneToOneField to Place (because a restaurant “is a” place; in fact, to
handle this you’d typically use inherit Each car has exactly one driver and each driver only drives one car. Does it not make sense to separate car anance, which involves an
implicit one-to-one relation).

Django uses OneToOne to model inheritance (and might use it internally, I haven’t checked out the source though). I feel like if there is a tool django is providing and you can use that tool in a way that you can defend, why not use it? It seems like it makes sense, that if a car only has one driver, then enforce that in the db using the tools (OneToOneField) that django provides

0👍

OneToOneField() is used when extending User model to add extra fields as shown below. *You can see my answer explaining how to add extra fields with OneToOneField():

# "account/models.py"

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(
        User, 
        verbose_name=_("user"), 
        on_delete=models.CASCADE
    )
    age = models.PositiveSmallIntegerField(_("age"))
    gender = models.CharField(_("gender"), max_length=20)
    married = models.BooleanField(_("married"))

Leave a comment