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