Couche de modèle Django deuxième partie - création de relations multi-tables et opération multi-tables

avant-propos

Poursuivant le contenu de l'article précédent, cet article présente les opérations multi-tables. L'utilisation de django ORM peut créer une relation multi-tables et prend également en charge les opérations entre plusieurs tables, pour créer une relation de table et interroger deux parties pour illustrer le fonctionnement multi-tables de django ORM. Prenez plusieurs tableaux d'informations sur l'auteur, le livre, l'éditeur et l'auteur comme exemples d'illustration.

Créer une relation de table

Remarque : Dans le développement réel, il n'est pas recommandé d'utiliser des clés étrangères pour établir des relations de table, c'est-à-dire de ne pas utiliser la mise à jour en cascade et la suppression en cascade, mais d'utiliser des relations de clé étrangère logiques pour établir des relations de table.

Parmi les quatre tables ci-dessus, la relation entre les livres et la maison d'édition est une relation un-à-plusieurs, et la clé étrangère est établie du côté de la fréquence de requête la plus élevée. Les tables d'auteur et de détails sur l'auteur appartiennent à une relation un-à-un. La clé étrangère est établie du côté où la fréquence des requêtes est élevée. Les auteurs et les livres appartiennent à une relation plusieurs-à-plusieurs. Une troisième table est nécessaire pour stocker les Il est recommandé de construire la clé étrangère du côté de la fréquence de requête élevée. Assurez-vous d'exécuter la commande de migration de la base de données lors de la création d'une table ~

Lors de la création d'une relation de table, vous pouvez d'abord créer le modèle de table, puis ajouter le champ de clé étrangère. De plus, lorsque vous utilisez django ORM pour créer la relation de clé étrangère, le champ de clé étrangère associé sera automatiquement ajouté après le champ, et la relation entre la table et les _idvaleurs par défaut de la table Utilisez la clé primaire comme champ associé. De plus, lors de la création de relations de table, il n'est pas recommandé d'utiliser des clés étrangères réelles pour l'association, mais de spécifier les relations de table à l'aide de relations logiques.

class Book(models.Model):
    name = models.CharField(max_length=60, verbose_name='图书名')
    # 浮点数字段,max_digits表示数字共8位, decimal_place表示小数点占2位
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='图书价格')
    inventory_num = models.IntegerField(verbose_name='库存数量')
    sell_num = models.IntegerField(verbose_name='卖出数量')
    # 一对多关系外键字段创建使用 ForeigenKey(to='表名'),默认关联主键字段, db_constraint=Flase表示不建立实质的外键关系,只是逻辑上的关系
    publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='外键关联出版社')
    # 多对多关系,使用ManyToManyField(to='表名'),author是一个虚拟的字段,主要是用来告诉ORM,书籍和作者是多对多的关系,而且ORM会自动创建多对多关系的第三张
    author = models.ManyToManyField(to='Author', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='外键关联作者')


class Publish(models.Model):
    name = models.CharField(max_length=12, verbose_name='出版社名称')


class Author(models.Model):
    name = models.CharField(max_length=10, verbose_name='作者名称')
    # 一对一关系使用OneToOneField(to='表名')
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='外间关联作者详情')


class AuthorDetail(models.Model):
    age = models.IntegerField(verbose_name='年龄')
    phone = models.CharField(max_length=11, verbose_name='手机号')

De plus, il faut ajouter qu'il existe trois façons de créer une relation de table plusieurs à plusieurs, qui sont la création entièrement automatique, la création semi-automatique et la création entièrement manuelle :

# 全自动创建 - ManyToManyField,一般这种方式可以满足需求
'''
使用全自动创建多对多关系的优点就是无需手动创建第三张表,非常方便,django ORM直接提供操作第三张表关系的方法
缺点就是无法扩展第三张关系表
'''
class Book(models.Model):
	name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author')
    
class Author(models.Model):
    name = models.CharField(max_length=32)
    
    
    
# 纯手动创建 -  ForeignKey手动创建第三张表
'''
第三张表完全取决于手动的扩展,但是需要写的代码较多,而且无法使用ORM提供的简单方法
'''
class Book(models.Model):
    name = models.CharField(max_length=32)
    
class Author(models.Model):
	name = models.CharField(max_length=32)
	
class Book2Author(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')
    
# 半自动创建,通过ManyToManyField的参数控制第三张表
class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(
        to='Author', # 告诉ORM不需要自动帮忙创建第三张关系表
        through='Book2Author', # 告诉ORM第三张关系表对应的表的外键字段
        through_fields=('book','author')  # 通过哪两个字段关联表,当前在哪张表,就先写哪个表的关联字段
                                     )
class Author(models.Model):
    name = models.CharField(max_length=32) 
    
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

Opération de données multi-tables - ajout, suppression et modification

Tout d'abord, nous présenterons les opérations d'ajout, de suppression et de modification des opérations multi-tables, car les opérations de requête de données multi-tables sont un peu plus gênantes, nous allons donc faire un petit travail séparément.

Relation un-à-plusieurs et un-à-un - ajouter, supprimer, modifier

Les opérations d'ajout, de suppression et de modification un à un et un à plusieurs sont fondamentalement les mêmes.

augmenter les données

Il existe deux façons d'ajouter des données, l'une consiste à ajouter via des champs réels et l'autre consiste à ajouter via l'affectation d'objets de champ virtuel.

# 方式1:通过实际字段
book_obj = models.Book.objects.create(name='哈利波特', price=10.2, publish_id=1)

# 方式2,先获取出版社对象,再将书籍和出版社通过出版社对象进行关联
publis_obj = models.Publish.objects.filter(pk=1).first()
book_obj = models.Book.objects.create(name='哈利波特', price=10.2, publish=publis_obj)

Suprimmer les données

Il convient de noter que la suppression de données dans le développement réel du projet n'est pas vraiment supprimée, mais un champ booléen est utilisé pour indiquer si les données sont supprimées.

Si vous ne spécifiez pas lors de la suppression des données, on_delete=models.DO_NOTHINGla valeur par défaut est la mise à jour en cascade et la suppression en cascade.

models.Publish.objects.filter(pk=1).delete()

modifier les données

Il existe deux manières de modifier des données et d'ajouter des données.

# 方式1
models.Book.objects.filter(pk=1).update(publish_id=1)

# 方式2
pub_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=pub_obj)

Relation plusieurs-à-plusieurs - ajouter, supprimer, modifier

Tout d'abord, il doit être clair que les ajouts, les suppressions et les modifications plusieurs-à-plusieurs opèrent la troisième table relationnelle, mais la troisième table relationnelle est automatiquement créée par Django. La relation de clé étrangère plusieurs-à-plusieurs est construite dans la table du livre, et le champ de clé étrangère plusieurs-à-plusieurs est authorun champ, de sorte que book_obj.authorla troisième table peut être exploitée en la passant.

Pour la relation plusieurs-à-plusieurs de la troisième table créée automatiquement par Django, Django fournit des méthodes supplémentaires pour opérer sur les données.

Ajout d'une relation plusieurs à plusieurs - add ()

add()La méthode ajoute des données à la troisième table relationnelle. Les nombres et les objets peuvent être passés entre parenthèses, et plusieurs opérations simultanées sont prises en charge.

# 方式1,直接添加id值
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.add(1)		# 增加 1 1记录,即id为1的书绑定id为1的作者
book_obj.author.add(2, 3)   # 增加两条记录,1 2 和 1 3

# 方式2,通过对象添加关系
book_obj = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.author.add(author_obj1)				# 增加1条记录
book_obj.author.add(author_obj2, author_obj3)	# 增加2条

Supprimer une relation plusieurs à plusieurs - remove()

remove()La méthode est utilisée pour supprimer les données de la troisième table. De même, les nombres et les objets peuvent être passés entre parenthèses, et plusieurs données peuvent être utilisées en même temps.

# 方式1:直接删除值
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.remove(2)  # 删除book_id为1和author_id都为2的记录
book_obj.authors.remove(1, 3)  # 删除多条

# 方式2:通过对象删除
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj1, author_obj2)

Modifier la relation plusieurs à plusieurs - set()

set()La méthode est utilisée pour modifier la troisième table. Cette méthode est une opération de remplacement, qui remplace la relation précédente par la nouvelle relation. Le paramètre de cette méthode doit être une liste ou un tuple, indiquant des nombres ou des objets, et elle prend également en charge plusieurs données. opérations en même temps.

# 方式1:直接通过值进行修改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.set([2])  # 将book_id为1对应的author_id修改为2
book_obj.authors.set([1, 2])  # 将书的作者设置为id=1 和id=2的作者

# 方式2:通过对象进行修改
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj2, author_obj3])

Effacer la relation de liaison d'un objet dans la troisième table - clear ()

clear()La méthode effacera la relation de liaison d'un objet dans la troisième table de relations.

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.clear()

requête multitable

Avant d'effectuer des opérations de requête multi-tables, vous devez comprendre un concept, qu'est-ce qu'une requête directe et une requête inversée .

Requête directe : dans quelle table est la clé étrangère, l'interrogation de la table associée est une requête directe, telle que l'interrogation de la maison d'édition via des livres ;

Requête inversée : la table associée recherche la table dans laquelle se trouve le champ de clé étrangère est une requête inversée, telle que l'interrogation de livres via une maison d'édition.

sous-requête

Si la requête est plus compliquée, vous pouvez utiliser la méthode de sous-requête. La sous-requête signifie une requête pas à pas et le résultat obtenu par la première requête est utilisé comme condition pour la requête suivante.

recherche directe

Transférer la requête par champ, s'il y a plusieurs résultats requis 外键字段.all(), comment juger qu'il y a plusieurs résultats de requête ? Si .all()le résultat obtenu sans ajout est 应用名.模型名.None, par exemple, first.Author.Nonedans ce cas, cela signifie qu'il n'y a pas d'erreur dans l'instruction ORM, mais qu'il y a plusieurs résultats de requête, vous devez ajouter .all(). Lorsqu'il n'y a qu'un seul résultat de requête, un objet modèle est obtenu, et s'il y en a plusieurs, il s'agit d'un objet QuerySet.

# 一对多关系查询:查询书籍主键为1的书籍由哪个出版社出版
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.publish  # Publish object (1)
print(res.name)

# 多对多关系查询:查询数据主键为1的作者
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.author  # first.Author.None,说明结果有多个
res_many = book_obj.author.all()  # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
    
# 一对一关系查询:查询作者lili的年龄
author_obj = models.Author.objects.filter(name='lili').first()
res = author_obj.author_detail
print(res.phone)

recherche inversée

Si la requête inversée est un-à-un 表名小写, elle est vraie si elle est un-à-plusieurs ou plusieurs-à-plusieurs 表明小写——set. De plus, s'il y a plusieurs résultats, il doit être ajouté après avoir indiqué une minuscule _set.all(). La méthode de juger s'il y a plusieurs résultats revient au même que transmettre La requête est la même. Lorsqu'il n'y a qu'un seul résultat de requête, un objet modèle est obtenu, et s'il y en a plusieurs, il s'agit d'un objet QuerySet.

# 一对多关系查询,查询出版社是东方出版社出版的书
publish_obj = models.Publish.objects.filter(name='东方').first()
res = publish_obj.book_set.all()  # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>

# 多对多关系查询,查询作者是lili写过的书
author_obj = models.Author.objects.filter(name='lili').first()
res = author_obj.book_set  # first.Book.None,说明有多个结果
res_many = author_obj.book_set.all()
print(res_many)  # <QuerySet [<Book: Book object (1)>]>

# 一对一关系查询,查询手机号是119的作者
author_detail_obj = models.AuthorDetail.objects.filter(phone='119').first()
res = author_detail_obj.author
print(res.name)

Joindre la requête de table

La requête de table jointe est comme la requête de table jointe de l'instruction SQL dans MySQ, sauf que la requête de table jointe à double trait de soulignement (requête de table croisée) est utilisée dans l'ORM de django . Vous pouvez utiliser une ligne de code pour interroger les résultats de la requête de table jointe, et la requête de table jointe suit également la relation directe et inverse.

recherche directe

# 一对多关系查询:查询书籍主键为1的出版社名称和书名
# 首先获取书籍对象,书籍是查询publish的基表,因此获取书名直接values('names')即可,而出版社的名字是通过外键字段跳到出版社的表中农,需要通过__找到需要的字段值
res = models.Book.objects.filter(pk=1).values('name', 'publish__name')  # <QuerySet [{'name': '哈利波特', 'publish__name': '东方'}]>

# 多对多关系查询,查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('author__name')  # <QuerySet [{'author__name': 'lili'}, {'author__name': 'nana'}]>

# 一对一关系查询,查询lili的手机号和姓名
res = models.Author.objects.filter(name='lili').values('name', 'author_detail__phone').first()
print(res.get('name'), res.get('author_detail__phone'))

recherche inversée

# 一对多关系查询:查询数据主键为1的出版社名称和书的名字
res = models.Publish.objects.filter(book__id=1).values('name', 'book__name')  # <QuerySet [{'name': '东方', 'book__name': '哈利波特'}]>

# 多对多关系查询:查询书籍主键为1的作者姓名和书名
res = models.Author.objects.filter(book__id=1).values('name', 'book__name')  # <QuerySet [{'name': 'lili', 'book__name': '哈利波特'}, {'name': 'nana', 'book__name': '哈利波特'}]>

# 一对一关系查询:查询作者id是1作者的姓名和手机号
res = models.AuthorDetail.objects.filter(author__id=1).values('author__name', 'phone')  # <QuerySet [{'author__name': 'lili', 'phone': '119'}]>

# 综合大查询:查询书籍主键是1的作者的手机号,首先获取书籍对象,书籍关联了作者表,作者表又关联了作者详情表 
res = models.Book.objects.filter(pk=1).values('author__author_detail__phone')  # <QuerySet [{'author__author_detail__phone': '119'}, {'author__author_detail__phone': '120'}]>

requête d'agrégation

La requête d'agrégation est généralement utilisée avec le regroupement. La requête d'agrégation utilise certains outils statistiques, tels que la valeur maximale, la valeur minimale, la valeur moyenne, etc., ainsi que la méthode d'importation de la fonction d'agrégation. Si vous utilisez la fonction d'agrégation sans regroupement, vous devez utiliser dans from django.db.models import Max, Min, Sum, Count, Avgla aggregate()méthode utilisée à l'intérieur.

from django.db.models import Min,Max,Sum,Count,Avg
# 统计书的平均价格
res = models.Book.objects.aggregate(Avg('price'))
print(res)
# 可以将这些聚合函数同时使用
res = models.Book.objects.aggregate(Max('price'),Sum('price'),Count('pk'))
print(res)

Requête de groupe

Les fonctions d'agrégation sont généralement utilisées avec le regroupement. La méthode de regroupement des requêtes consiste à utiliser annotatela valeur par défaut comme models.分组依据base de regroupement, c'est-à-dire la clé primaire de la table à regrouper. Si elle annotate()apparaît avant la méthode , elle sera regroupée values()en fonction de la valeur spécifiée dans . valuesLa requête de groupe prend en charge __la requête entre tables.

from django.db.models import Sum, Max, Min, Avg, Count

# 1.统计每本书的作者个数
res = models.Book.objects.annotate(author_num=Count('author')).values('name', 'author_num')  # author_num是自己定义的字段用来存储统计出来的每本书对应的作者个数,暂时存为表中的字段

# 2.统计每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')

# 3.统计不止一个作者的图书
# 先按照图书分组,算出每本书的作者数量,再过滤出作者数量大于1的数据
res = models.Book.objects.annotate(author_num=Count('author')).filter(author_num__gt=1).values('name', 'author_num')

# 4.查询每个作者出版书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')

Requête F et Q

Requête F

La requête F peut obtenir la valeur de données d'un certain champ de la table, particulièrement adaptée aux opérations de comparaison entre deux champs de la table. Lors de l'utilisation de données de type caractère, F ne peut pas épisser directement les chaînes et a besoin d'aide Concat和Value.

from django.db.models import F

# 1.查询卖出数量大于库存数量的书籍
res = models.Book.objects.filter(sell_num__gt=F('inventory_num'))

# 将所有书籍的价格提升20元
res = models.Book.objects.update(price=F('price')+20)

ConcatLa requête F nécessite l'aide de deux méthodes pour les opérations sur les chaînesValue :

# 将所有书的名称后面加上爆款两个字
from django.db.models.functions import Concat
from django.db.models import F, Value

models.Book.objects.update(name=Concat(F('name'),Value('爆款')))

Requête Q

Lors de l'utilisation filter()du filtrage conditionnel, l'opération logique AND est utilisée and. Si vous souhaitez modifier plusieurs conditions de filtrage en orune relation OR not, vous devez utiliser la requête Q. |La relation exprimée dans la requête Q or, la relation ~exprimée not.

import django.db.models import Q

# 查询卖出数量大于100或者价格小于20的书籍
res = models.Book.objects.filter(~Q(sell_num__gt=100) | Q(price__lt=20))

En outre, il existe une autre utilisation plus avancée de la requête Q, c'est-à-dire que le côté gauche de la condition de requête peut également être converti en chaîne.

# 先产生一个Q的实例
q = Q()
# 修改q的连接条件的关系
q.connector = 'or'
q.children.append(('sell_num__gt',100))
q.children.append(('price__lt',200))
res = models.Book.objects.filter(q)
# filter的条件是Q实例化产生的对象,每个条件默认还是and关系,可以修改
print(res)

django démarrer la transaction

MySQL dispose d'un mécanisme de transaction pour assurer la sécurité des données. Puisque django peut se connecter à MySQL, django peut prendre en charge MySQL 事务机制. Le code suivant consiste à démarrer une transaction dans Django :

from django.db import transaction

try:
    with transaction.atomic():		 # 在with代码快内书写的所有orm操作都属于同一个事务
        ...
except Exception as e:
    print(r)
...

Je suppose que tu aimes

Origine blog.csdn.net/nhb687095/article/details/130475199
conseillé
Classement