Курс по Django: https://stepik.org/a/183363
Архив проекта: 30_sitewomen.zip
Последний тип
связи, что мы рассмотрим, это связь One To One или один к
одному. Ее довольно часто используют для расширения существующих моделей.
Например, фреймворк Django изначально предоставляет нам таблицу user для хранения
информации о пользователях. И ее достаточно для большинства задач. Однако если
возникнет необходимость добавить в нее новые поля, то один из вариантов это
сделать – создать еще одну таблицу (модель) и присоединить ее к таблице user связью один к
одному.
Но пока мы не
будем трогать модель User. Речь о ней еще впереди. А для
демонстрации этого типа связи мы расширим модель Women, добавив еще
одну модель Husband (муж).
Очевидно, в нашей стране или Европе одна женщина может иметь только одного
мужа, а мужчина – одну жену. Поэтому связь One To One здесь будет в
самый раз.
Вначале определим
модель Husband следующим
образом:
class Husband(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField(null=True)
def __str__(self):
return self.name
И добавим в
модель Women связь один к
одному:
class Women(models.Model):
...
husband = models.OneToOneField('Husband', on_delete=models.SET_NULL, null=True, blank=True, related_name='wuman')
...
После этого нам
нужно создать файл миграций и применить их:
python manage.py makemigrations
python
manage.py migrate
Таблица husband создана, давайте
ее наполним каким-либо содержимым. Для этого перейдем в консоль фреймворка Django:
python manage.py
shell_plus
и выполним
следующие знакомые нам команды:
h1 = Husband.objects.create(name="Брэд Питт", age=59)
h2 = Husband.objects.create(name="Том Акерли", age=31)
h3 = Husband.objects.create(name="Дэниэл Модер")
h4 = Husband.objects.create(name="Кук Марони")
Теперь мы можем
этих мужчин распределить по женщинам. Возьмем первую запись по Анджелине Джоли:
w1 = Women.objects.get(pk=1)
У этого объекта
имеется атрибут husband:
Сейчас он
принимает значение NULL. Давайте присвоим ему объект h1:
Теперь Анджелина
Джоли снова замужем за Брэдом Питтом. Но в таблице БД этих изменений еще нет.
Для этого нужно выполнить метод save():
Видим, что
изменения применились и в поле husband появилось
значение 1 – это идентификатор записи из таблицы husband для Брэда Питта.
Причем, мы можем получать данные и через объект w1:
и через объект h1:
Атрибут wuman был сформирован
благодаря параметру related_name класса OneToOneField. Если бы мы его
не указали, то следовало бы обращаться по имени модели women (малыми
буквами).
По идее связь
можно было бы установить и с другой стороны (мужа). Предположим, что для второй
записи (Марго Робби):
w2 = Women.objects.get(pk=2)
мы бы хотели
указать мужа h2 (Том Акерли).
Сделать это можно и так:
Обратите
внимание, мы здесь сохраняем именно объект w2, так как в нем
хранится внешний ключ husband_id для связи с
таблицей husband. То есть, мы
должны сохранять ту запись, в которой произошли изменения. Запись h2 напрямую связь
не хранит, а потому и сохранять нечего.
Давайте теперь
попробуем Джулии Робертс назначить того же самого мужа h2 (Тома Акерли):
w3 = Women.objects.get(pk=3)
w3.husband = h2
Пока никаких
ошибок нет. Но при попытке сохранить эту запись:
получаем ошибку:
IntegrityError:
UNIQUE constraint failed: women_women.husband_id
Она, как раз,
связана с тем, что запись h2 уже ассоциирована с записью w2, поэтому
назначить ее h2 еще раз другой
записи нельзя. В этом смысл связи One To One (один к
одному).
Мужа h2 можно было бы
назначить женщине w3, предварительно удалив связь между h2 и w2. Это можно
сделать следующим образом:
w2.husband = None
w2.save()
Теперь
комбинация команд:
w3.husband = h2
w3.save()
сработают и у
Джулии Робертс появился новый муж. Соответственно подробную информацию о муже
можно посмотреть, обращаясь к объекту husband. Например:
w1 = Women.objects.get(pk=1)
w1.husband.name
w1.husband.age
Мало того, мы
можем прямо через объект husband менять
содержимое соответствующей записи:
w1.husband.age = 30
w1.husband.save()
Теперь Брэд Питт
имеет возраст 30 лет. Вот так достаточно просто создается связь один к одному и
происходит работа с ней.
Курс по Django: https://stepik.org/a/183363