I was watching a video on django-orm and the instructor stated that:
We should set
primary_key=True
to prevent a Model from having duplicate rows in a OneToOne relationship (Ex: Prevent a user from having multiple profiles).
I know this statement is wrong! AFAIK, an OneToOne
field is just a ForeignKey
with unique
parameter set to True
. But I got curious and looked-up the Django documentation, Sure enough they are using primary=True
in their example.
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
So, why would someone set primary_key=True
on an OneToOne
relation?
My guess is that it's just reasonable to have that field as a primary key and there is no technical background behind it.
This is a pattern to implement object-oriented inheritance in a relational database, for example as this article of Oracle discusses.
Indeed, it means that one can define a Place
, and for that Place
create a Restaurant
model as well. It has a OneToOneField(…)
to the "parent" model. The OneToOneField
prevents that one can define two (or more) Restaurant
s for the same Place
.
Usually it is defined as a primary key, since then it shares the same "primary code space", and it removes a column that is otherwise used to do the mapping and thus would make the database larger.
Django will implement this the same way. If we define this as:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
pass
then it will be implemented as:
mysql> describe place;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
| address | varchar(80) | NO | | NULL | |
+---------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> describe restaurant;
+--------------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------+------+-----+---------+-------+
| place_ptr_id | int | NO | PRI | NULL | |
+--------------+------+------+-----+---------+-------+
It thus will add a primary key named place_ptr_id
that refers to the place
table. This originates from a OneToOneField
that Django adds to the Restaurant
model named place_ptr
.
We should set
primary_key=True
to prevent a Model from having duplicate rows in a OneToOne relationship (Ex: Prevent a user from having multiple profiles)
This makes no sense, since a OneToOneField
is in essence a ForeignKey
with unique=True
[Django-doc]. So this is already enforced by the OneToOneField
, it is not necessary to make it a primary key.
Something that can not be done with the above modeling is preventing that an Place
is a Restaurant
and Library
at the same time.