Django ORM – Exemples multi-tables (Agrégation et requêtes groupées)

Requêtes d'agrégation (aggregate)

Les fonctions de requête d'agrégation effectuent des calculs sur un ensemble de valeurs et renvoient une seule valeur.

Avant d'utiliser des requêtes d'agrégation dans Django, vous devez d'abord importer Avg, Max, Min, Count, Sum (en majuscules) depuis django.db.models.

from django.db.models import Avg,Max,Min,Count,Sum  #   引入函数

La valeur de retour d'une requête d'agrégation est de type dictionnaire.

La fonction aggregate() est une clause terminale pour QuerySet, produisant une valeur de synthèse, équivalente à count().

Après avoir utilisé aggregate(), le type de données devient un dictionnaire, et vous ne pouvez plus utiliser certaines API du type de données QuerySet.

Le type de données date (DateField) peut utiliser Max et Min.

Dans le dictionnaire renvoyé : le nom de clé est par défaut (nom de l’attribut suivi de __ puis du nom de la fonction d’agrégation), et la valeur est la valeur agrégée calculée.

Si vous souhaitez personnaliser le nom de clé dans le dictionnaire renvoyé, vous pouvez définir un alias :

aggregate(别名 = 聚合函数名("属性名称"))

Calculez le prix moyen de tous les livres :

Exemple

from django.db.models import Avg,Max,Min,Count,Sum  # Importer la fonction
...
res = models.Book.objects.aggregate(Avg("price"))
print(res, type(res))
...

Calculez le nombre total de tous les livres, le prix le plus élevé et le prix le plus bas :

Exemple

res=models.Book.objects.aggregate(c=Count("id"),max=Max("price"),min=Min("price"))
print(res,type(res)


Requêtes groupées (annotate)

Les requêtes groupées utilisent généralement des fonctions d’agrégation, donc avant de les utiliser, vous devez importer Avg, Max, Min, Count, Sum (avec majuscule) depuis django.db.models.

from django.db.models import Avg,Max,Min,Count,Sum  #   引入函数

Valeur de retour :

  • Après regroupement, si vous utilisez values pour récupérer des valeurs, la valeur de retour est un type de données QuerySet contenant des dictionnaires.
  • Après regroupement, si vous utilisez values_list pour récupérer des valeurs, la valeur de retour est un type de données QuerySet contenant des tuples.

Dans MySQL, la clause limit est équivalente à un découpage du type de données QuerySet dans l'ORM.

Remarque :

Placez les fonctions d'agrégation à l'intérieur de annotate.

  • Placez values ou values_list avant annotate :values ou values_list déclare les champs selon lesquels regrouper, et annotate effectue le regroupement.

  • values ou values_list placés après annotate :annotate signifie regrouper directement par la pk de la table courante ; values ou values_list indique quels champs interroger, et vous devez donner un alias aux fonctions d'agrégation dans annotate, puis écrire ces alias dans values ou values_list.

Préparez les données et créez les modèles

models.py

class Emp(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    salary = models.DecimalField(max_digits=8, decimal_places=2)
    dep = models.CharField(max_length=32)
    province = models.CharField(max_length=32)

class Emps(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    salary =     models.DecimalField(max_digits=8, decimal_places=2)
    dep = models.ForeignKey("Dep", on_delete=models.CASCADE)
    province = models.CharField(max_length=32)
class Dep(models.Model):
    title = models.CharField(max_length=32)
 

Données :

Exécuter dans la ligne de commande MySQL :

INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES ('1', 'Linghu Chong', '24', '6000.00', 'Service des ventes', 'Henan'); INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES ('2', 'Ren Yingying', '18', '8000.00', 'Département Guan Gong', 'Guangdong'); INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES ('3', 'Ren Woxing', '56', '10000.00', 'Département des ventes', 'Guangdong'); INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES ('4', 'Yue Lingshan', '19', '6000.00', 'Département Guan Gong', 'Henan'); INSERT INTO `app01_emp` (`id`, `name`, `age`, `salary`, `dep`, `province`) VALUES ('5', 'Xiaolongnü', '20', '8000.00', 'Département Guan Gong', 'Hebei'); INSERT INTO `app01_dep` (`id`, `title`) VALUES ('1', 'Département des ventes'); INSERT INTO `app01_dep` (`id`, `title`) VALUES ('2', 'Département Guan Gong'); INSERT INTO `app01_emps` (`id`, `name`, `age`, `salary`, `province`, `dep_id`) VALUES ('2', 'Linghu Chong', '24', '8000.00', 'Henan', '1'); INSERT INTO `app01_emps` (`id`, `name`, `age`, `salary`, `province`, `dep_id`) VALUES ('3', 'Ren Yingying', '18', '9000.00', 'Guangdong', '2'); INSERT INTO `app01_emps` (`id`, `name`, `age`, `salary`, `province`, `dep_id`) VALUES ('4', 'Ren Woxing', '57', '10000.00', 'Guangdong', '1'); INSERT INTO `app01_emps` (`id`, `name`, `age`, `salary`, `province`, `dep_id`) VALUES ('5', 'Yue Lingshan', '19', '6000.00', 'Henan', '2'); INSERT INTO `app01_emps` (`id`, `name`, `age`, `salary`, `province`, `dep_id`) VALUES ('6', 'Xiaolongnü', '20', '8000.00', 'Hebei', '2');

Calculez le prix du livre le moins cher pour chaque éditeur :

Exemple

res = models.Publish.objects.values("name").annotate(in_price = Min("book__price"))
print(res)

La sortie suivante peut être vue dans la ligne de commande :

<QuerySet [{'name': 'Example出版社', 'in_price': Decimal('100.00')}, {'name': '明教出版社', 'in_price': Decimal('300.00')}]>

Comptez le nombre d'auteurs pour chaque livre :

Exemple

res = models.Book.objects.annotate(c = Count("authors__name")).values("title","c")
print(res)
Vous pouvez voir la sortie suivante dans la ligne de commande :
<QuerySet [{'title': 'Example', 'c': 1}, {'title': '吸星大法', 'c': 1}, {'title': '冲灵剑法', 'c': 1}]>

Comptez le nombre d'auteurs pour chaque livre dont le titre commence par "dish" :

Exemple

res = models.Book.objects.filter(title__startswith="dish").annotate(c = Count("authors__name")).values("title","c")
print(res)

Comptez les titres des livres ayant plus d'un auteur :

Exemple

res = models.Book.objects.annotate(c = Count("authors__name")).filter(c__gt=0).values("title","c")
print(res)
Vous pouvez voir la sortie suivante dans la ligne de commande :
<QuerySet [{'title': 'Example', 'c': 1}, {'title': '吸星大法', 'c': 1}, {'title': '冲灵剑法', 'c': 1}]>

Trier le QuerySet par ordre décroissant en fonction du nombre d'auteurs de chaque livre :

Exemple

res = models.Book.objects.annotate(c = Count("authors__name")).order_by("-c").values("title","c")
print(res)

Interroger le prix total des livres publiés par chaque auteur :

Exemple

res = models.Author.objects.annotate(all = Sum("book__price")).values("name","all")
print(res)

Requête F()

Une instance de F() peut référencer des champs dans une requête pour comparer les valeurs de deux champs différents dans la même instance de modèle.

Les filtres construits précédemment ne comparent que les valeurs de champs avec une constante. Si vous voulez comparer les valeurs de deux champs, vous devez utiliser F().

Avant de l'utiliser, vous devez d'abord importer F depuis django.db.models.

from django.db.models import F

Utilisation :

F("字段名称")

F obtient dynamiquement la valeur d'un champ d'un objet et peut effectuer des opérations.

Django prend en charge les opérations d'addition, de soustraction, de multiplication, de division et de modulo entre des objets F(), et entre des objets F() et des constantes.

L'opération de mise à jour peut également utiliser la fonction F().

Interroger les personnes dont le salaire est supérieur à leur âge :

Exemple

from django.db.models import F
...
book=models.Emp.objects.filter(salary__gt=F("age")).values("name","age")
...

Augmenter le prix de chaque livre de 100 yuan :

Exemple

res = models.Book.objects.update(price=F("price")+100)
print(res)

Requête Q()

Avant de l'utiliser, importez d'abord Q depuis django.db.models :
from django.db.models import Q

Utilisation :

Q(条件判断)

Par exemple :

Q(title__startswith="菜")

Les conditions multiples dans les filtres précédemment construits sont toutes liées par AND. Si vous devez exécuter des requêtes plus complexes (telles que des instructions OR), vous pouvez utiliser Q.

Les objets Q peuvent être combinés à l'aide des opérateurs &, |, ~ (AND, OR, NOT).

Priorité de la plus élevée à la plus faible : ~, &, |.

Vous pouvez mélanger des objets Q et des arguments nommés. Les objets Q et les arguments nommés sont combinés avec « and » (c.-à-d., traitez les virgules comme AND), mais les objets Q doivent être placés avant tous les arguments nommés.

Interrogez les noms et les prix des livres dont le prix est supérieur à 350 ou dont le nom commence par « dish ».

from django.db.models import Q

Exemple

...
res=models.Book.objects.filter(Q(price__gt=350)|Q(title__startswith="dish")).values("title","price")
print(res)
...

Interrogez les livres dont le nom se termine par « dish » ou qui ne sont pas d'octobre 2010 :

Exemple

res = models.Book.objects.filter(Q(title__endswith="dish") | ~Q(Q(pub_date__year=2010) & Q(pub_date__month=10)))
print(res)  

Interrogez les livres dont la date de publication est en 2004 ou 1999, et dont le titre contient « dish ».

Mélangez des objets Q et des arguments nommés ; les objets Q doivent précéder tous les mots-clés :

Exemple

res = models.Book.objects.filter(Q(pub_date__year=2004) | Q(pub_date__year=1999), title__contains="dish")
print(res)  

autres extensions