Django ORM – Exemples multi-tables
Les relations entre les tables peuvent être réparties en trois types suivants :
- un-à-un: Une personne correspond à un numéro d'identification, définissez le champ de données comme unique.
- un-à-plusieurs: Une famille compte plusieurs personnes, généralement implémenté au moyen d'une clé étrangère.
- plusieurs-à-plusieurs: Un étudiant a plusieurs cours, et un cours a plusieurs étudiants, généralement l'association est implémentée au moyen d'une troisième table.

Créer un modèle
Ensuite, examinons les scénarios multi-tables et multi-instances.
Exemple
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, "Femme"),
(1, "Homme"),
(2, "Confidentiel"),
)
gender = models.SmallIntegerField(choices=gender_choices)
tel = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
birthday = models.DateField()
Description:
- 1. Le type de données EmailField est au format e-mail, hérite de CharField au niveau inférieur et est encapsulé, ce qui équivaut à varchar dans MySQL.
- 2. Version Django1.1 : la suppression en cascade n'est pas requise : on_delete=models.CASCADE, Django2.2 l'exige.
- 3. En général, il n'est pas nécessaire de configurer des mises à jour en cascade.
- 4. Définissez la clé étrangère du côté plusieurs d'une relation un-à-plusieurs :models.ForeignKey("related class name", on_delete=models.CASCADE)。
- 5. OneToOneField = ForeignKey(..., unique=True) établit une relation un-à-un.
- 6. Si une classe de modèle possède une clé étrangère, lors de la création de données, vous devez d'abord créer les données pour la classe de modèle associée à la clé étrangère ; sinon, lors de la création de données pour la classe de modèle contenant la clé étrangère, les données de la classe de modèle associée à la clé étrangère ne seront pas trouvées.
structure de table
Table Book : Book: title, price, pub_date, publish (clé étrangère, plusieurs à un), authors (plusieurs à plusieurs)
Table de l'éditeur Publish: name, city, email
Table de l'auteur : Author: name, age, au_detail (un à un)
Table des détails de l'auteur AuthorDetail: gender, tel, addr, birthday
Ce qui suit est une description des relations entre les tables :
Insertion de données
Nous exécutons l'opération d'insertion SQL suivante dans 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 - Ajout de données
Un à plusieurs (clé étrangère ForeignKey)
Méthode 1 :Sous la forme de transmission d'un objet, le type de données de la valeur de retour est un objet, un objet Book.
Étapes:
- a. Récupérer l'objet éditeur
- b. Passer l'objet éditeur à l'attribut publish du livre
code du fichier app01/views.py :
# Récupérer l'objet éditeur
pub_obj = models.Publish.objects.filter(pk=1).first()
# Passer l'objet éditeur à l'attribut publish du livre
book = models.Book.objects.create(title="Example", price=200, pub_date="2010-10-10", publish=pub_obj)
print(book, type(book))
return HttpResponse(book)

Méthode 2 : Passer l'id de l'objet (puisque les données transmises sont généralement un id, passer l'id de l'objet est couramment utilisé).
Dans une relation un-à-plusieurs, dans la classe (la table 'many') qui définit la propriété de clé étrangère, le nom du champ affiché dans MySQL est :Nom de l'attribut de clé étrangère _id。
Le type de données de la valeur de retour est un objet, un objet livre.
Étapes:
- a. Obtenir l'id de l'objet éditeur
- b. Passer l'id de l'objet éditeur au champ éditeur associé du livre pulish_id
code du fichier app01/views.py :
# Récupérer l'objet éditeur
pub_obj = models.Publish.objects.filter(pk=1).first()
# Obtenir l'id de l'objet éditeur
pk = pub_obj.pk
# Passer l'id de l'objet éditeur au champ éditeur associé du livre publish_id
book = models.Book.objects.create(title=Technique de l'épée Chongling, price=100, pub_date="2004-04-04", publish_id=pk)
print(book, type(book))
return HttpResponse(book)

Plusieurs-à-plusieurs (ManyToManyField) : Ajouter des données dans la troisième table de relation
Méthode 1 :Passage sous forme d'objet ; aucune valeur de retour.
Étapes:
- a. Obtenir l'objet auteur
- b. Obtenir l'objet livre
- c. Utiliser la méthode add pour passer l'objet auteur à l'attribut authors de l'objet livre
code du fichier app01/views.py :
# Obtenir l'objet auteur
chong = models.Author.objects.filter(name="Linghu Chong").first()
ying = models.Author.objects.filter(name="Ren Yingying").first()
# Obtenir l'objet livre
book = models.Book.objects.filter(title="Example").first()
# Passer les objets auteur à l'attribut authors de l'objet livre en utilisant la méthode add.
book.authors.add(chong, ying)
return HttpResponse(book)

Méthode 2 :Passage de l'id de l'objet ; aucune valeur de retour.
Étapes:
- a. Obtenir l'id de l'objet auteur
- b. Obtenir l'objet livre
- c. Utiliser la méthode add pour passer l'id de l'objet auteur à l'attribut authors de l'objet livre
code du fichier app01/views.py :
# Obtenir l'objet auteur
chong = models.Author.objects.filter(name="Linghu Chong").first()
# Obtenir l'id de l'objet auteur
pk = chong.pk
# Obtenir l'objet livre
book = models.Book.objects.filter(title=Technique de l'épée Chongling).premier()
# Utiliser la méthode add pour passer l'id de l'objet auteur à l'attribut authors de l'objet livre
book.authors.add(pk)

Gestionnaire associé (appel d'objet)
Prérequis :
- Plusieurs-à-plusieurs (les deux directions ont des gestionnaires associés)
- Un-à-plusieurs (seul l'objet de la classe 'many' a un gestionnaire associé, c'est-à-dire uniquement dans la direction inverse)
Syntaxe :
正向:属性名 反向:小写类名加 _set
Remarque :La relation un-à-plusieurs ne peut se faire que dans le sens inverse.
Méthodes courantes :
add(): Utilisée pour les relations plusieurs-à-plusieurs, ajoute l'objet de modèle spécifié à l'ensemble d'objets liés (table de relation).
Remarque :Dans une relation un-à-plusieurs (c'est-à-dire clé étrangère), add() ne peut passer que des objets (type de données *QuerySet), pas des ids (*[table id]).
*[ ]Utilisation :
# Méthode 1 : Passer l'objetauthor_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*author_list) # Ajouter les objets auteur dont l'id est supérieur à 2 à l'ensemble d'auteurs de ce livre
# Méthode 2 : Passer l'id de l'objet
book_obj.authors.add(*[1,3]) # Ajouter les objets auteur avec id=1 et id=3 à l'ensemble d'auteurs de ce livre.
return HttpResponse("ok")

Inverse :nom de table en minuscules_set
book = models.Book.objects.filter(title=Technique de l'épée Chongling).premier()
ying.book_set.add(book)
return HttpResponse("ok")

create(): Crée un nouvel objet et l'ajoute à l'ensemble d'objets associés en même temps.
Renvoie l'objet nouvellement créé.
wo = models.Author.objects.filter(name="Ren Woxing").first()
book = wo.book_set.create(title=Technique d'absorption des étoiles, price=300, pub_date="1999-9-19", publish=pub)
print(book, type(book))
return HttpResponse("ok")

remove(): Supprime l'objet de modèle spécifié de l'ensemble d'objets associés.
Pour les objets ForeignKey, cette méthode n'existe que lorsque null=True (peut être vide), et n'a aucune valeur de retour.
Exemple
book_obj = models.Book.objects.get(id=11)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")

clear(): Supprime tous les objets de l'ensemble d'objets liés, supprime les relations, mais ne supprime pas les objets.
Pour les objets ForeignKey, cette méthode n'existe que lorsque null=True (peut être vide).
Aucune valeur de retour.
book = models.Book.objects.filter(title="Example").first()
book.authors.clear()
Requête ORM
Requêtes inter-tables basées sur les objets.
正向:属性名称 反向:小写类名_set
un-à-plusieurs
Interroger la ville où se situe l'éditeur du livre ayant la clé primaire 1 (en avant).
Exemple
res = book.publish.city
print(res, type(res))
return HttpResponse("ok")

Interroger les noms des livres publiés par la maison d'édition Mingjiao (inverse).
Inverse :object.lowercase_class_name_set (pub.book_set)Vous pouvez accéder à la table associée (la table book).
pub.book_set.all(): Récupérer tous les objets book de la table book, et dans un QuerySet, itérer pour récupérer chaque objet book.
Exemple
res = pub.book_set.all()
for i in res:
print(i.title)
return HttpResponse("ok")

un-à-un
Interroger le numéro de téléphone de Linghu Chong (direct)
Direct : object.attribute (author.au_detail) peut accéder à la table associée (table des détails de l'auteur)
Exemple
res = author.au_detail.tel
print(res, type(res))
return HttpResponse("ok")

Récupérez les noms de tous les auteurs dont l'adresse est à Black Wood Cliff (inverse).
Pour l'inverse d'un un-à-un, il suffit d'utiliserle nom de classe en minuscules de l'objet, pas besoin d'ajouter _set.
Inverse : object.lowercase_class_name (addr.author) permet d'accéder à la table associée (table des auteurs).
Exemple
res = addr.author.name
print(res, type(res))
return HttpResponse("ok")

plusieurs-à-plusieurs
Tous les noms et numéros de téléphone des auteurs dans Example Tutorial (direct).
Direct :object.attribute (book.authors)permet d'accéder à la table associée (la table des auteurs).
Il n'y a pas de numéro de téléphone d'auteur dans la table des auteurs, donc à nouveau viaobject.attribute (i.au_detail)Accédez à la table associée (table des détails d'auteur).
Exemple
res = book.authors.all()
for i in res:
print(i.name, i.au_detail.tel)
return HttpResponse("ok")

Interroger les noms de tous les livres publiés par Ren Woxing (inverse).
Exemple
res = author.book_set.all()
for i in res:
print(i.title)
return HttpResponse("ok")

Requêtes inter-tables basées sur les doubles underscores
Direct : nom d'attribut __ nom d'attribut sur la table liée Inverse : nom de classe en minuscules __ nom d'attribut sur la table liée
un-à-plusieurs
Interroger les noms et les prix de tous les livres publiés par Rookie Publishing House.
Exemple

Inverse : via le nom de classe en minusculesÉcrire nom de classe__nom d'attribut inter-table (book__title, book__price)Récupération de données inter-tables.
Exemple
return HttpResponse("ok")

plusieurs-à-plusieurs
Interroger les noms de tous les livres publiés par Ren Woxing.
Direct : obtenir des données inter-tables via nom d'attribut __ nom d'attribut sur la table liée (authors__name) :
res = models.Book.objects.filter(authors__name="任我行").values_list("title")
Inverse : obtenir des données entre tables via le nom de classe en minuscules __ nom d'attribut sur la table liée (book__title) :
res = models.Author.objects.filter(name="任我行").values_list("book__title")

un-à-un
Interroger le numéro de téléphone de Ren Woxing.
Direct : viaNom d'attribut __ nom d'attribut sur la table liée (au_detail__tel)Récupération de données entre tables.
res = models.Author.objects.filter(name="任我行").values_list("au_detail__tel")

Inverse : viaNom de classe en minuscules __ nom d'attribut sur la table liée (author__name)Récupération de données entre tables.
res = models.AuthorDetail.objects.filter(author__name="任我行").values_list("tel")

