[PYTHON] Comment utiliser la clause exist dans l'ensemble de requêtes Django

introduction

Comme le titre l'indique, comment écrire pour utiliser la "clause existe" dans l'ensemble de requêtes de Django? Notes d'enquête sur.

Spécification des conditions de jeu de requêtes dans Django

Lors de l'émission d'une requête avec Django, spécifiez une condition en tant que paramètre dans l'objet Queryset.

models.py


from django.db import models

class Author(models.Model):
    class Meta :
        db_table = 'AUTHOR'
    name     = models.CharField('Nom de l'auteur', max_length=100)
    birthday = models.DateField('Anniversaire')

class Book(models.Model):
    class Meta :
        db_table = 'BOOK'
    name   = models.CharField('Titre de livre', max_length=100)
    price  = models.IntegerField('prix')
    author = models.ForeignKey(Author, verbose_name='Auteur')

Par exemple, pour un modèle comme ↑

Book.objects.filter(name__contains='Django', price__lte=3000)

Dans le cas de l'ensemble de requêtes de ↑, cela signifie que les conditions selon lesquelles "le nom du livre contient la chaîne de caractères" Django "" et "le prix est inférieur ou égal à 3000" sont spécifiées, et la requête réellement émise ressemble à ↓. devenir.

SELECT ... FROM BOOK WHERE NAME LIKE '%Django%' AND PRICE <= 3000

Ces conditions spécifient les conditions directement pour les champs dans le modèle Book, mais s'il s'agit d'un champ ForeignKey, vous pouvez suivre la relation et écrire les conditions du champ auquel vous voulez vous rapporter.

Book.objects.filter(author__name__contains='xxx')

Dans le cas de ↑, la colonne avec FK est utilisée comme condition de jointure et la requête est comme indiqué dans ↓.

SELECT ... FROM BOOK INNER JOIN AUTHOR ON (BOOK.AUTHOR_ID = AUTHOR.ID)
WHERE AUTHOR.NAME LIKE '%xxx%'

Notez que la jointure de table est générée automatiquement du côté Django en traçant la relation à partir du champ FK, et vous ne pouvez pas effectuer la jointure de table par vous-même en utilisant le champ sans FK comme condition de jointure.

syntaxe de clause exist

La clause EXISTS dans SQL est utilisée dans la clause Where comme suit.

SELECT ... FROM AUTHOR
WHERE EXISTS(
  SELECT 1 FROM BOOK
  WHERE BOOK.AUTHOR_ID = AUTHOR.ID
  AND BOOK.PRICE >= 5000
)

Dans cet exemple, le SQL est "Rechercher les auteurs qui ont publié des livres avec des prix supérieurs à 5000". Si vous essayez d'exprimer cela dans l'ensemble de requêtes de Django, vous pouvez l'écrire comme ↓ en utilisant le champ correspondant.

Author.objects.filter(book__price__gte=5000)

Cependant, dans ce cas, «les auteurs qui ont publié plusieurs livres avec des prix de 5 000 ou plus» seront touchés par le nombre de livres. Pour éviter la duplication, utilisez la méthode distinct,

Author.objects.filter(book__price__gte=5000).distinct()

Cependant, cela gaspille les performances et n'est pas cool. Une telle condition "si ◯◯ existe" est intelligente si vous pouvez utiliser la clause exist ...

Solution

Donc, après avoir enquêté sur diverses choses, il y avait un moyen d'utiliser correctement la clause existait. (Mais pas très intelligent)

(1) Étendre la requête "juste un peu" en utilisant la méthode ʻextra`

La méthode supplémentaire a été mentionnée dans la documentation officielle de Django. Vous pouvez utiliser cette méthode pour étendre certaines de vos requêtes, telles que les clauses select, from et where.

Cette fois, nous allons ajouter une condition à la clause where, alors écrivez comme suit

Author.objects.extra(where=['exists(select 1 from BOOK where BOOK.author_id=AUTHOR.id and BOOK.price >= 5000)'])

Le SQL émis avec le contenu de ↑ est comme indiqué dans ↓.

SELECT "AUTHOR"."id", "AUTHOR"."name", "AUTHOR"."birthday" FROM "AUTHOR" 
WHERE (exists(select 1 from BOOK where BOOK.author_id=AUTHOR.id and BOOK.price >= 5000))

La chaîne de caractères spécifiée par extra est ajoutée telle quelle en tant que condition de la clause where. De plus, le paramètre where ajouté par extra est un type de liste, et si plusieurs conditions sont spécifiées, il sera automatiquement combiné par AND.

En passant, il est également possible d'utiliser la clause from et la clause where ensemble pour joindre des tables qui n'ont pas FK. Large gamme d'applications. Néanmoins, la valeur de retour est un objet Queryset, vous pouvez donc connecter la chaîne de méthodes telle quelle. C'est pratique.

Author.objects.extra(where=['exists(...réduction...)']).order_by('birthday')

↓ ça ressemble à ça

SELECT "AUTHOR"."id", "AUTHOR"."name", "AUTHOR"."birthday" FROM "AUTHOR" 
WHERE (exists(select 1 from BOOK where BOOK.author_id=AUTHOR.id and BOOK.price >= 5000))
ORDER BY "AUTHOR"."birthday" ASC

(2) Exécuter du SQL brut en utilisant la méthode raw

Comment utiliser la méthode brute

C'est un modèle de n'importe quoi. Tant que vous pouvez faire correspondre le contenu de la clause Select avec le champ de modèle à rechercher, vous pouvez écrire vous-même tout le SQL.

Si c'est la condition de l'exemple, écrivez comme ↓.

>>> Author.objects.raw('''select id,name,birthday from AUTHOR 
...                       where exists(
...                          select 1 from BOOK 
...                          where BOOK.author_id=AUTHOR.id 
...                          and BOOK.price >= 5000)''')
...
<RawQuerySet: 'select id,name,birthday from AUTHOR where exists(select 1 from BOOK where BOOK.author_id=AUTHOR.id and BOOK.price >= 5000)'>

Étant donné que le retour de la méthode brute est un objet RawQuerySet, la chaîne de méthodes de Queryset ne peut pas être connectée. Eh bien, j'ai écrit tout le SQL moi-même, donc je n'ai pas à l'écrire dans la chaîne de méthodes.

(3) Exécutez le SQL personnalisé directement à l'aide de l'objet cursor

Exécuter directement SQL personnalisé

C'est un modèle qui est vraiment n'importe quoi. Ce n'est pas quelque chose que la clause existe est utilisée à un tel niveau, mais elle est utilisée lorsque vous souhaitez émettre directement DDL ou DML. Ou s'agit-il d'émettre une requête qui n'a pas de classe de modèle correspondante (comme appeler VIEW ou FUNCTION)?

Si vous osez exécuter l'exemple de requête, vous pouvez écrire comme ↓

>>> from django.db import connection
>>> cursor = connection.cursor()
>>> cursor.execute('select id,name,birthday from AUTHOR where exists(...réduction...)')
>>> cursor.fetchall()
[(1,'xxx',datetime.date(yyyy,mm,dd)), (2,'xxx',datetime.date(yyyy,mm,dd)),,,]

Le résultat est une liste de tapples. Ce n'est pas un dict, donc soyez prudent lors de la récupération via le curseur.

Résumé

Si vous souhaitez écrire une requête qui ne peut pas être exprimée par le filtre de Django, etc., il existe les trois méthodes suivantes.

  1. méthode supplémentaire (étendre la clause "select, from, where")
  2. méthode brute (écrivez toutes les requêtes que vous souhaitez exécuter vous-même)
  3. objet curseur (exécution directe de DML, DDL, etc., ou émission d'une requête pour laquelle le modèle correspondant n'existe pas)

Pour le thème de cette fois, "Ecrire une clause existe", la méthode supplémentaire suffit. Si vous souhaitez créer une requête complexe, vous devrez peut-être utiliser la méthode brute. Je ne pense pas qu'il soit possible d'utiliser l'objet curseur pour créer une application normalement. Cela peut entrer en jeu lors de la création d'API ou du développement d'applications générant des flux de données complexes. (Je l'ai utilisé lorsque j'ai fait une commande pour générer des commentaires de table dans Django)

Pour le moment, il existe également un moyen d'exécuter du SQL complexe. Oui.

Recommended Posts

Comment utiliser la clause exist dans l'ensemble de requêtes Django
Comment utiliser le générateur
Comment faire fonctionner GeoIp2 de Django
Comment utiliser le décorateur
Comment utiliser le modèle appris dans Lobe en Python
Comment utiliser la fonction zip
Comment utiliser le module optparse
Comment utiliser les classes dans Theano
Comment utiliser SQLite en Python
Comment utiliser Mysql avec python
Comment utiliser ChemSpider en Python
Comment utiliser PubChem avec Python
Comment utiliser le module ConfigParser
[python] Comment vérifier si la clé existe dans le dictionnaire
Comment utiliser la méthode __call__ dans la classe Python
Comment définir l'attribut de classe html dans le formulaire forms.py de Django
Remarques sur l'utilisation de la guimauve dans la bibliothèque de schémas
[Introduction à Python] Comment utiliser la classe en Python?
Comment utiliser le pipeline Spark ML
Comment utiliser Google Test en langage C
[Linux] Comment utiliser la commande echo
Comment utiliser l'astérisque (*) en Python. C'est peut-être tout? ..
[Introduction à Python] Comment utiliser l'opérateur in dans l'instruction for?
Comment utiliser l'interpréteur d'Anaconda avec PyCharm
Comment utiliser __slots__ dans la classe Python
Comment utiliser le débogueur IPython (ipdb)
Comment utiliser les expressions régulières en Python
Comment utiliser Map dans ViewPager d'Android
Comment utiliser la fonction de rendu définie dans .mako (.html) directement dans mako
Comment utiliser is et == en Python
Comment afficher les images dans l'administration de Django
Comment utiliser MkDocs pour la première fois
Utilisez la clause LIKE avec golang x SQLite3
Comment utiliser la bibliothèque d'images Python dans la série python3
Comment utiliser la bibliothèque de dessins graphiques Bokeh
Résumé de l'utilisation de MNIST avec Python
Comment utiliser l'API Google Cloud Translation
Comment utiliser l'API du guide des programmes NHK
[Algorithm x Python] Comment utiliser la liste
Comment obtenir les fichiers dans le dossier [Python]
Comment utiliser tkinter avec python dans pyenv
Connectez-vous avec json en utilisant pygogo.
Comment utiliser xml.etree.ElementTree
Comment utiliser Python-shell
Remarques sur l'utilisation de tf.data
Comment utiliser virtualenv
Comment utiliser Seaboan
Comment utiliser la correspondance d'image
Comment utiliser le shogun
Comment utiliser Pandas 2
Comment utiliser Virtualenv
Comment utiliser numpy.vectorize
Comment utiliser partiel
Comment utiliser Bio.Phylo
Comment utiliser SymPy
Comment utiliser WikiExtractor.py
Comment utiliser IPython
Comment utiliser virtualenv
Comment utiliser Matplotlib
Comment utiliser iptables