[PYTHON] Verwendung der Exist-Klausel in Django Queryset

Einführung

Wie schreibe ich, wie der Titel schon sagt, um die "existierende Klausel" in einem Django-Abfragesatz zu verwenden? Umfrage Notizen über.

Abfragesatz-Bedingungsspezifikation in Django

Geben Sie beim Ausgeben einer Abfrage mit Django eine Bedingung als Parameter im Queryset-Objekt an.

models.py


from django.db import models

class Author(models.Model):
    class Meta :
        db_table = 'AUTHOR'
    name     = models.CharField('Autorenname', max_length=100)
    birthday = models.DateField('Geburtstag')

class Book(models.Model):
    class Meta :
        db_table = 'BOOK'
    name   = models.CharField('Buchtitel', max_length=100)
    price  = models.IntegerField('Preis')
    author = models.ForeignKey(Author, verbose_name='Autor')

Zum Beispiel für ein Modell wie ↑

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

Im Fall des Abfragesatzes von ↑ bedeutet dies, dass die Bedingungen "der Buchname enthält die Zeichenfolge 'Django'" und "der Preis beträgt 3000 oder weniger" angegeben sind und die tatsächlich ausgegebene Abfrage wie ↓ aussieht. werden.

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

Diese Bedingungen geben die Bedingungen direkt für die Felder im Buchmodell an. Wenn es sich jedoch um ein ForeignKey-Feld handelt, können Sie der Beziehung folgen und die Bedingungen für das Feld schreiben, auf das Sie sich beziehen möchten.

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

Im Fall von ↑ wird die Spalte mit FK als Verknüpfungsbedingung verwendet, und die Abfrage ist wie in ↓ gezeigt.

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

Beachten Sie, dass die Tabellenverknüpfung auf der Django-Seite automatisch generiert wird, indem die Beziehung aus dem FK-Feld verfolgt wird. Sie können die Tabellenverknüpfung nicht selbst durchführen, indem Sie das Feld ohne FK als Verknüpfungsbedingung verwenden.

existiert Klauselsyntax

Die EXISTS-Klausel in SQL wird in der Where-Klausel wie folgt verwendet.

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

In diesem Beispiel lautet SQL "Suche nach Autoren, die Bücher mit Preisen über 5000 veröffentlicht haben". Wenn Sie versuchen, dies in Djangos Abfragesatz auszudrücken, können Sie ihn über das zugehörige Feld als ↓ schreiben.

Author.objects.filter(book__price__gte=5000)

In diesem Fall werden jedoch "Autoren, die mehrere Bücher mit Preisen von 5000 oder mehr veröffentlicht haben", von der Anzahl der Bücher betroffen sein. Verwenden Sie die Methode "different", um Doppelarbeit zu vermeiden.

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

Das ist in Ordnung, aber Leistung ist verschwendet und vor allem nicht cool. Eine solche Bedingung "wenn ◯◯ existiert" ist klug, wenn Sie die existierende Klausel verwenden können ...

Lösung

Nachdem wir verschiedene Dinge untersucht hatten, gab es eine Möglichkeit, die existierende Klausel richtig zu verwenden. (Aber nicht sehr klug)

(1) Erweitern Sie die Abfrage "ein wenig" mit der Methode "extra"

Die zusätzliche Methode wurde in der offiziellen Django-Dokumentation erwähnt. Mit dieser Methode können Sie einige Ihrer Abfragen erweitern, z. B. select-, from- und where-Klauseln.

Dieses Mal fügen wir der where-Klausel eine Bedingung hinzu. Schreiben Sie also wie folgt

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

Die mit dem Inhalt von ↑ ausgegebene SQL ist wie in ↓ gezeigt.

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

Die durch extra angegebene Zeichenfolge wird hinzugefügt, da dies eine Bedingung für die where-Klausel ist. Darüber hinaus ist der durch extra hinzugefügte where-Parameter ein Listentyp. Wenn mehrere Bedingungen angegeben werden, wird er automatisch durch AND kombiniert.

Übrigens ist es auch möglich, die from-Klausel und die where-Klausel zusammen zu verwenden, um Tabellen ohne FK zu verbinden. Breites Anwendungsspektrum. Der Rückgabewert ist jedoch ein Queryset-Objekt, sodass Sie die Methodenkette unverändert verbinden können. Das ist praktisch.

Author.objects.extra(where=['exists(...Kürzung...)']).order_by('birthday')

↓ Es sieht so aus

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) Führen Sie einfaches SQL mit der Methode "raw" aus

Verwendung der Rohmethode

Dies ist ein Muster von allem. Solange Sie den Inhalt der Select-Klausel mit dem zu durchsuchenden Modellfeld abgleichen können, können Sie die gesamte SQL selbst schreiben.

Wenn dies die Bedingung des Beispiels ist, schreiben Sie als ↓.

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

Da die Rückgabe der raw-Methode ein RawQuerySet-Objekt ist, kann die Methodenkette von Queryset nicht verbunden werden. Nun, ich habe das gesamte SQL selbst geschrieben, sodass ich es nicht in die Methodenkette schreiben muss.

(3) Führen Sie benutzerdefiniertes SQL direkt mit dem Cursor-Objekt aus

Benutzerdefiniertes SQL direkt ausführen

Dies ist ein Muster, das wirklich alles ist. Es ist nicht etwas, dass die existierende Klausel auf einer solchen Ebene verwendet wird, aber sie wird verwendet, wenn Sie DDL oder DML direkt ausgeben möchten. Oder geht es darum, eine Abfrage auszugeben, die keine entsprechende Modellklasse hat (z. B. Aufruf von VIEW oder FUNCTION)?

Wenn Sie es wagen, die Beispielabfrage auszuführen, können Sie wie ↓ schreiben

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

Das Ergebnis ist eine Liste von Tapples. Es ist kein Diktat, seien Sie also vorsichtig, wenn Sie mit dem Cursor abrufen.

Zusammenfassung

Wenn Sie eine Abfrage schreiben möchten, die vom Django-Filter usw. nicht ausgedrückt werden kann, gibt es die folgenden drei Methoden.

  1. zusätzliche Methode (erweitern Sie "select, from, where-Klausel" a little ")
  2. Raw-Methode (schreiben Sie alle Abfragen, die Sie selbst ausführen möchten)
  3. Cursorobjekt (direkte Ausführung von DML, DDL usw. oder Ausgabe einer Abfrage, für die das entsprechende Modell nicht existiert)

Für das Thema dieser Zeit, "Write a exist Klausel", ist die zusätzliche Methode ausreichend. Wenn Sie eine komplexe Abfrage erstellen möchten, müssen Sie möglicherweise die Raw-Methode verwenden. Ich glaube nicht, dass es eine Chance gibt, das Cursorobjekt zum normalen Erstellen einer App zu verwenden. Dies kann beim Erstellen von APIs oder beim Entwickeln von Apps, die komplexe Datenflüsse generieren, ins Spiel kommen. (Ich habe es verwendet, als ich einen Befehl zum Generieren von Tabellenkommentaren in Django ausgeführt habe)

Vorerst gab es auch eine Möglichkeit, komplexes SQL auszuführen. Ja.

Recommended Posts

Verwendung der Exist-Klausel in Django Queryset
Verwendung des Generators
So bedienen Sie GeoIp2 von Django
Wie benutzt man den Dekorateur?
Verwendung des in Lobe in Python erlernten Modells
Verwendung der Zip-Funktion
Verwendung des optparse-Moduls
Verwendung von Klassen in Theano
Verwendung von SQLite in Python
Wie man MySQL mit Python benutzt
Verwendung von ChemSpider in Python
Verwendung von PubChem mit Python
Verwendung des ConfigParser-Moduls
[Python] So überprüfen Sie, ob der Schlüssel im Wörterbuch vorhanden ist
Verwendung der Methode __call__ in der Python-Klasse
So legen Sie das HTML-Klassenattribut in Djangos forms.py fest
Hinweise zur Verwendung von Marshmallow in der Schemabibliothek
[Einführung in Python] Wie verwende ich eine Klasse in Python?
Verwendung der Spark ML-Pipeline
Verwendung von Google Test in C-Sprache
[Linux] Verwendung des Befehls echo
Verwendung von Sternchen (*) in Python. Vielleicht ist das alles? ..
[Einführung in Python] Wie verwende ich den Operator in in der for-Anweisung?
Verwendung von Anacondas Interpreter mit PyCharm
Verwendung von __slots__ in der Python-Klasse
Verwendung des IPython-Debuggers (ipdb)
Verwendung regulärer Ausdrücke in Python
So verwenden Sie Map in ViewPager von Android
Verwendung der in .mako (.html) direkt in mako definierten Renderfunktion
Verwendung ist und == in Python
So zeigen Sie Bilder in Djangos Admin an
So verwenden Sie MkDocs zum ersten Mal
Verwenden Sie die LIKE-Klausel mit golang x SQLite3
Verwendung der Python-Bildbibliothek in der Python3-Serie
Verwendung der Grafikzeichnungsbibliothek Bokeh
Zusammenfassung der Verwendung von MNIST mit Python
Verwendung der Google Cloud Translation API
Verwendung der NHK-Programmführer-API
[Algorithmus x Python] Verwendung der Liste
So erhalten Sie die Dateien im Ordner [Python]
Wie man tkinter mit Python in Pyenv benutzt
Loggen Sie sich mit json mit pygogo ein.
Verwendung von xml.etree.ElementTree
Wie benutzt man Python-Shell
Hinweise zur Verwendung von tf.data
Verwendung von virtualenv
Wie benutzt man Seaboan?
Verwendung von Image-Match
Wie man Shogun benutzt
Verwendung von Pandas 2
Verwendung von Virtualenv
Verwendung von numpy.vectorize
Wie man teilweise verwendet
Wie man Bio.Phylo benutzt
Verwendung von SymPy
Verwendung von WikiExtractor.py
Verwendung von IPython
Verwendung von virtualenv
Wie benutzt man Matplotlib?
Verwendung von iptables