Зачем кому-то устанавливать primary_key=True для отношения "один к одному" (OneToOneField)?

Я смотрел видео по и инструктор заявил, что:

Мы должны установить primary_key=True для предотвращения дублирования строк в модели в отношениях "один к одному" (например: предотвращение наличия у пользователя нескольких профилей).

Я знаю, что это утверждение неверно! AFAIK, поле OneToOne - это просто ForeignKey с параметром unique, установленным в True. Но мне стало любопытно, и я заглянул в документацию Django. Уверен, что они используют primary=True в своем примере.

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,
    )

Итак, зачем кому-то устанавливать primary_key=True на отношение OneToOne? Я думаю, что это просто разумно иметь это поле в качестве первичного ключа, и за этим не стоит никакой технической подоплеки.

Это паттерн для реализации объектно-ориентированного наследования в реляционной базе данных, например, как это обсуждается в этой статье Oracle.

Действительно, это означает, что можно определить Place, и для этой Place создать модель Restaurant. Она имеет OneToOneField(…) к "родительской" модели. OneToOneField предотвращает возможность определения двух (или более) Restaurant для одной и той же Place.

Обычно он определяется как первичный ключ, поскольку тогда он разделяет то же самое "пространство первичного кода", и он удаляет столбец, который иначе используется для выполнения сопоставления и таким образом сделает базу данных больше.

Django реализует это таким же образом. Если мы определим это как:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    pass

тогда он будет реализован как:

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    |       |
+--------------+------+------+-----+---------+-------+

Таким образом, добавляется первичный ключ place_ptr_id, который ссылается на таблицу place. Это происходит от OneToOneField, который Django добавляет к Restaurant модели с именем place_ptr.

Мы должны установить primary_key=True для предотвращения дублирования строк в модели в отношениях "один к одному" (Например: предотвращение наличия у пользователя нескольких профилей)

.

Это не имеет смысла, поскольку OneToOneField по сути является ForeignKey с unique=True [Django-doc]. Таким образом, это уже обеспечивается OneToOneField, нет необходимости делать его первичным ключом.

То, что невозможно сделать с помощью вышеприведенного моделирования - это предотвращение того, что Place является Restaurant и Library одновременно.

Вернуться на верх