Suche…


Einführung

Ein Queryset ist im Queryset eine Liste von Objekten, die von einem Model durch Zusammenstellung von Datenbankabfragen abgeleitet werden.

Einfache Abfragen für ein Standalone-Modell

Hier ist ein einfaches Modell, mit dem wir einige Testabfragen ausführen:

class MyModel(models.Model):
    name = models.CharField(max_length=10)
    model_num = models.IntegerField()
    flag = models.NullBooleanField(default=False)

Holen Sie sich ein einzelnes Modellobjekt, bei dem die ID / PK 4 ist:
(Wenn keine Elemente mit der ID 4 vorhanden sind oder mehr als ein Element, wird eine Ausnahme ausgelöst.)

MyModel.objects.get(pk=4)

Alle Modellobjekte:

MyModel.objects.all()

Modellobjekte, deren flag auf " True :

MyModel.objects.filter(flag=True)

model_num mit einer model_num größer als 25:

MyModel.objects.filter(model_num__gt=25)

Modellieren Sie Objekte mit dem name "Billigartikel" und dem flag " False :

MyModel.objects.filter(name="Cheap Item", flag=False)

Modelle einfache Suche name für bestimmte Zeichenfolge (Groß- und Kleinschreibung):

MyModel.objects.filter(name__contains="ch")

Modelle einfache Suche name für bestimmte Zeichenfolge (Groß- und Kleinschreibung):

MyModel.objects.filter(name__icontains="ch")

Erweiterte Abfragen mit Q-Objekten

Angesichts des Modells:

class MyModel(models.Model):
    name = models.CharField(max_length=10)
    model_num = models.IntegerField()
    flag = models.NullBooleanField(default=False)

Wir können Q Objekte verwenden, um AND , OR Bedingungen in Ihrer Suchabfrage zu erstellen. model_num>15 wir beispielsweise an, wir wollen alle Objekte mit flag=True ODER model_num>15 .

from django.db.models import Q
MyModel.objects.filter(Q(flag=True) | Q(model_num__gt=15))

Das obige übersetzt WHERE flag=True OR model_num > 15 für ein AND, das Sie tun würden.

MyModel.objects.filter(Q(flag=True) & Q(model_num__gt=15))

Q Objekte erlauben uns auch, mit der Verwendung von ~ keine Abfragen zu machen. Nehmen wir an, wir wollten alle Objekte erhalten, die flag=False AND model_num!=15 , würden wir tun:

MyModel.objects.filter(Q(flag=True) & ~Q(model_num=15)) 

Wenn Sie Q-Objekte und "normale" Parameter in filter() , müssen die Q Objekte an erster Stelle stehen . Die folgende Abfrage sucht nach Modellen mit ( flag auf True oder einer Modellnummer größer als 15 ) und einem Namen, der mit "H" beginnt.

from django.db.models import Q
MyModel.objects.filter(Q(flag=True) | Q(model_num__gt=15), name__startswith="H")

Hinweis: Q Objekte können mit jeder Suchfunktion verwendet werden, die Schlüsselwortargumente wie filter , exclude und get übernimmt. Stellen Sie sicher, dass Sie bei Verwendung von get nur ein Objekt zurückgeben, da sonst die MultipleObjectsReturned Ausnahme MultipleObjectsReturned wird.

Reduzieren Sie die Anzahl der Abfragen bei ManyToManyField (n + 1 Problem).

Problem

# models.py:
class Library(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Book)

class Book(models.Model):
    title = models.CharField(max_length=100)
# views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.all()

    # Query the database on each iteration (len(author) times)
    # if there is 100 librairies, there will have 100 queries plus the initial query
    for library in libraries:
        books = library.books.all()
        books[0].title
        # ...

    # total : 101 queries

Lösung

Verwenden Sie prefetch_related für ManyToManyField wenn Sie wissen, dass Sie später auf ein Feld zugreifen müssen, das ein ManyToManyField Feld ist.

# views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related('books').all()
    
    # Does not query the database again, since `books` is pre-populated
    for library in libraries:
        books = library.books.all()
        books[0].title
        # ...

    # total : 2 queries - 1 for libraries, 1 for books

prefetch_related kann auch für Nachschlagefelder verwendet werden:

# models.py:
class User(models.Model):
    name = models.CharField(max_length=100)

class Library(models.Model):
    name = models.CharField(max_length=100)
    books = models.ManyToManyField(Book)

class Book(models.Model):
    title = models.CharField(max_length=100)
    readers = models.ManyToManyField(User)
 # views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related('books', 'books__readers').all()
    
    # Does not query the database again, since `books` and `readers` is pre-populated
    for library in libraries:
        for book in library.books.all():
            for user in book.readers.all():
                user.name
                # ...

    # total : 3 queries - 1 for libraries, 1 for books, 1 for readers

Sobald das Abfrageset ausgeführt wurde, können die abgerufenen Daten jedoch nicht geändert werden, ohne erneut auf die Datenbank zuzugreifen. Das Folgende würde beispielsweise zusätzliche Abfragen ausführen:

 # views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related('books').all()
    for library in libraries:
        for book in library.books.filter(title__contains="Django"):
            print(book.name)

Folgendes kann mit einem Prefetch Objekt optimiert werden, das in Django 1.7 eingeführt wurde:

from django.db.models import Prefetch
# views.py
def myview(request):
    # Query the database.
    libraries = Library.objects.prefetch_related(
        Prefetch('books', queryset=Book.objects.filter(title__contains="Django")
    ).all()
    for library in libraries:
        for book in library.books.all():
            print(book.name)  # Will print only books containing Django for each library

Anzahl der Abfragen im Feld ForeignKey (n + 1 Problem) reduzieren

Problem

Django-Querysets werden faul bewertet. Zum Beispiel:

# models.py:
class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author, related_name='books')
    title = models.CharField(max_length=100)
# views.py
def myview(request):
    # Query the database
    books = Book.objects.all()

    for book in books:
        # Query the database on each iteration to get author (len(books) times)
        # if there is 100 books, there will have 100 queries plus the initial query
        book.author
        # ...

    # total : 101 queries

Der obige Code bewirkt, dass django die Datenbank nach dem Autor jedes Buches abfragt. Dies ist ineffizient und es ist besser, nur eine einzige Abfrage zu haben.

Lösung

Verwenden Sie select_related für ForeignKey wenn Sie wissen, dass Sie später auf ein ForeignKey Feld zugreifen ForeignKey .

# views.py
def myview(request):
    # Query the database.
    books = Books.objects.select_related('author').all()
    
    for book in books:
        # Does not query the database again, since `author` is pre-populated
        book.author
        # ...

    # total : 1 query

select_related kann auch für select_related verwendet werden:

# models.py:
class AuthorProfile(models.Model):
    city = models.CharField(max_length=100)

class Author(models.Model):
    name = models.CharField(max_length=100)
    profile = models.OneToOneField(AuthorProfile)

class Book(models.Model):
    author = models.ForeignKey(Author, related_name='books')
    title = models.CharField(max_length=100)    
# views.py
def myview(request):
    books = Book.objects.select_related('author')\
                        .select_related('author__profile').all()
   
    for book in books:
        # Does not query database
        book.author.name
        # or
        book.author.profile.city
        # ...

    # total : 1 query

Holen Sie sich SQL für Django Queryset

Das query in Queryset enthält eine SQL-äquivalente Syntax für Ihre Abfrage.

>>> queryset = MyModel.objects.all()
>>> print(queryset.query)
SELECT "myapp_mymodel"."id", ... FROM "myapp_mymodel"

Warnung:

Diese Ausgabe sollte nur zum Debuggen verwendet werden. Die generierte Abfrage ist nicht backend-spezifisch. Daher werden die Parameter nicht korrekt in Anführungszeichen gesetzt, sodass sie für die SQL-Injection anfällig sind, und die Abfrage kann nicht einmal in Ihrem Datenbank-Backend ausgeführt werden.

Erhalte den ersten und letzten Datensatz von QuerySet

Erstes Objekt erhalten:

MyModel.objects.first()

Letzte Objekte bekommen:

MyModel.objects.last()

Filter First Objekt verwenden:

MyModel.objects.filter(name='simple').first()

Filter Last Objekt verwenden:

MyModel.objects.filter(name='simple').last()

Erweiterte Abfragen mit F-Objekten

Ein F () - Objekt repräsentiert den Wert eines Modellfelds oder einer kommentierten Spalte. Es ermöglicht, auf Modellfeldwerte zu verweisen und Datenbankoperationen mit diesen auszuführen, ohne sie tatsächlich aus der Datenbank in den Python-Speicher ziehen zu müssen. - F () Ausdrücke

Es ist sinnvoll, F() Objekte zu verwenden, wenn Sie in Ihrer Abfrage auf den Wert eines anderen Feldes verweisen müssen. F() Objekte bedeuten an sich nichts und können und dürfen nicht außerhalb eines Abfragesets aufgerufen werden. Sie werden verwendet, um auf den Wert eines Felds in demselben Abfragesatz zu verweisen.

Zum Beispiel ein Modell gegeben ...

SomeModel(models.Model):
    ...
    some_field = models.IntegerField()

Ein Benutzer kann Objekte abfragen, bei denen der Wert von some_field doppelt so some_field ist wie seine id indem er auf den Wert des id Felds verweist und dabei mit F() some_field :

SomeModel.objects.filter(some_field=F('id') * 2)

F('id') referenziert einfach den id Wert für dieselbe Instanz. Django verwendet es, um eine entsprechende SQL-Anweisung zu erstellen. In diesem Fall ähnelt dies etwas:

SELECT * FROM some_app_some_model 
WHERE some_field = ((id * 2))

Ohne F() Ausdrücke würde dies entweder mit Raw-SQL oder durch Filtern in Python erreicht werden (was die Leistung verringert, insbesondere wenn viele Objekte vorhanden sind).


Verweise:

Aus der Definition der Klasse F() :

Ein Objekt, das Verweise auf vorhandene Abfrageobjekte auflösen kann. - F-Quelle

Hinweis: Dieses Beispiel stammt aus der Antwort, die mit Zustimmung von TinyInstance oben aufgeführt wurde.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow