Zoeken…


Invoering

Een Queryset is in wezen een lijst met objecten afgeleid van een Model , door een compilatie van databasequery's.

Eenvoudige zoekopdrachten op een zelfstandig model

Hier is een eenvoudig model dat we zullen gebruiken om een paar testquery's uit te voeren:

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

Verkrijg een enkel modelobject met een id / pk van 4:
(Als er geen items met de id 4 zijn of er meerdere zijn, geeft dit een uitzondering.)

MyModel.objects.get(pk=4)

Alle modelobjecten:

MyModel.objects.all()

Modelobjecten waarvoor flag ingesteld op True :

MyModel.objects.filter(flag=True)

model_num met een model_num groter dan 25:

MyModel.objects.filter(model_num__gt=25)

Modelobjecten met de name "Goedkoop artikel" en flag ingesteld op False :

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

Modellen eenvoudig zoeken name voor specifieke string (hoofdlettergevoelig):

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

Modellen eenvoudig zoeken name voor specifieke string (Case-insensitive):

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

Geavanceerde zoekopdrachten met Q-objecten

Gezien het model:

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

We kunnen Q objecten gebruiken om AND of OR voorwaarden te maken in uw opzoekquery. Stel bijvoorbeeld dat we alle objecten met flag=True OF model_num>15 .

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

Het bovenstaande vertaalt zich in WHERE flag=True OR model_num > 15 dezelfde manier voor een AND die u zou doen.

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

Q objecten kunnen we ook GEEN zoekopdrachten uitvoeren met behulp van ~ . Laten we zeggen dat we alle objecten met flag=False EN model_num!=15 wilden krijgen, zouden we doen:

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

Bij gebruik Q objecten "normale" parameters filter() , wordt de Q objecten eerst moet komen. De volgende zoekopdracht zoekt naar modellen met ( flag ingesteld op True of een modelnummer groter dan 15 ) en een naam die begint met "H".

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

Opmerking: Q objecten kunnen worden gebruikt met elke opzoekfunctie waarvoor trefwoordargumenten nodig zijn, zoals filter , exclude , get . Zorg ervoor dat wanneer u met get , u slechts één object retourneert of dat de uitzondering MultipleObjectsReturned wordt verhoogd.

Verminder het aantal zoekopdrachten op ManyToManyField (probleem n + 1)

Probleem

# 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

Oplossing

Gebruik prefetch_related op ManyToManyField als u weet dat u later toegang moet krijgen tot een veld dat een ManyToManyField veld is.

# 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 kan ook worden gebruikt in opzoekvelden:

# 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

Zodra de queryset is uitgevoerd, kunnen de opgehaalde gegevens echter niet meer worden gewijzigd zonder opnieuw de database te raken. Het volgende zou bijvoorbeeld extra zoekopdrachten uitvoeren:

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

Het volgende kan worden geoptimaliseerd met een Prefetch object, geïntroduceerd in Django 1.7:

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

Verminder het aantal zoekopdrachten in het ForeignKey-veld (probleem n + 1)

Probleem

Django-querysets worden op een luie manier geëvalueerd. Bijvoorbeeld:

# 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

De bovenstaande code zorgt ervoor dat django de database doorzoekt voor de auteur van elk boek. Dit is inefficiënt en het is beter om slechts één query te hebben.

Oplossing

Gebruik select_related op ForeignKey als u weet dat u later toegang moet krijgen tot een ForeignKey veld.

# 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 kan ook worden gebruikt in opzoekvelden:

# 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

Download SQL voor Django queryset

De query attribuut op queryset geeft u SQL-equivalent syntaxis voor uw zoekopdracht.

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

Waarschuwing:

Deze uitvoer mag alleen worden gebruikt voor foutopsporing. De gegenereerde zoekopdracht is niet backend-specifiek. Als zodanig worden de parameters niet correct geciteerd, waardoor het kwetsbaar is voor SQL-injectie en de query mogelijk niet eens uitvoerbaar is in uw database-backend.

Ontvang het eerste en laatste record van QuerySet

Om het eerste object te krijgen:

MyModel.objects.first()

Laatste objecten ophalen:

MyModel.objects.last()

Filter First-object gebruiken:

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

Filter Laatste object gebruiken:

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

Geavanceerde zoekopdrachten met F-objecten

Een F () -object vertegenwoordigt de waarde van een modelveld of geannoteerde kolom. Het maakt het mogelijk om te verwijzen naar modelveldwaarden en databasebewerkingen uit te voeren zonder ze daadwerkelijk uit de database naar Python-geheugen te hoeven halen. - F () uitdrukkingen

Het is aangewezen om F() -objecten te gebruiken wanneer u in uw zoekopdracht naar de waarde van een ander veld moet verwijzen. Op zichzelf betekenen objecten F() niets en kunnen en mogen ze niet buiten een queryset worden aangeroepen. Ze worden gebruikt om naar de waarde van een veld op dezelfde queryset te verwijzen.

Bijvoorbeeld, gegeven een model ...

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

... een gebruiker kan objecten opvragen waarbij de waarde some_field twee keer zijn id door naar de waarde van het id veld te verwijzen terwijl hij met F() als volgt filtert:

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

F('id') verwijst eenvoudigweg naar de id waarde voor diezelfde instantie. Django gebruikt het om een overeenkomstige SQL-instructie te maken. In dit geval lijkt dit sterk op dit:

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

Zonder F() -uitdrukkingen zou dit worden bereikt met ofwel ruwe SQL of filtering in Python (wat de prestaties vermindert, vooral wanneer er veel objecten zijn).


Referenties:

Uit de definitie van de klasse F() :

Een object dat verwijzingen naar bestaande queryobjecten kan oplossen. - F bron

Opmerking: dit gepubliceerde voorbeeld is afkomstig van het bovenstaande antwoord met toestemming van TinyInstance.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow