Django ORM – Примеры с несколькими таблицами
Связи между таблицами можно разделить на следующие три типа:
- один-к-одному: Одному человеку соответствует один идентификационный номер, поле данных делается уникальным.
- один-ко-многим: У одной семьи несколько человек, обычно реализуется через внешний ключ.
- многие-ко-многим: У одного студента несколько курсов, а у одного курса много студентов; обычно связь реализуется через третью таблицу.

Создание модели
Далее рассмотрим многотабличные сценарии с несколькими экземплярами.
Пример
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
pub_date = models.DateField()
publish = models.ForeignKey("Publish", on_delete=models.CASCADE)
authors = models.ManyToManyField("Author")
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=64)
email = models.EmailField()
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.SmallIntegerField()
au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)
class AuthorDetail(models.Model):
gender_choices = (
(0, "Женский"),
(1, "Мужской"),
(2, "Конфиденциально"),
)
gender = models.SmallIntegerField(choices=gender_choices)
tel = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
birthday = models.DateField()
Описание:
- 1. Тип данных EmailField представляет собой формат электронной почты, наследует CharField на нижнем уровне и инкапсулирован, эквивалентен varchar в MySQL.
- 2. В Django1.1 не требуется каскадное удаление:on_delete=models.CASCADE, в Django2.2 требуется.
- 3. Обычно нет необходимости настраивать каскадные обновления.
- 4. Установите внешний ключ на стороне «многие» отношения «один ко многим»:models.ForeignKey("related class name", on_delete=models.CASCADE)。
- 5. OneToOneField = ForeignKey(..., unique=True) задаёт отношение «один к одному».
- 6. Если у класса модели есть внешний ключ, при создании данных сначала необходимо создать данные для класса модели, связанного с внешним ключом; иначе при создании данных для класса модели, содержащего внешний ключ, данные класса модели, связанного с внешним ключом, не будут найдены.
структура таблицы
Таблица Book: Book:title 、 price 、 pub_date 、 publish(Внешний ключ,многие-к-одному) 、 authors(многие-ко-многим)
Таблица издателя Publish:name 、 city 、 email
Таблица Author: Author: name, age, au_detail (один-к-одному)
Таблица сведений об авторе AuthorDetail:gender 、 tel 、 addr 、 birthday
Ниже приведено описание связей между таблицами:
Вставка данных
Мы выполняем следующую операцию вставки SQL в MySQL:
insert into app01_publish(name,city,email) values ("华山出版社", "华山", "[email protected]"), ("明教出版社", "黑木崖", "[email protected]")
# 先插入 authordetail 表中多数据
insert into app01_authordetail(gender,tel,addr,birthday) values (1,13432335433,"华山","1994-5-23"), (1,13943454554,"黑木崖","1961-8-13"), (0,13878934322,"黑木崖","1996-5-20")
# 再将数据插入 author,这样 author 才能找到 authordetail
insert into app01_author(name,age,au_detail_id) values ("令狐冲",25,1), ("任我行",58,2), ("任盈盈",23,3)

ORM — добавление данных
Один-ко-многим (внешний ключ ForeignKey)
Способ 1:В форме передачи объекта тип данных возвращаемого значения — объект, объект книги.
Шаги:
- a. Получить объект издателя
- b. Передать объект издателя в атрибут pulish книги
код файла app01/views.py:
# Получить объект издателя
pub_obj = models.Publish.objects.filter(pk=1).first()
# Передать объект издателя в атрибут publish книги
book = models.Book.objects.create(title="Example", price=200, pub_date="2010-10-10", publish=pub_obj)
print(book, type(book))
return HttpResponse(book)

Метод 2: Передача id объекта (поскольку передаваемые данные обычно являются id, передача id объекта часто используется).
В отношении «один ко многим», в классе (таблице «многие»), который задаёт свойство внешнего ключа, имя поля, отображаемое в MySQL:Имя атрибута внешнего ключа _id。
Тип данных возвращаемого значения — объект, объект книги.
Шаги:
- a. Получить id объекта издателя
- b. Передать id объекта издателя в связанное с книгой поле издателя pulish_id
код файла app01/views.py:
# Получить объект издателя
pub_obj = models.Publish.objects.filter(pk=1).first()
# Получить id объекта издателя
pk = pub_obj.pk
# Передать id объекта издателя в связанное с книгой поле издателя publish_id
book = models.Book.objects.create(title=Техника меча Чунлин, price=100, pub_date="2004-04-04", publish_id=pk)
print(book, type(book))
return HttpResponse(book)

Многие ко многим (ManyToManyField): Добавление данных в третью таблицу связей
Способ 1:Передача в виде объекта; возвращаемое значение отсутствует.
Шаги:
- a. Получить объект автора
- b. Получить объект книги
- c. Использовать метод add, чтобы передать объект автора в атрибут authors объекта книги
код файла app01/views.py:
# Получить объект автора
chong = models.Author.objects.filter(name="Linghu Chong").first()
ying = models.Author.objects.filter(name="Ren Yingying").first()
# Получить объект книги
book = models.Book.objects.filter(title="Example").first()
# Передать объекты авторов в атрибут authors объекта книги с помощью метода add.
book.authors.add(chong, ying)
return HttpResponse(book)

Способ 2:Передача формы id объекта; без возвращаемого значения.
Шаги:
- a. Получите id объекта автора
- b. Получить объект книги
- c. Используйте метод add, чтобы передать id объекта автора в атрибут authors объекта book
код файла app01/views.py:
# Получить объект автора
chong = models.Author.objects.filter(name="Linghu Chong").first()
# Получите id объекта автора
pk = chong.pk
# Получить объект книги
book = models.Book.objects.filter(title=Техника меча Чунлина).first()
# Используйте метод add, чтобы передать id объекта автора в атрибут authors объекта book
book.authors.add(pk)

Связанный менеджер (вызов через объект)
Предварительное условие:
- Многие-ко-многим (в обоих направлениях есть связанные менеджеры)
- Один-ко-многим (только объект класса 'many' имеет связанный менеджер, то есть только в обратном направлении)
Синтаксис:
正向:属性名 反向:小写类名加 _set
Примечание:Один-ко-многим можно выполнить только в обратном направлении.
Общие методы:
add(): Используется для связей многие-ко-многим, добавляет указанный объект модели в набор связанных объектов (таблицу связей).
Примечание:В связи один-ко-многим (то есть связи по внешнему ключу) add() может передавать только объекты (тип данных *QuerySet), а не идентификаторы (*[id table]).
*[ ]Использование:
# Способ 1: Передать объектauthor_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*author_list) # Добавить объекты авторов с id больше 2 в набор авторов этой книги
# Способ 2: Передать id объекта
book_obj.authors.add(*[1,3]) # Добавить объекты авторов с id=1 и id=3 в набор авторов этой книги.
return HttpResponse("ok")

Обратное:имя таблицы в нижнем регистре_set
book = models.Book.objects.filter(title=Техника меча Чунлина).first()
ying.book_set.add(book)
return HttpResponse("ok")

create(): Создаёт новый объект и одновременно добавляет его в связанный набор объектов.
Возвращает только что созданный объект.
wo = models.Author.objects.filter(name="Ren Woxing").first()
book = wo.book_set.create(title=Star Absorption Technique, price=300, pub_date="1999-9-19", publish=pub)
print(book, type(book))
return HttpResponse("ok")

remove(): Удаляет указанный объект модели из связанного набора объектов.
Для объектов ForeignKey этот метод существует только при null=True (может быть пустым) и не возвращает значения.
Пример
book_obj = models.Book.objects.get(id=11)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")

clear(): Удаляет все объекты из набора связанных объектов, удаляет связи, но не удаляет сами объекты.
Для объектов ForeignKey этот метод существует только при null=True (может быть пустым).
Нет возвращаемого значения.
book = models.Book.objects.filter(title="Example").first()
book.authors.clear()
ORM-запрос
Межтабличные запросы на основе объектов.
正向:属性名称 反向:小写类名_set
один-ко-многим
Запросить город, в котором находится издательство книги с первичным ключом 1 (прямой запрос).
Пример
res = book.publish.city
print(res, type(res))
return HttpResponse("ok")

Запросить названия книг, изданных издательством Mingjiao (обратный запрос).
Обратный запрос:object.lowercase_class_name_set (pub.book_set)Можно перейти к связанной таблице (таблице book).
pub.book_set.all(): Получить все объекты book из таблицы book и внутри QuerySet выполнить итерацию, чтобы извлечь каждый объект book.
Пример
res = pub.book_set.all()
for i in res:
print(i.title)
return HttpResponse("ok")

один-к-одному
Запросить номер телефона Линху Чуна (прямой запрос)
Прямой запрос: object.attribute (author.au_detail) позволяет перейти к связанной таблице (таблице author detail).
Пример
res = author.au_detail.tel
print(res, type(res))
return HttpResponse("ok")

Запросите имена всех авторов, чей адрес — Black Wood Cliff (обратный запрос).
Для обратной связи один-к-одному используйтеObject.lowercase class name— этого достаточно, не нужно добавлять _set.
Обратная связь: object.lowercase_class_name (addr.author) позволяет перейти к связанной таблице (таблице авторов).
Пример
res = addr.author.name
print(res, type(res))
return HttpResponse("ok")

многие-ко-многим
Имена и номера телефонов всех авторов в примере руководства (прямая связь).
Прямая связь:object.attribute (book.authors)можно перейти к связанной таблице (таблице авторов).
В таблице авторов нет телефона автора, поэтому снова черезobject.attribute (i.au_detail)переходим к связанной таблице (таблице сведений об авторе).
Пример
res = book.authors.all()
for i in res:
print(i.name, i.au_detail.tel)
return HttpResponse("ok")

Запрос названий всех книг автора Ren Woxing (обратный).
Пример
res = author.book_set.all()
for i in res:
print(i.title)
return HttpResponse("ok")

Межтабличные запросы на основе двойных подчёркиваний
Прямой: имя атрибута __ имя атрибута в связанной таблице Обратный: имя класса в нижнем регистре __ имя атрибута в связанной таблице
один-ко-многим
Запрос названий и цен всех книг, изданных издательством Rookie Publishing House.
Пример

Обратный: через имя класса в нижнем регистреУкажите имя класса__имя атрибута связанной таблицы (book__title, book__price)Извлечение данных из связанных таблиц.
Пример
return HttpResponse("ok")

многие-ко-многим
Запрос названий всех книг автора Ren Woxing.
Прямой: получение данных из связанных таблиц через имя атрибута __ имя атрибута в связанной таблице (authors__name):
res = models.Book.objects.filter(authors__name="任我行").values_list("title")
Обратный запрос: получение данных из связанных таблиц через имя класса в нижнем регистре __ имя атрибута в связанной таблице (book__title):
res = models.Author.objects.filter(name="任我行").values_list("book__title")

один-к-одному
Запросить номер телефона Жэнь Восина.
Прямой запрос: черезИмя атрибута __ имя атрибута в связанной таблице (au_detail__tel)Получение данных между таблицами.
res = models.Author.objects.filter(name="任我行").values_list("au_detail__tel")

Обратный запрос: черезИмя класса в нижнем регистре __ имя атрибута в связанной таблице (author__name)Получение данных между таблицами.
res = models.AuthorDetail.objects.filter(author__name="任我行").values_list("tel")

