Django ORM – Примеры с несколькими таблицами

Связи между таблицами можно разделить на следующие три типа:

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

Создание модели

Далее рассмотрим многотабличные сценарии с несколькими экземплярами.

Пример

class Book(models.Model):
    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:

def add_book(request):
    # Получить объект издателя
    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:

def add_book(request):
    # Получить объект издателя
    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:

def add_book(request):
    # Получить объект автора
    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:

def add_book(request):
    # Получить объект автора
    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: Передать объект
book_obj = models.Book.objects.get(id=10)
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

ying = models.Author.objects.filter(name="Ren Yingying").first()
book = models.Book.objects.filter(title=Техника меча Чунлина).first()
ying.book_set.add(book)
return HttpResponse("ok")

create(): Создаёт новый объект и одновременно добавляет его в связанный набор объектов.

Возвращает только что созданный объект.

pub = models.Publish.objects.filter(name="Mingjiao Press").first()
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 (может быть пустым) и не возвращает значения.

Пример

author_obj =models.Author.objects.get(id=1)
book_obj = models.Book.objects.get(id=11)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")

clear(): Удаляет все объекты из набора связанных объектов, удаляет связи, но не удаляет сами объекты.

Для объектов ForeignKey этот метод существует только при null=True (может быть пустым).

Нет возвращаемого значения.

# Очистить всех авторов, связанных с Dugu Nine Swords.
book = models.Book.objects.filter(title="Example").first()
book.authors.clear()

ORM-запрос

Межтабличные запросы на основе объектов.

正向:属性名称
反向:小写类名_set

один-ко-многим

Запросить город, в котором находится издательство книги с первичным ключом 1 (прямой запрос).

Пример

book = models.Book.objects.filter(pk=10).first()
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.

Пример

pub = models.Publish.objects.filter(name="Mingjiao Press").first()
res = pub.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")

один-к-одному

Запросить номер телефона Линху Чуна (прямой запрос)

Прямой запрос: object.attribute (author.au_detail) позволяет перейти к связанной таблице (таблице author detail).

Пример

author = models.Author.objects.filter(name="Linghu Chong").first()
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) позволяет перейти к связанной таблице (таблице авторов).

Пример

addr = models.AuthorDetail.objects.filter(addr="Blackwood Cliff").first()
res = addr.author.name
print(res, type(res))
return HttpResponse("ok")

многие-ко-многим

Имена и номера телефонов всех авторов в примере руководства (прямая связь).

Прямая связь:object.attribute (book.authors)можно перейти к связанной таблице (таблице авторов).

В таблице авторов нет телефона автора, поэтому снова черезobject.attribute (i.au_detail)переходим к связанной таблице (таблице сведений об авторе).

Пример

book = models.Book.objects.filter(title="Example").first()
res = book.authors.all()
for i in res:
    print(i.name, i.au_detail.tel)
return HttpResponse("ok")

Запрос названий всех книг автора Ren Woxing (обратный).

Пример

author = models.Author.objects.filter(name="Ren Woxing").first()
res = author.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")


Межтабличные запросы на основе двойных подчёркиваний

Прямой: имя атрибута __ имя атрибута в связанной таблице Обратный: имя класса в нижнем регистре __ имя атрибута в связанной таблице

один-ко-многим

Запрос названий и цен всех книг, изданных издательством Rookie Publishing House.

Пример

res = models.Book.objects.filter(publish__name="Rookie Press").values_list("title", "price")

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

Пример

res = models.Publish.objects.filter(name="Rookie Press").values_list("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")

Другие расширения