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

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, "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 :

def add_book(request):
    # 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 :

def add_book(request):
    # 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 :

def add_book(request):
    # 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 :

def add_book(request):
    # 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'objet
book_obj = models.Book.objects.get(id=10)
author_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

ying = models.Author.objects.filter(name="Ren Yingying").first()
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éé.

pub = models.Publish.objects.filter(name="Mingjiao Press").first()
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

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(): 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.

# Effacer tous les auteurs associés à Dugu Nine Swords.
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

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

pub = models.Publish.objects.filter(name="Mingjiao Press").first()
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

author = models.Author.objects.filter(name="Linghu Chong").first()
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

addr = models.AuthorDetail.objects.filter(addr="Blackwood Cliff").first()
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

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

Interroger les noms de tous les livres publiés par Ren Woxing (inverse).

Exemple

author = models.Author.objects.filter(name="Ren Woxing").first()
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

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

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

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

autres extensions