aPI-referens för QuerySet
¶
Detta dokument beskriver detaljerna i API:et QuerySet
. Det bygger på det material som presenteras i guiderna model och database query, så du vill förmodligen läsa och förstå dessa dokument innan du läser det här.
I den här referensen använder vi exempel på bloggmodeller som presenteras i guide för databasfrågor.
När QuerySet
utvärderas¶
Internt kan en QuerySet
konstrueras, filtreras, skivas och i allmänhet skickas runt utan att faktiskt träffa databasen. Ingen databasaktivitet sker faktiskt förrän du gör något för att utvärdera queryset.
Du kan utvärdera en QuerySet
på följande sätt:
**En
QuerySet
är itererbar och den utför sin databasfråga första gången du itererar över den. Till exempel: kommer detta att skriva ut rubriken på alla poster i databasen:for e in Entry.objects.all(): print(e.headline)
Observera: Använd inte detta om allt du vill göra är att avgöra om minst ett resultat finns. Det är mer effektivt att använda
exists()
.**En
QuerySet
kan också itereras över med hjälp avasync for
:async for e in Entry.objects.all(): results.append(e)
Både synkrona och asynkrona iteratorer av QuerySets delar samma underliggande cache.
**Som förklaras i Begränsning av QuerySet, kan en
QuerySet
skivas med hjälp av Pythons syntax för array-skivning. Att skiva en ovärderadQuerySet
returnerar vanligtvis en annan ovärderadQuerySet
, men Django kommer att utföra databasförfrågan om du använder parametern ”step” i slice-syntaxen och returnerar en lista. Att skära enQuerySet
som har utvärderats returnerar också en lista.Observera också att även om slicing av en ovärderad
QuerySet
returnerar en annan ovärderadQuerySet
, är det inte tillåtet att modifiera den ytterligare (t.ex. lägga till fler filter eller ändra ordningen), eftersom det inte översätts bra till SQL och det skulle inte heller ha en tydlig mening.Pickling/Caching. Se följande avsnitt för detaljer om vad som gäller vid ”picking” av QuerySets. Det viktiga i det här avsnittet är att resultaten läses från databasen.
repr(). En
QuerySet
utvärderas när du anroparrepr().
på den. Detta är för enkelhetens skull i Pythons interaktiva tolk, så att du omedelbart kan se dina resultat när du använder API:et interaktivt.len(). En
QuerySet
utvärderas när du anroparlen()
på den. Detta returnerar, som du kanske förväntar dig, längden på resultatlistan.Obs: Om du bara behöver bestämma antalet poster i uppsättningen (och inte behöver de faktiska objekten) är det mycket effektivare att hantera en räkning på databasnivå med SQL: s ``SELECT COUNT(*) ``. Django tillhandahåller en
count()
-metod av just denna anledning.list(). Tvinga fram utvärdering av en
QuerySet
genom att anropalist().
på den. Till exempel:entry_list = list(Entry.objects.all())
bool(). Om en
QuerySet
testas i ett booleskt sammanhang, t.ex. medbool().
,or
,and
eller enif
-sats, kommer frågan att utföras. Om det finns minst ett resultat ärQuerySet
True
, annarsFalse
. Till exempel:if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")
Observera: Om du bara vill avgöra om minst ett resultat finns (och inte behöver de faktiska objekten) är det effektivare att använda
exists()
.
Inläggning av ”QuuerySet¶
Om du pickle
en QuerySet
, kommer detta att tvinga alla resultat att laddas in i minnet före pickling. Pickling används vanligtvis som en föregångare till cachelagring och när det cachade querysetet laddas om vill du att resultaten redan ska finnas och vara redo att användas (att läsa från databasen kan ta lite tid, vilket motverkar syftet med cachelagring). Detta innebär att när du plockar upp en QuerySet
innehåller den resultaten vid den tidpunkt då den plockades upp, snarare än de resultat som för närvarande finns i databasen.
Om du bara vill plocka ut den information som behövs för att återskapa QuerySet
från databasen vid ett senare tillfälle, plockar du ut query
-attributet för QuerySet
. Du kan sedan återskapa den ursprungliga QuerySet
(utan några resultat laddade) med hjälp av någon kod som denna:
>>> import pickle
>>> query = pickle.loads(s) # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query # Restore the original 'query'.
Attributet query
är ett opakt objekt. Det representerar det interna i query-konstruktionen och är inte en del av det publika API:et. Det är dock säkert (och stöds fullt ut) att plocka ut och plocka in attributets innehåll enligt beskrivningen här.
Begränsningar för QuerySet.values_list()
Om du återskapar QuerySet.values_list()
med det inlagda query
-attributet kommer det att konverteras till QuerySet.values()
:
>>> import pickle
>>> qs = Blog.objects.values_list("id", "name")
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
aPI för ”frågeuppsättning¶
Här är den formella deklarationen av en QuerySet
:
- class QuerySet(model=None, query=None, using=None, hints=None)[source]¶
Vanligtvis när du interagerar med en
QuerySet
använder du den genom att kedja filter. För att få detta att fungera returnerar de flestaQuerySet
-metoder nya querysets. Dessa metoder behandlas i detalj senare i detta avsnitt.Klassen
QuerySet
har följande publika attribut som du kan använda för introspektion:- ordered[source]¶
True
omQuerySet
är ordnad - dvs. har enorder_by()
klausul eller en standardordning på modellen.False
i annat fall.
Observera
Parametern
query
tillQuerySet
finns för att specialiserade frågeunderklasser ska kunna rekonstruera interna frågestatus. Värdet på parametern är en opak representation av detta frågetillstånd och är inte en del av ett offentligt API.
Metoder som returnerar nya QuerySet
¶
Django tillhandahåller en rad förfiningsmetoder för QuerySet
som ändrar antingen de typer av resultat som returneras av QuerySet
eller hur dess SQL-fråga exekveras.
Observera
Dessa metoder kör inte databasfrågor och är därför säkra att köra i asynkron kod och har inga separata asynkrona versioner.
filter()`
¶
- filter(*args, **kwargs)¶
Returnerar en ny QuerySet
som innehåller objekt som matchar de angivna uppslagningsparametrarna.
Uppslagsparametrarna (**kwargs
) ska vara i det format som beskrivs i Fältuppslag nedan. Flera parametrar sammanfogas via AND
i den underliggande SQL-satsen.
Om du behöver köra mer komplexa frågor (t.ex. frågor med OR
-satser) kan du använda Q objects
(*args
).
exkludera()
¶
- exclude(*args, **kwargs)¶
Returnerar en ny QuerySet
som innehåller objekt som inte matchar de angivna uppslagningsparametrarna.
Uppslagsparametrarna (**kwargs
) bör vara i det format som beskrivs i Field lookups nedan. Flera parametrar sammanfogas via AND
i den underliggande SQL-satsen, och det hela omsluts av en NOT()
.
Detta exempel utesluter alla poster vars pub_date
är senare än 2005-1-3 OCH vars headline
är ”Hello”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline="Hello")
I SQL-termer utvärderas detta till:
SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
Detta exempel utesluter alla poster vars pub_date
är senare än 2005-1-3 ELLER vars rubrik är ”Hello”:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline="Hello")
I SQL-termer utvärderas detta till:
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'
Observera att det andra exemplet är mer restriktivt.
Om du behöver köra mer komplexa frågor (t.ex. frågor med OR
-satser) kan du använda Q objects
(*args
).
annotera()`
¶
- annotate(*args, **kwargs)¶
Antecknar varje objekt i QuerySet
med den angivna listan över query expressions eller Q
-objekt. Varje objekt kan annoteras med:
ett enkelt värde, via
Value()
;en referens till ett fält i modellen (eller eventuella relaterade modeller), via
F()
;en boolean, via
Q()
; ellerett resultat från ett aggregerat uttryck (medelvärden, summor etc.) beräknat över de objekt som är relaterade till objekten i
QuerySet
.
Varje argument till annotate()
är en annotering som kommer att läggas till varje objekt i den QuerySet
som returneras.
De aggregeringsfunktioner som tillhandahålls av Django beskrivs i Aggregeringsfunktioner nedan.
Annoteringar som anges med nyckelordsargument kommer att använda nyckelordet som alias för annoteringen. För anonyma argument genereras ett alias baserat på namnet på aggregeringsfunktionen och det modellfält som aggregeras. Endast aggregatuttryck som refererar till ett enda fält kan vara anonyma argument. Allt annat måste vara ett nyckelordsargument.
Om du t.ex. manipulerar en lista med bloggar kanske du vill avgöra hur många inlägg som har gjorts i varje blogg:
>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count("entry"))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42
Modellen Blog
definierar inte ett entry__count
-attribut i sig, men genom att använda ett nyckelordsargument för att ange den aggregerade funktionen kan du styra namnet på annotationen:
>>> q = Blog.objects.annotate(number_of_entries=Count("entry"))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
För en djupgående diskussion om aggregering, se the topic guide on Aggregation.
alias()`
¶
- alias(*args, **kwargs)¶
Samma som annotate()
, men istället för att annotera objekt i QuerySet
, sparas uttrycket för senare återanvändning med andra QuerySet
-metoder. Detta är användbart när resultatet av själva uttrycket inte behövs, men det används för filtrering, ordning eller som en del av ett komplext uttryck. Genom att inte välja det oanvända värdet tas överflödigt arbete bort från databasen, vilket bör leda till bättre prestanda.
Om du t.ex. vill hitta bloggar med fler än 5 inlägg, men inte är intresserad av det exakta antalet inlägg, kan du göra så här:
>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count("entry")).filter(entries__gt=5)
alias()
kan användas tillsammans med annotate()
, exclude()
, filter()
, order_by()
och update()
. Om du vill använda ett aliasuttryck med andra metoder (t.ex. aggregate()
) måste du omvandla det till en annotation:
Blog.objects.alias(entries=Count("entry")).annotate(
entries=F("entries"),
).aggregate(Sum("entries"))
filter()
och order_by()
kan ta uttryck direkt, men konstruktion och användning av uttryck sker ofta inte på samma ställe (till exempel skapar metoden QuerySet
uttryck för senare användning i vyer). alias()
gör det möjligt att bygga komplexa uttryck stegvis, eventuellt över flera metoder och moduler, hänvisa till uttrycksdelarna med deras alias och endast använda annotate()
för slutresultatet.
order_by()
¶
- order_by(*fields)¶
Som standard ordnas de resultat som returneras av en QuerySet
enligt den ordningstupel som anges av alternativet ordering
i modellens Meta
. Du kan åsidosätta detta per QuerySet
genom att använda metoden order_by
.
Exempel:
Entry.objects.filter(pub_date__year=2005).order_by("-pub_date", "headline")
Resultatet ovan kommer att sorteras efter pub_date
i fallande ordning, sedan efter headline
i stigande ordning. Det negativa tecknet framför "-pub_date"
anger nedstigande ordning. Stigande ordning är underförstådd. För slumpmässig ordning, använd "?"
, så här:
Entry.objects.order_by("?")
Obs: order_by('?')
-frågor kan vara dyra och långsamma, beroende på vilken databasbackend du använder.
Om du vill beställa efter ett fält i en annan modell använder du samma syntax som när du ställer frågor över modellrelationer. Det vill säga fältets namn, följt av ett dubbelt understreck (__
), följt av fältets namn i den nya modellen, och så vidare för så många modeller som du vill koppla samman. Till exempel:
Entry.objects.order_by("blog__name", "headline")
Om du försöker beställa efter ett fält som är en relation till en annan modell, kommer Django att använda standardbeställningen på den relaterade modellen, eller beställa efter den relaterade modellens primärnyckel om det inte finns någon Meta.ordering
angiven. Till exempel:, eftersom modellen Blog
inte har någon standardordning angiven:
Entry.objects.order_by("blog")
…är identisk med:
Entry.objects.order_by("blog__id")
Om Blog
hade ordering = ['name']
, så skulle den första frågeuppsättningen vara identisk med:
Entry.objects.order_by("blog__name")
Du kan också sortera efter query expressions genom att anropa asc()
eller desc()
på uttrycket:
Entry.objects.order_by(Coalesce("summary", "headline").desc())
asc()
och desc()
har argument (nulls_first
och nulls_last
) som styr hur nollvärden sorteras.
Var försiktig när du beställer efter fält i relaterade modeller om du också använder distinct()
. Se anmärkningen i distinct()
för en förklaring av hur beställning av relaterade modeller kan ändra de förväntade resultaten.
Observera
Det är tillåtet att ange ett flervärdesfält för att ordna resultaten efter (t.ex. ett fält ManyToManyField
eller den omvända relationen för ett fält ForeignKey
).
Tänk på detta fall:
class Event(Model):
parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
related_name="children",
)
date = models.DateField()
Event.objects.order_by("children__date")
Här kan det potentiellt finnas flera beställningsdata för varje Event
; varje Event
med flera children
kommer att returneras flera gånger till den nya QuerySet
som order_by()
skapar. Med andra ord, att använda order_by()
på QuerySet
kan returnera fler objekt än du arbetade med till att börja med - vilket förmodligen varken är förväntat eller användbart.
Var därför försiktig när du använder flervärdesfält för att ordna resultaten. **Om du kan vara säker på att det bara kommer att finnas en beställningsuppgift för var och en av de artiklar du beställer, bör det här tillvägagångssättet inte innebära några problem. Om inte, se till att resultaten är vad du förväntar dig.
Det finns inget sätt att ange om beställningen ska vara skiftlägeskänslig. Med avseende på skiftlägeskänslighet kommer Django att ordna resultaten på det sätt som din databas backend normalt ordnar dem.
Du kan beställa efter ett fält som konverterats till små bokstäver med Lower
som kommer att uppnå skiftlägeskonsekvent beställning:
Entry.objects.order_by(Lower("headline").desc())
Om du inte vill att någon ordning ska tillämpas på en fråga, inte ens standardordningen, anropar du order_by()
utan parametrar.
Du kan se om en fråga är ordnad eller inte genom att kontrollera attributet QuerySet.ordered
, som blir True
om QuerySet
har ordnats på något sätt.
Varje anrop av order_by()
rensar bort alla tidigare ordningar. Till exempel: kommer den här frågan att sorteras efter pub_date
och inte headline
:
Entry.objects.order_by("headline").order_by("pub_date")
Varning
Beställning är inte en gratis operation. Varje fält som du lägger till i beställningen medför en kostnad för din databas. Varje främmande nyckel som du lägger till kommer implicit att inkludera alla sina standardbeställningar också.
Om en fråga inte har någon angiven ordning returneras resultaten från databasen i en ospecificerad ordning. En viss ordning garanteras endast när ordningen görs med hjälp av en uppsättning fält som unikt identifierar varje objekt i resultatet. Om t.ex. fältet name
inte är unikt garanterar inte beställningen efter det att objekt med samma namn alltid visas i samma ordning.
omvänd()`
¶
- reverse()¶
Använd metoden reverse()
för att vända den ordning i vilken elementen i en queryset returneras. Om du anropar reverse()
en andra gång återställs ordningen till den normala riktningen.
Om du vill hämta de ”sista” fem objekten i en frågeuppsättning kan du göra så här:
my_queryset.reverse()[:5]
Observera att detta inte är riktigt samma sak som att skära från slutet av en sekvens i Python. Exemplet ovan returnerar det sista objektet först, sedan det näst sista objektet och så vidare. Om vi hade en Python-sekvens och tittade på seq[-5:]
, skulle vi se det femte sista objektet först. Django stöder inte detta sätt (att skära från slutet), eftersom det inte är möjligt att göra det effektivt i SQL.
Observera också att reverse()
i allmänhet endast bör anropas på ett QuerySet
som har en definierad ordning (t.ex. vid en fråga mot en modell som definierar en standardordning eller vid användning av order_by()
). Om ingen sådan ordning är definierad för ett visst QuerySet
, har det ingen verklig effekt att anropa reverse()
på det (ordningen var odefinierad före anropet av reverse()
och kommer att förbli odefinierad efteråt).
distinct()
¶
- distinct(*fields)¶
Returnerar en ny QuerySet
som använder SELECT DISTINCT
i sin SQL-fråga. Detta eliminerar duplicerade rader från frågeresultaten.
Som standard kommer en QuerySet
inte att eliminera duplicerade rader. I praktiken är detta sällan ett problem, eftersom enkla frågor som Blog.objects.all()
inte introducerar möjligheten till duplicerade resultatrader. Men om din fråga spänner över flera tabeller är det möjligt att få dubbla resultat när en QuerySet
utvärderas. Det är då du skulle använda distinct()
.
Observera
Alla fält som används i ett order_by()
-anrop ingår i SQL-kolumnerna SELECT
. Detta kan ibland leda till oväntade resultat när det används tillsammans med distinct()
. Om du beställer efter fält från en relaterad modell kommer dessa fält att läggas till i de valda kolumnerna och de kan göra att annars duplicerade rader verkar vara distinkta. Eftersom de extra kolumnerna inte visas i de returnerade resultaten (de finns bara där för att stödja beställningen) ser det ibland ut som om icke-distinkta resultat returneras.
På samma sätt, om du använder en values()
-fråga för att begränsa de kolumner som väljs, kommer de kolumner som används i en order_by()
(eller standardmodellordning) fortfarande att vara inblandade och kan påverka resultatens unikhet.
Sensmoralen här är att om du använder distinct()
var försiktig med att beställa efter relaterade modeller. På samma sätt, när du använder distinct()
och values()
tillsammans, var försiktig när du beställer efter fält som inte finns i values()
-anropet.
Endast på PostgreSQL kan du skicka positionella argument (`` * fält``) för att ange namnen på fält som `` DISTINCT`` ska gälla. Detta översätts till en SQL-fråga SELECT DISTINCT ON
. Här är skillnaden. Vid ett normalt distinct()
-anrop jämför databasen varje fält i varje rad när den avgör vilka rader som är distinkta. Vid ett distinct()
-anrop med specificerade fältnamn jämför databasen bara de specificerade fältnamnen.
Observera
När du anger fältnamn måste du tillhandahålla en order_by()
i QuerySet
, och fälten i order_by()
måste börja med fälten i distinct()
, i samma ordning.
Till exempel:, SELECT DISTINCT ON (a)
ger dig den första raden för varje värde i kolumn a
. Om du inte anger någon ordning får du någon godtycklig rad.
Exempel (de efter den första kommer bara att fungera på PostgreSQL):
>>> Author.objects.distinct()
[...]
>>> Entry.objects.order_by("pub_date").distinct("pub_date")
[...]
>>> Entry.objects.order_by("blog").distinct("blog")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
[...]
>>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
[...]
>>> Entry.objects.order_by("author", "pub_date").distinct("author")
[...]
Observera
Tänk på att order_by()
använder all standardordning för relaterade modeller som har definierats. Du kan behöva uttryckligen beställa efter relationens _id
eller det refererade fältet för att se till att DISTINCT ON
-uttrycken matchar dem i början av ORDER BY
-klausulen. Till exempel:, om modellen Blog
definierade en ordering
by name
:
Entry.objects.order_by("blog").distinct("blog")
… skulle inte fungera eftersom frågan skulle beställas av blog__name
och därmed inte matcha DISTINCT ON
-uttrycket. Du måste uttryckligen beställa efter relationens _id
-fält (blog_id
i det här fallet) eller den refererade (blog__pk
) för att se till att båda uttrycken matchar.
värden()
¶
- values(*fields, **expressions)¶
Returnerar en QuerySet
som returnerar ordböcker, snarare än modellinstanser, när den används som en iterabel.
Var och en av dessa ordböcker representerar ett objekt, med nycklar som motsvarar attributnamnen för modellobjekt.
I detta exempel jämförs ordlistorna i values()
med de normala modellobjekten:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
Metoden values()
tar emot valfria positionella argument, *fields
, som anger fältnamn som SELECT
ska begränsas till. Om du anger fälten kommer varje dictionary endast att innehålla fältnycklarna/värdena för de fält du anger. Om du inte anger fälten kommer varje ordbok att innehålla en nyckel och ett värde för varje fält i databastabellen.
Exempel:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
Metoden values()
tar också valfria nyckelordsargument, **expressions
, som skickas vidare till annotate()
:
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
Du kan använda inbyggda och custom lookups i beställningen. Till exempel:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>
Ett aggregat inom en values()
-sats tillämpas före andra argument inom samma values()
-sats. Om du behöver gruppera efter ett annat värde lägger du till det i en tidigare values()
-sats istället. Ett exempel:
>>> from django.db.models import Count
>>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
Några finesser som är värda att nämna:
Om du har ett fält som heter
foo
som är enForeignKey
, kommer standardanropetvalues()
att returnera en ordboksnyckel som heterfoo_id
, eftersom detta är namnet på det dolda modellattributet som lagrar det faktiska värdet (attributetfoo
hänvisar till den relaterade modellen). När du anroparvalues()
och skickar in fältnamn kan du skicka in antingenfoo
ellerfoo_id
och du kommer att få tillbaka samma sak (ordboksnyckeln matchar fältnamnet du skickade in).Till exempel:
>>> Entry.objects.values() <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]> >>> Entry.objects.values("blog") <QuerySet [{'blog': 1}, ...]> >>> Entry.objects.values("blog_id") <QuerySet [{'blog_id': 1}, ...]>
När du använder
values()
tillsammans meddistinct()
bör du vara medveten om att ordningen kan påverka resultatet. Se anmärkningen idistinct()
för mer information.Om du använder en
values()
-sats efter ettextra()
-anrop, måste alla fält som definieras av ettselect
-argument iextra()
uttryckligen inkluderas ivalues()
-anropet. Allaextra()
-anrop som görs efter ettvalues()
-anrop kommer att få sina extra valda fält ignorerade.Att anropa
only()
ochdefer()
eftervalues()
är inte meningsfullt, så det kommer att ge upphov till ettTypeError
.För att kombinera transformationer och aggregat krävs att två
annotate()
-anrop används, antingen explicit eller som nyckelordsargument tillvalues()
. Som ovan, om transformationen har registrerats på den relevanta fälttypen kan den förstaannotate()
utelämnas, vilket innebär att följande exempel är likvärdiga:>>> from django.db.models import CharField, Count >>> from django.db.models.functions import Lower >>> CharField.register_lookup(Lower) >>> Blog.objects.values("entry__authors__name__lower").annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.values(entry__authors__name__lower=Lower("entry__authors__name")).annotate( ... entries=Count("entry") ... ) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]> >>> Blog.objects.annotate(entry__authors__name__lower=Lower("entry__authors__name")).values( ... "entry__authors__name__lower" ... ).annotate(entries=Count("entry")) <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
Det är användbart när du vet att du bara kommer att behöva värden från ett litet antal av de tillgängliga fälten och du inte behöver funktionaliteten hos ett modellinstansobjekt. Det är mer effektivt att bara välja de fält som du behöver använda.
Slutligen, notera att du kan anropa filter()
, order_by()
, etc. efter values()
-anropet, vilket innebär att dessa två anrop är identiska:
Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()
De som skapade Django föredrar att lägga alla SQL-påverkande metoder först, följt (eventuellt) av alla output-påverkande metoder (som values()
), men det spelar egentligen ingen roll. Det här är din chans att verkligen visa upp din individualism.
Du kan också hänvisa till fält i relaterade modeller med omvända relationer genom attributen OneToOneField
, ForeignKey
och ManyToManyField
:
>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
Varning
Eftersom ManyToManyField
-attribut och omvända relationer kan ha flera relaterade rader, kan inkludering av dessa ha en multiplikatoreffekt på storleken på din resultatuppsättning. Detta kommer att vara särskilt uttalat om du inkluderar flera sådana fält i din values()
-fråga, i vilket fall alla möjliga kombinationer kommer att returneras.
Specialvärden för JSONField
på SQLite
På grund av hur SQL-funktionerna JSON_EXTRACT
och JSON_TYPE
implementeras i SQLite, och avsaknaden av datatypen BOOLEAN
, kommer values()
att returnera True
, False
och None
istället för "true"
, "false"
och "null"
strängar för JSONField
nyckelomvandlingar.
SELECT
-klausulen som genereras vid användning av values()
uppdaterades för att respektera ordningen på de angivna *fälten
och **uttrycken
.
värden_lista()`
¶
- values_list(*fields, flat=False, named=False)¶
Detta liknar values()
förutom att den istället för att returnera ordböcker returnerar tuplar när den itereras över. Varje tupel innehåller värdet från respektive fält eller uttryck som skickas till anropet values_list()
- så det första objektet är det första fältet, etc. Till exempel:
>>> Entry.objects.values_list("id", "headline")
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list("id", Lower("headline"))
<QuerySet [(1, 'first entry'), ...]>
Om du bara skickar in ett enda fält kan du också skicka in parametern flat
. Om den är True
innebär detta att de returnerade resultaten är enskilda värden snarare än 1-tupler. Ett exempel bör göra skillnaden tydligare:
>>> Entry.objects.values_list("id").order_by("id")
<QuerySet[(1,), (2,), (3,), ...]>
>>> Entry.objects.values_list("id", flat=True).order_by("id")
<QuerySet [1, 2, 3, ...]>
Det är fel att skicka in flat
när det finns mer än ett fält.
Du kan ange named=True
för att få resultat som en namedtuple()
:
>>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
Att använda en namngiven tupel kan göra det lättare att läsa resultaten, på bekostnad av en liten prestandaförlust för att omvandla resultaten till en namngiven tupel.
Om du inte skickar några värden till values_list()
returneras alla fält i modellen i den ordning de deklarerades.
Ett vanligt behov är att få ett specifikt fältvärde för en viss modellinstans. För att uppnå det använder du values_list()
följt av ett get()
-anrop:
>>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'
values()
och values_list()
är båda avsedda som optimeringar för ett specifikt användningsfall: att hämta en delmängd av data utan att skapa en modellinstans. Denna metafor faller sönder när man hanterar många-till-många och andra flervärdesrelationer (t.ex. en-till-många-relationen för en omvänd främmande nyckel) eftersom antagandet ”en rad, ett objekt” inte håller.
Lägg till exempel märke till beteendet vid en fråga över en ManyToManyField
:
>>> Author.objects.values_list("name", "entry__headline")
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
('Don Quixote', None)]>
Författare med flera poster visas flera gånger och författare utan några poster har None
för postrubriken.
På samma sätt visas None
för poster som inte har någon författare när du frågar efter en omvänd främmande nyckel:
>>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
Specialvärden för JSONField
på SQLite
På grund av hur SQL-funktionerna JSON_EXTRACT
och JSON_TYPE
implementeras i SQLite, och avsaknaden av datatypen BOOLEAN
, kommer values_list()
att returnera True
, False
och None
istället för "true"
, "false"
och "null"
strängar för JSONField
key transforms.
Klausulen SELECT
som genereras vid användning av values_list()
uppdaterades för att respektera ordningen på de angivna *fälten
.
datum()`
¶
- dates(field, kind, order='ASC')¶
Returnerar en QuerySet
som utvärderas till en lista med datetime.date
-objekt som representerar alla tillgängliga datum av en viss typ inom innehållet i QuerySet
.
field
ska vara namnet på en DateField
av din modell. kind
bör vara antingen "year"
, "month"
, "week"
eller "day"
. Varje datetime.date
-objekt i resultatlistan ”trunkeras” till den angivna typen
.
"year"
returnerar en lista med alla distinkta årsvärden för fältet."month"
returnerar en lista med alla distinkta år/månad-värden för fältet."week"
returnerar en lista med alla distinkta år/veckovärden för fältet. Alla datum kommer att vara en måndag."day"
returnerar en lista med alla distinkta år/månad/dag-värden för fältet.
order
, som har standardvärdet 'ASC'
, bör vara antingen 'ASC'
eller 'DESC'
. Detta anger hur resultaten ska ordnas.
Exempel:
>>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]
datetimes()`
¶
- datetimes(field_name, kind, order='ASC', tzinfo=None)¶
Returnerar en QuerySet
som utvärderas till en lista med datetime.datetime
-objekt som representerar alla tillgängliga datum av en viss typ inom innehållet i QuerySet
.
field_name
ska vara namnet på en DateTimeField
i din modell.
kind
bör vara antingen "year"
, "month"
, "week"
, "day"
, "hour"
, "minute"
eller "second"
. Varje datetime.datetime
-objekt i resultatlistan ”trunkeras” till den angivna typen
.
order
, som har standardvärdet 'ASC'
, bör vara antingen 'ASC'
eller 'DESC'
. Detta anger hur resultaten ska ordnas.
tzinfo
definierar den tidszon till vilken datatider konverteras före trunkering. En given datatid har faktiskt olika representationer beroende på vilken tidszon som används. Denna parameter måste vara ett datetime.tzinfo
-objekt. Om den är None
använder Django :ref:aktuell tidszon <default-current-time-zone>
. Det har ingen effekt när USE_TZ
är False
.
Observera
Denna funktion utför tidszonskonverteringar direkt i databasen. Som en konsekvens måste din databas kunna tolka värdet av tzinfo.tzname(None)
. Detta översätts till följande krav:
SQLite: inga krav. Konverteringar utförs i Python.
PostgreSQL: inga krav (se Time Zones).
Oracle: inga krav (se Välja en tidszonfil).
MySQL: ladda tidszonstabellerna med mysql_tzinfo_to_sql.
none()
¶
- none()¶
Om du anropar none()
skapas en queryset som aldrig returnerar några objekt och ingen query kommer att köras vid åtkomst till resultaten. En qs.none()
queryset är en instans av EmptyQuerySet
.
Exempel:
>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True
all()
¶
- all()¶
Returnerar en kopia av den aktuella QuerySet
(eller QuerySet
-underklassen). Detta kan vara användbart i situationer där du kanske vill skicka in antingen en modellhanterare eller en QuerySet
och göra ytterligare filtrering på resultatet. Efter att ha anropat all()
på något av objekten har du definitivt ett QuerySet
att arbeta med.
När en QuerySet
:ref:evaluated <when-querysets-are-evaluated>
utvärderas, lagras resultaten i cachen. Om data i databasen kan ha ändrats sedan en QuerySet
utvärderades kan du få uppdaterade resultat för samma fråga genom att anropa all()
på en tidigare utvärderad QuerySet
.
union()`
¶
- union(*other_qs, all=False)¶
Använder SQL:s operator UNION
för att kombinera resultaten från två eller flera QuerySet
. Till exempel:
>>> qs1.union(qs2, qs3)
Operatorn UNION
väljer som standard endast distinkta värden. För att tillåta duplicerade värden, använd argumentet all=True
.
union()
, intersection()
och difference()
returnerar modellinstanser av typen för den första QuerySet
även om argumenten är QuerySet
av andra modeller. Att skicka olika modeller fungerar så länge som SELECT
-listan är densamma i alla QuerySet
(åtminstone typerna, namnen spelar ingen roll så länge som typerna är i samma ordning). I sådana fall måste du använda kolumnnamnen från det första QuerySet
i QuerySet
-metoder som tillämpas på det resulterande QuerySet
. Till exempel:
>>> qs1 = Author.objects.values_list("name")
>>> qs2 = Entry.objects.values_list("headline")
>>> qs1.union(qs2).order_by("name")
Dessutom är endast LIMIT
, OFFSET
, COUNT(*)
, ORDER BY
och specificering av kolumner (dvs. slicing, count()
, exists()
, order_by()
och values()
/values_list()
) tillåtna på den resulterande QuerySet
. Dessutom lägger databaser restriktioner på vilka operationer som är tillåtna i de kombinerade frågorna. De flesta databaser tillåter t.ex. inte LIMIT
eller OFFSET
i de kombinerade frågorna.
intersektion()
¶
- intersection(*other_qs)¶
Använder SQL:s operator INTERSECT
för att returnera de delade elementen i två eller flera QuerySet
. Till exempel:
>>> qs1.intersection(qs2, qs3)
Se union()
för vissa begränsningar.
skillnad()
¶
- difference(*other_qs)¶
Använder SQL:s operator EXCEPT
för att endast behålla element som finns i QuerySet
men inte i några andra QuerySet
. Till exempel:
>>> qs1.difference(qs2, qs3)
Se union()
för vissa begränsningar.
extra()`
¶
- extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)¶
Ibland kan Djangos frågesyntax i sig inte enkelt uttrycka en komplex WHERE
-klausul. För dessa kantfall tillhandahåller Django modifieraren extra()
QuerySet
- en krok för att injicera specifika klausuler i SQL som genereras av en QuerySet
.
Använd denna metod som en sista utväg
Detta är ett gammalt API som vi har för avsikt att avskaffa någon gång i framtiden. Använd det endast om du inte kan uttrycka din fråga med hjälp av andra queryset-metoder. Om du behöver använda det, öppna ett ärende med nyckelordet QuerySet.extra med ditt användningsfall (kontrollera listan över befintliga biljetter först) så att vi kan förbättra QuerySet API för att tillåta borttagning av extra()
. Vi förbättrar inte längre eller fixar buggar för den här metoden.
Till exempel: denna användning av extra()
:
>>> qs.extra(
... select={"val": "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
är likvärdig med:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
Den största fördelen med att använda RawSQL
är att du kan ställa in output_field
om det behövs. Den största nackdelen är att om du hänvisar till något tabellalias för queryset i den råa SQL, så är det möjligt att Django kan ändra det aliaset (till exempel när queryset används som en underfråga i ännu en fråga).
Varning
Du bör vara mycket försiktig när du använder extra()
. Varje gång du använder den bör du undkomma alla parametrar som användaren kan kontrollera med hjälp av params
för att skydda mot SQL-injektionsattacker.
Du får inte heller använda citattecken för platshållare i SQL-strängen. Det här exemplet är sårbart för SQL-injektion på grund av citaten runt %s
:
SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
Du kan läsa mer om hur Djangos SQL injection protection fungerar.
Per definition kan dessa extra uppslagningar inte vara portabla till olika databasmotorer (eftersom du uttryckligen skriver SQL-kod) och bryter mot DRY-principen, så du bör undvika dem om möjligt.
Ange ett eller flera av params
, select
, where
eller tables
. Inget av argumenten är obligatoriskt, men du bör använda minst ett av dem.
välja
Med argumentet
select
kan du lägga till extra fält iSELECT
-satsen. Det bör vara en ordbok som mappar attributnamn till SQL-satser som ska användas för att beräkna attributet.Exempel:
Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})
Som ett resultat kommer varje
Entry
-objekt att ha ett extra attribut,is_recent
, ett boolean som anger om postenspub_date
är större än 1 januari 2006.Django infogar det angivna SQL-utdraget direkt i
SELECT
-satsen, så den resulterande SQL i ovanstående exempel skulle vara något liknande:SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
Nästa exempel är mer avancerat; det gör en underfråga för att ge varje resulterande
Blog
-objekt ettentry_count
-attribut, ett heltalsantal av associeradeEntry
-objekt:Blog.objects.extra( select={ "entry_count": "SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id" }, )
I detta speciella fall utnyttjar vi det faktum att frågan redan kommer att innehålla tabellen
blog_blog
i sinFROM
-klausul.Den resulterande SQL i ovanstående exempel skulle vara:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
Observera att de parenteser som krävs av de flesta databasmotorer runt underfrågor inte krävs i Djangos
select
-klausuler.I vissa sällsynta fall kan du vilja skicka parametrar till SQL-fragmenten i
extra(select=...)
. För detta ändamål använder du parameternselect_params
.Detta kommer att fungera, till exempel:
Blog.objects.extra( select={"a": "%s", "b": "%s"}, select_params=("one", "two"), )
Om du behöver använda en bokstavlig
%s
i din select-sträng använder du sekvensen%%s
.where
/tables
Du kan definiera explicita SQL
WHERE
-klausuler - kanske för att utföra icke-explicita sammanfogningar - genom att användawhere
. Du kan manuellt lägga till tabeller i SQL-satsenFROM
med hjälp avtables
.where
ochtables
tar båda emot en lista med strängar. Allawhere
parametrar är ”AND”ed till alla andra sökkriterier.Exempel:
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
…översätts (ungefär) till följande SQL:
SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Var försiktig när du använder parametern
tables
om du anger tabeller som redan används i frågan. När du lägger till extra tabeller via parameterntables
antar Django att du vill att den tabellen ska inkluderas en extra gång, om den redan är inkluderad. Det skapar ett problem, eftersom tabellnamnet då får ett alias. Om en tabell förekommer flera gånger i en SQL-sats måste den andra och efterföljande förekomsterna använda alias så att databasen kan skilja dem åt. Om du hänvisar till den extra tabellen som du lade till i den extrawhere
-parametern kommer detta att orsaka fel.Normalt lägger du bara till extra tabeller som inte redan finns i frågan. Men om det fall som beskrivs ovan inträffar finns det några lösningar. Först kan du se om du kan klara dig utan att inkludera den extra tabellen och använda den som redan finns i frågan. Om det inte är möjligt, placera ditt
extra()
-anrop längst fram i queryset-konstruktionen så att din tabell är den första användningen av den tabellen. Slutligen, om allt annat misslyckas, titta på den query som producerats och skriv om dittwhere
-tillägg för att använda det alias som ges till din extra tabell. Aliaset kommer att vara detsamma varje gång du konstruerar queryset på samma sätt, så du kan lita på att aliasnamnet inte ändras.order_by
Om du behöver ordna den resulterande frågeuppsättningen med hjälp av några av de nya fält eller tabeller som du har inkluderat via
extra()
, använd parameternorder_by
tillextra()
och skicka in en sekvens av strängar. Dessa strängar bör antingen vara modellfält (som i den normalaorder_by()
-metoden på querysets), av formentable_name.column_name
eller ett alias för en kolumn som du angav iselect
-parametern tillextra()
.Till exempel:
q = Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"}) q = q.extra(order_by=["-is_recent"])
Detta skulle sortera alla objekt för vilka
is_recent
är sant längst fram i resultatuppsättningen (True
sorteras föreFalse
i en fallande ordning).Detta visar förresten att du kan göra flera anrop till
extra()
och att det kommer att bete sig som du förväntar dig (lägga till nya begränsningar varje gång).params
Parametern
where
som beskrivs ovan kan använda Pythons standardplatshållare för databassträngar -'%s'
för att ange parametrar som databasmotorn automatiskt ska citera. Argumentetparams
är en lista över eventuella extra parametrar som ska ersättas.Exempel:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Använd alltid
params
istället för att bädda in värden direkt iwhere
eftersomparams
ser till att värdena citeras korrekt enligt din specifika backend. Till exempel: kommer citattecken att escapas korrekt.Dålig:
Entry.objects.extra(where=["headline='Lennon'"])
Bra:
Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Varning
Om du utför frågor på MySQL, observera att MySQL: s tysta typcoercion kan orsaka oväntade resultat när du blandar typer. Om du ställer en fråga på en kolumn av strängtyp, men med ett heltalsvärde, kommer MySQL att tvinga typerna för alla värden i tabellen till ett heltal innan jämförelsen utförs. Om din tabell till exempel innehåller värdena 'abc'
, 'def'
och du frågar efter WHERE mycolumn=0
, kommer båda raderna att matcha. För att förhindra detta måste du utföra korrekt typecasting innan du använder värdet i en fråga.
defer()
¶
- defer(*fields)¶
I vissa komplexa datamodelleringssituationer kan dina modeller innehålla många fält, varav vissa kan innehålla mycket data (till exempel textfält) eller kräva dyr bearbetning för att konvertera dem till Python-objekt. Om du använder resultaten av en queryset i en situation där du inte vet om du behöver just de här fälten när du först hämtar data, kan du säga till Django att inte hämta dem från databasen.
Detta görs genom att skicka namnen på de fält som inte ska laddas till defer()
:
Entry.objects.defer("headline", "body")
En queryset som har uppskjutna fält kommer fortfarande att returnera modellinstanser. Varje uppskjutet fält hämtas från databasen om du öppnar det fältet (ett i taget, inte alla uppskjutna fält på en gång).
Observera
Uppskjutna fält kommer inte att lazy-loadas på det här sättet från asynkron kod. Istället kommer du att få ett SynchronousOnlyOperation
undantag. Om du skriver asynkron kod bör du inte försöka komma åt några fält som du defer()
.
Du kan göra flera anrop till defer()
. Varje anrop lägger till nya fält i den uppskjutna uppsättningen:
# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")
Ordningen i vilken fälten läggs till i den uppskjutna uppsättningen spelar ingen roll. Att anropa defer()
med ett fältnamn som redan har skjutits upp är ofarligt (fältet kommer fortfarande att skjutas upp).
Du kan skjuta upp laddningen av fält i relaterade modeller (om de relaterade modellerna laddas via select_related()
) genom att använda standardnotationen med dubbla understrykningar för att separera relaterade fält:
Blog.objects.select_related().defer("entry__headline", "entry__body")
Om du vill rensa uppsättningen av uppskjutna fält, skicka None
som en parameter till defer()
:
# Load all fields immediately.
my_queryset.defer(None)
Vissa fält i en modell kommer inte att skjutas upp, även om du ber om dem. Du kan aldrig skjuta upp laddningen av primärnyckeln. Om du använder select_related()
för att hämta relaterade modeller ska du inte skjuta upp laddningen av det fält som kopplar från den primära modellen till den relaterade modellen, eftersom det leder till ett fel.
På samma sätt är det inte meningsfullt att anropa defer()
(eller dess motsvarighet only()
) med ett argument från en aggregering (t.ex. genom att använda resultatet av annotate()
): detta kommer att leda till ett undantag. De aggregerade värdena kommer alltid att hämtas till den resulterande queryset.
Observera
Metoden defer()
(och dess kusin, only()
, nedan) är endast avsedd för avancerade användningsfall. De ger en optimering för när du har analyserat dina frågor noggrant och förstår exakt vilken information du behöver och har mätt att skillnaden mellan att returnera de fält du behöver och den fullständiga uppsättningen fält för modellen kommer att vara betydande.
Även om du tror att du befinner dig i ett avancerat användningsfall, ska du bara använda defer()
när du inte, vid laddning av queryset, kan avgöra om du behöver de extra fälten eller inte. Om du ofta laddar och använder en viss delmängd av dina data är det bästa valet du kan göra att normalisera dina modeller och lägga de icke-laddade data i en separat modell (och databastabell). Om kolumnerna måste stanna i en tabell av någon anledning, skapa en modell med Meta.managed = False
(se managed attribut
dokumentation) som bara innehåller de fält som du normalt behöver ladda och använd den där du annars skulle ringa defer()
. Detta gör din kod mer explicit för läsaren, är något snabbare och förbrukar lite mindre minne i Python-processen.
Till exempel: använder båda dessa modeller samma underliggande databastabell:
class CommonlyUsedModel(models.Model):
f1 = models.CharField(max_length=10)
class Meta:
managed = False
db_table = "app_largetable"
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
db_table = "app_largetable"
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer("f2")
Om många fält behöver dupliceras i den ohanterade modellen kan det vara bäst att skapa en abstrakt modell med de delade fälten och sedan låta den ohanterade och den hanterade modellen ärva från den abstrakta modellen.
endast()`
¶
- only(*fields)¶
Metoden only()
är i princip motsatsen till defer()
. Endast de fält som skickas till den här metoden och som inte redan har angetts som uppskjutna laddas omedelbart när frågeuppsättningen utvärderas.
Om du har en modell där nästan alla fält måste skjutas upp kan du använda only()
för att ange den kompletterande uppsättningen fält, vilket kan resultera i enklare kod.
Anta att du har en modell med fälten namn
, ålder
och biografi
. Följande två frågeuppsättningar är desamma när det gäller uppskjutna fält:
Person.objects.defer("age", "biography")
Person.objects.only("name")
När du anropar only()
ersätter den uppsättning fält som ska laddas omedelbart. Metodens namn är ett minnesmärke: endast dessa fält laddas omedelbart; resten skjuts upp. Successiva anrop till only()
resulterar således i att endast de sista fälten beaktas:
# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")
Eftersom defer()
agerar stegvis (lägger till fält i den uppskjutna listan) kan du kombinera anrop till only()
och defer()
och saker och ting kommer att bete sig logiskt:
# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline immediately.
Entry.objects.defer("body").only("headline", "body")
Alla varningar i anmärkningen för defer()
-dokumentationen gäller även för only()
. Använd den försiktigt och endast efter att ha uttömt dina andra alternativ.
Att använda only()
och utelämna ett fält som begärts med select_related()
är också ett fel. Å andra sidan kommer anrop av only()
utan några argument att returnera alla fält (inklusive annoteringar) som hämtats av queryset.
Precis som med defer()
kan du inte komma åt de icke-laddade fälten från asynkron kod och förvänta dig att de laddas. Istället kommer du att få ett SynchronousOnlyOperation
undantag. Se till att alla fält som du kan komma åt finns i ditt only()
-anrop.
använda()`
¶
- using(alias)¶
Den här metoden används för att styra vilken databas som QuerySet
ska utvärderas mot om du använder mer än en databas. Det enda argument som den här metoden tar emot är aliaset för en databas, enligt definitionen i DATABASES
.
Till exempel:
# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using("backup")
select_for_update()
¶
- select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)¶
Returnerar en queryset som låser rader till slutet av transaktionen, vilket genererar en SQL-sats SELECT ... FOR UPDATE
på databaser som stöds.
Till exempel:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
När queryset utvärderas (i det här fallet for entry in entries
) kommer alla matchade poster att låsas fram till slutet av transaktionsblocket, vilket innebär att andra transaktioner inte kan ändra eller förvärva lås på dem.
Om en annan transaktion redan har skaffat ett lås på en av de valda raderna blockeras vanligtvis frågan tills låset frigörs. Om detta inte är det beteende du vill ha kan du anropa select_for_update(nowait=True)
. Detta gör anropet icke-blockerande. Om ett motstridigt lås redan har förvärvats av en annan transaktion, kommer DatabaseError
att tas upp när queryset utvärderas. Du kan också ignorera låsta rader genom att använda select_for_update(skip_locked=True)
istället. Alternativen nowait
och skip_locked
är ömsesidigt uteslutande och försök att anropa select_for_update()
med båda alternativen aktiverade kommer att resultera i ett ValueError
.
Som standard låser select_for_update()
alla rader som väljs av frågan. Till exempel: låses rader med relaterade objekt som anges i select_related()
utöver raderna i frågeuppsättningens modell. Om detta inte är önskvärt kan du ange de relaterade objekt som du vill låsa i select_for_update(of=(...))
med samma fältsyntax som i select_related()
. Använd värdet 'self'
för att hänvisa till frågeuppsättningens modell.
Låsa föräldramodeller i select_for_update(of=(...))
Om du vill låsa föräldramodeller när du använder :ref:multi-table inheritance <multi-table-inheritance>
, måste du ange föräldralänkfält (som standard <parent_model_name>_ptr
) i argumentet of
. Till exempel:
Restaurant.objects.select_for_update(of=("self", "place_ptr"))
Använda select_for_update(of=(...))
med angivna fält
Om du vill låsa modeller och ange valda fält, t.ex. med hjälp av values()
, måste du välja minst ett fält från varje modell i argumentet of
. Modeller utan valda fält kommer inte att låsas.
Endast på PostgreSQL kan du skicka `` no_key = True `` för att få ett svagare lås, som fortfarande tillåter att skapa rader som bara refererar till låsta rader (till exempel genom en främmande nyckel) medan låset är på plats. PostgreSQL-dokumentationen har mer information om låslägen på radnivå <https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS>`_.
Du kan inte använda select_for_update()
på nullable-relationer:
>>> Person.objects.select_related("hometown").select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
För att undvika den begränsningen kan du utesluta null-objekt om du inte bryr dig om dem:
>>> Person.objects.select_related("hometown").select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
Databasbackendarna postgresql
, oracle
och mysql
stöder select_for_update()
. MariaDB stöder dock endast argumentet nowait
, MariaDB 10.6+ stöder även argumentet skip_locked
och MySQL stöder argumenten nowait
, skip_locked
och of
. Argumentet no_key
stöds endast på PostgreSQL.
Att skicka nowait=True
, skip_locked=True
, no_key=True
eller of
till select_for_update()
med databasbackends som inte stöder dessa alternativ, till exempel MySQL, ger upphov till ett NotSupportedError
. Detta förhindrar att koden oväntat blockeras.
Att utvärdera en queryset med select_for_update()
i autocommit-läge på backends som stöder SELECT ... FOR UPDATE
är ett TransactionManagementError
-fel eftersom raderna inte är låsta i det fallet. Om det var tillåtet skulle detta underlätta datakorruption och kan lätt orsakas av anropande kod som förväntar sig att köras i en transaktion utanför en transaktion.
Att använda select_for_update()
på backends som inte stöder SELECT ... FOR UPDATE
(t.ex. SQLite) har ingen effekt. SELECT ... FOR UPDATE
läggs inte till i frågan och ett fel uppstår inte om select_for_update()
används i autocommit-läge.
Varning
Även om select_for_update()
normalt misslyckas i autocommit-läge, eftersom TestCase
automatiskt omsluter varje test i en transaktion, kommer anrop av select_for_update()
i ett TestCase
även utanför ett atomic()
-block (kanske oväntat) att passera utan att ge upphov till ett TransactionManagementError
. För att korrekt testa select_for_update()
bör du använda TransactionTestCase
.
raw()
¶
- raw(raw_query, params=(), translations=None, using=None)¶
Tar en rå SQL-fråga, kör den och returnerar en django.db.models.query.RawQuerySet
-instans. Denna RawQuerySet
-instans kan itereras över precis som en vanlig QuerySet
för att tillhandahålla objektinstanser.
Se Utföra SQL-frågor i råformat för mer information.
Varning
raw()
utlöser alltid en ny fråga och tar inte hänsyn till tidigare filtrering. Därför bör den i allmänhet anropas från Manager
eller från en ny QuerySet
-instans.
Operatorer som returnerar nya QuerySet
¶
Kombinerade querysets måste använda samma modell.
AND (&
)¶
Kombinerar två QuerySet
med SQL-operatorn AND
på ett sätt som liknar kedjning av filter.
Följande är likvärdiga:
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1).filter(y=2)
SQL-ekvivalent:
SELECT ... WHERE x=1 AND y=2
ELLER (|
)¶
Kombinerar två QuerySet
med hjälp av SQL-operatorn OR
.
Följande är likvärdiga:
Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) | Q(y=2))
SQL-ekvivalent:
SELECT ... WHERE x=1 OR y=2
|
är inte en kommutativ operation, eftersom olika (men likvärdiga) frågor kan genereras.
XOR (^
)¶
Kombinerar två QuerySet
med hjälp av SQL-operatorn XOR
. Ett XOR
-uttryck matchar rader som matchas av ett udda antal operander.
Följande är likvärdiga:
Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q
Model.objects.filter(Q(x=1) ^ Q(y=2))
SQL-ekvivalent:
SELECT ... WHERE x=1 XOR y=2
Observera
XOR
har inbyggt stöd i MariaDB och MySQL. På andra databaser konverteras x ^ y ^ ... ^ z
konverteras till en motsvarighet:
(x OR y OR ... OR z) AND
1=MOD(
(CASE WHEN x THEN 1 ELSE 0 END) +
(CASE WHEN y THEN 1 ELSE 0 END) +
...
(CASE WHEN z THEN 1 ELSE 0 END),
2
)
Metoder som inte returnerar QuerySet
¶
Följande QuerySet
-metoder utvärderar QuerySet
och returnerar något annat än ett QuerySet
.
Dessa metoder använder inte en cache (se Cachelagring och ”QuerySet). Istället frågar de databasen varje gång de anropas.
Eftersom dessa metoder utvärderar QuerySet är de blockerande anrop, och därför kan deras huvudsakliga (synkrona) versioner inte anropas från asynkron kod. Av denna anledning har var och en en motsvarande asynkron version med prefixet a
- till exempel, i stället för get(...)
kan du await aget(...)
.
Det finns vanligtvis ingen skillnad i beteende bortsett från deras asynkrona natur, men eventuella skillnader noteras nedan bredvid varje metod.
get()`
¶
- get(*args, **kwargs)¶
- aget(*args, **kwargs)¶
Asynkron version: aget()
Returnerar objektet som matchar de angivna parametrarna för lookup, som bör vara i det format som beskrivs i Field lookups. Du bör använda uppslagningar som garanterat är unika, t.ex. primärnyckeln eller fält i en unik begränsning. Till exempel:
Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))
Om du förväntar dig att en queryset redan ska returnera en rad kan du använda get()
utan några argument för att returnera objektet för den raden:
Entry.objects.filter(pk=1).get()
Om get()
inte hittar något objekt, uppstår ett Model.DoesNotExist
undantag:
Entry.objects.get(id=-999) # raises Entry.DoesNotExist
Om get()
hittar mer än ett objekt, ger det upphov till ett Model.MultipleObjectsReturned
undantag:
Entry.objects.get(name="A Duplicated Name") # raises Entry.MultipleObjectsReturned
Båda dessa undantagsklasser är attribut till modellklassen och är specifika för den modellen. Om du vill hantera sådana undantag från flera get()
-anrop för olika modeller kan du använda deras generiska basklasser. Du kan t.ex. använda django.core.exceptions.ObjectDoesNotExist
för att hantera DoesNotExist
undantag från flera modeller:
from django.core.exceptions import ObjectDoesNotExist
try:
blog = Blog.objects.get(id=1)
entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
print("Either the blog or entry doesn't exist.")
skapa()`
¶
- create(**kwargs)¶
- acreate(**kwargs)¶
Asynkron version: acreate()
En bekväm metod för att skapa ett objekt och spara allt i ett steg. Alltså:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")
och:
p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
är likvärdiga.
Parametern force_insert finns dokumenterad på annat håll, men allt den innebär är att ett nytt objekt alltid kommer att skapas. Normalt behöver du inte oroa dig för detta. Men om din modell innehåller ett manuellt primärnyckelvärde som du ställer in och om det värdet redan finns i databasen, kommer ett anrop till create()
att misslyckas med en IntegrityError
eftersom primärnycklar måste vara unika. Var beredd på att hantera undantaget om du använder manuella primärnycklar.
get_or_create()
¶
- get_or_create(defaults=None, **kwargs)¶
- aget_or_create(defaults=None, **kwargs)¶
Asynkron version: aget_or_create()
En bekväm metod för att leta upp ett objekt med de angivna kwargs
(kan vara tomt om din modell har standardvärden för alla fält), och skapa ett om det behövs.
Returnerar en tupel av (object, created)
, där object
är det hämtade eller skapade objektet och created
är en boolean som anger om ett nytt objekt skapades.
Detta är tänkt att förhindra att duplicerade objekt skapas när förfrågningar görs parallellt, och som en genväg till boilerplatish-kod. Till exempel:
try:
obj = Person.objects.get(first_name="John", last_name="Lennon")
except Person.DoesNotExist:
obj = Person(first_name="John", last_name="Lennon", birthday=date(1940, 10, 9))
obj.save()
Här, med samtidiga förfrågningar, kan flera försök att spara en Person
med samma parametrar göras. För att undvika detta race condition kan exemplet ovan skrivas om med hjälp av get_or_create()
på följande sätt:
obj, created = Person.objects.get_or_create(
first_name="John",
last_name="Lennon",
defaults={"birthday": date(1940, 10, 9)},
)
Alla nyckelordsargument som skickas till get_or_create()
- undantaget ett valfritt som heter defaults
- kommer att användas i ett get()
-anrop. Om ett objekt hittas returnerar get_or_create()
en tupel av det objektet och False
.
Varning
Denna metod är atomisk och förutsätter att databasen tillämpar unikhet för nyckelordsargumenten (se unique
eller unique_together
). Om fälten som används i nyckelordsargumenten inte har en unikhetsbegränsning kan samtidiga anrop till den här metoden resultera i att flera rader med samma parametrar infogas.
Du kan ange mer komplexa villkor för det hämtade objektet genom att kedja get_or_create()
med filter()
och använda Q objects
. Till exempel:, för att hämta Robert eller Bob Marley om någon av dem finns, och skapa den senare annars:
from django.db.models import Q
obj, created = Person.objects.filter(
Q(first_name="Bob") | Q(first_name="Robert"),
).get_or_create(last_name="Marley", defaults={"first_name": "Bob"})
Om flera objekt hittas, ger get_or_create()
upphov till MultipleObjectsReturned
. Om ett objekt inte hittas kommer get_or_create()
att instansiera och spara ett nytt objekt och returnera en tupel av det nya objektet och True
. Det nya objektet kommer att skapas ungefär enligt denna algoritm:
params = {k: v for k, v in kwargs.items() if "__" not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
På engelska betyder det att du börjar med alla nyckelordsargument som inte är defaults
och som inte innehåller ett dubbelt understreck (vilket skulle indikera en icke-exakt uppslagning). Lägg sedan till innehållet i defaults
, åsidosätt eventuella nycklar om det behövs, och använd resultatet som nyckelordsargument till modellklassen. Om det finns några callables i defaults
, utvärdera dem. Som antyddes ovan är detta en förenkling av den algoritm som används, men den innehåller alla relevanta detaljer. Den interna implementationen har lite mer felkontroll än detta och hanterar några extra kantvillkor; om du är intresserad, läs koden.
Om du har ett fält som heter defaults
och vill använda det som en exakt uppslagning i get_or_create()
, använder du 'defaults__exact'
, så här:
Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})
Metoden get_or_create()
har liknande felbeteende som create()
när du använder manuellt specificerade primärnycklar. Om ett objekt behöver skapas och nyckeln redan finns i databasen, kommer ett IntegrityError
att uppstå.
Slutligen, ett ord om att använda get_or_create()
i Django-vyer. Se till att endast använda den i POST
-förfrågningar om du inte har en bra anledning att inte göra det. GET
-förfrågningar bör inte ha någon effekt på data. Använd istället POST
när en begäran till en sida har en sidoeffekt på dina data. För mer information, se Säkra metoder i HTTP-specifikationen.
Varning
Du kan använda get_or_create()
genom ManyToManyField
-attribut och omvända relationer. I det fallet kommer du att begränsa frågorna inom ramen för den relationen. Det kan leda till vissa integritetsproblem om du inte använder det konsekvent.
Gäller följande modeller:
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
Du kan använda get_or_create()
genom Book’s chapters-fält, men det hämtar bara inom kontexten för den boken:
>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError
Detta händer eftersom det försöker hämta eller skapa ”Kapitel 1” genom boken ”Ulysses”, men det kan inte göra någotdera: relationen kan inte hämta det kapitlet eftersom det inte är relaterat till den boken, men det kan inte heller skapa det eftersom fältet title
måste vara unikt.
uppdatera_eller_skapa()
¶
- update_or_create(defaults=None, create_defaults=None, **kwargs)¶
- aupdate_or_create(defaults=None, create_defaults=None, **kwargs)¶
Asynkron version: aupdate_or_create()
En bekvämlighetsmetod för att uppdatera ett objekt med de givna kwargs
, och skapa ett nytt om det behövs. Både create_defaults
och defaults
är dictionaries av (fält, värde) par. Värdena i både create_defaults
och defaults
kan vara callables. defaults
används för att uppdatera objektet medan create_defaults
används för create-operationen. Om create_defaults
inte anges kommer defaults
att användas för att skapa objektet.
Returnerar en tupel av (object, created)
, där object
är det skapade eller uppdaterade objektet och created
är en boolean som anger om ett nytt objekt skapades.
Metoden update_or_create
försöker hämta ett objekt från databasen baserat på de givna kwargs
. Om en matchning hittas, uppdateras fälten som skickas i defaults
dictionary.
Detta är tänkt som en genväg till standardkod. Till exempel:
defaults = {"first_name": "Bob"}
create_defaults = {"first_name": "Bob", "birthday": date(1940, 10, 9)}
try:
obj = Person.objects.get(first_name="John", last_name="Lennon")
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
new_values = {"first_name": "John", "last_name": "Lennon"}
new_values.update(create_defaults)
obj = Person(**new_values)
obj.save()
Det här mönstret blir ganska otympligt när antalet fält i en modell ökar. Exemplet ovan kan skrivas om med hjälp av update_or_create()
på följande sätt:
obj, created = Person.objects.update_or_create(
first_name="John",
last_name="Lennon",
defaults={"first_name": "Bob"},
create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)
För en detaljerad beskrivning av hur namn som skickas i kwargs
löses, se get_or_create()
.
Såsom beskrivs ovan i get_or_create()
, är den här metoden känslig för ett tävlingsförhållande som kan leda till att flera rader infogas samtidigt om unikhet inte upprätthålls på databasnivå.
Precis som get_or_create()
och create()
, om du använder manuellt angivna primära nycklar och ett objekt behöver skapas men nyckeln redan finns i databasen, kommer ett IntegrityError
att uppstå.
bulk_create()
¶
- bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)¶
- abulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)¶
Asynkron version: abulk_create()
Den här metoden infogar den angivna listan med objekt i databasen på ett effektivt sätt (i allmänhet bara 1 fråga, oavsett hur många objekt det finns) och returnerar skapade objekt som en lista i samma ordning som den angivna:
>>> objs = Entry.objects.bulk_create(
... [
... Entry(headline="This is a test"),
... Entry(headline="This is only a test"),
... ]
... )
Detta har dock ett antal förbehåll:
Modellens metod
save()
kommer inte att anropas och signalernapre_save
ochpost_save
kommer inte att skickas.Det fungerar inte med underordnade modeller i ett arvsscenario med flera tabeller.
Om modellens primära nyckel är en
AutoField
ochignore_conflicts
är False, kan det primära nyckelattributet endast hämtas på vissa databaser (för närvarande PostgreSQL, MariaDB och SQLite 3.35+). På andra databaser kommer den inte att ställas in.Det fungerar inte med många-till-manga-relationer.
Den kastar
objs
till en lista, som fullt ut utvärderarobjs
om det är en generator. Castet gör det möjligt att inspektera alla objekt så att alla objekt med en manuellt inställd primärnyckel kan infogas först. Om du vill infoga objekt i satser utan att utvärdera hela generatorn på en gång kan du använda den här tekniken så länge objekten inte har några manuellt inställda primära nycklar:from itertools import islice batch_size = 100 objs = (Entry(headline="Test %s" % i) for i in range(1000)) while True: batch = list(islice(objs, batch_size)) if not batch: break Entry.objects.bulk_create(batch, batch_size)
Parametern batch_size
styr hur många objekt som skapas i en enda fråga. Standardinställningen är att skapa alla objekt i en batch, utom för SQLite där standardinställningen är att högst 999 variabler per fråga används.
I databaser som stöder detta (alla utom Oracle) kan parametern ignore_conflicts
ställas in på True
, vilket innebär att databasen ignorerar misslyckanden med att infoga rader som inte uppfyller begränsningar som t.ex. duplicerade unika värden.
På databaser som stöder det (alla utom Oracle), genom att ställa in parametern update_conflicts
till True
, berättar databasen att uppdatera update_fields
när en radinsättning misslyckas med konflikter. På PostgreSQL och SQLite, förutom update_fields
, måste en lista över unique_fields
som kan vara i konflikt tillhandahållas.
Om parametern ignore_conflicts
aktiveras inaktiveras inställningen av primärnyckeln för varje modellinstans (om databasen normalt stöder detta).
Varning
I MySQL och MariaDB förvandlar inställningen av parametern ignore_conflicts
till True
vissa typer av fel, andra än duplicerade nycklar, till varningar. Även med Strikt läge. Till exempel: ogiltiga värden eller icke-nullbara överträdelser. Se MySQL-dokumentationen och MariaDB-dokumentationen för mer information.
bulk_update()
¶
- bulk_update(objs, fields, batch_size=None)¶
- abulk_update(objs, fields, batch_size=None)¶
Asynkron version: abulk_update()
Denna metod uppdaterar effektivt de angivna fälten på de angivna modellinstanserna, vanligtvis med en fråga, och returnerar antalet uppdaterade objekt:
>>> objs = [
... Entry.objects.create(headline="Entry 1"),
... Entry.objects.create(headline="Entry 2"),
... ]
>>> objs[0].headline = "This is entry 1"
>>> objs[1].headline = "This is entry 2"
>>> Entry.objects.bulk_update(objs, ["headline"])
2
QuerySet.update()
används för att spara ändringarna, så det här är effektivare än att iterera genom listan med modeller och anropa save()
på var och en av dem, men det har några förbehåll:
Du kan inte uppdatera modellens primärnyckel.
Varje modells metod
save()
anropas inte och signalernapre_save
ochpost_save
skickas inte.Om du uppdaterar ett stort antal kolumner i ett stort antal rader kan den SQL som genereras bli mycket stor. Undvik detta genom att ange en lämplig
batch_size
.Uppdatering av fält som definieras på förfäder med flera tabeller kommer att medföra en extra fråga per förfader.
När en enskild batch innehåller dubbletter kommer endast den första förekomsten i den batchen att resultera i en uppdatering.
Det antal uppdaterade objekt som returneras av funktionen kan vara färre än det antal objekt som skickades in. Detta kan bero på duplicerade objekt som skickas in och som uppdateras i samma batch eller tävlingsförhållanden som gör att objekten inte längre finns i databasen.
Parametern batch_size
styr hur många objekt som sparas i en enda fråga. Standardinställningen är att uppdatera alla objekt i en batch, med undantag för SQLite och Oracle som har begränsningar för antalet variabler som används i en fråga.
räkna()`
¶
- count()¶
- acount()¶
Asynkron version: acount()
Returnerar ett heltal som representerar antalet objekt i databasen som matchar QuerySet
.
Exempel:
# Returns the total number of entries in the database.
Entry.objects.count()
# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains="Lennon").count()
Ett count()
-anrop utför en SELECT COUNT(*)
bakom kulisserna, så du bör alltid använda count()
hellre än att ladda alla poster i Python-objekt och anropa len()
på resultatet (såvida du inte behöver ladda objekten i minnet ändå, i vilket fall len()
kommer att vara snabbare).
Observera att om du vill ha antalet objekt i en QuerySet
och även hämtar modellinstanser från den (t.ex. genom att iterera över den), är det förmodligen effektivare att använda len(queryset)
som inte orsakar en extra databasfråga som count()
skulle göra.
Om frågeuppsättningen redan har hämtats i sin helhet kommer count()
att använda den längden i stället för att göra en extra databasförfrågan.
in_bulk()`
¶
- in_bulk(id_list=None, *, field_name='pk')¶
- ain_bulk(id_list=None, *, field_name='pk')¶
Asynkron version: ain_bulk()
Tar en lista med fältvärden (id_list
) och field_name
för dessa värden och returnerar en ordbok som mappar varje värde till en instans av objektet med det angivna fältvärdet. Inga django.core.exceptions.ObjectDoesNotExist
-undantag kommer någonsin att skapas av in_bulk
; det vill säga, alla id_list
-värden som inte matchar någon instans kommer helt enkelt att ignoreras. Om id_list
inte anges returneras alla objekt i queryset. field_name
måste vara ett unikt fält eller ett distinkt fält (om det bara finns ett fält som anges i distinct()
). field_name
är som standard den primära nyckeln.
Exempel:
>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(["beatles_blog"], field_name="slug")
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct("name").in_bulk(field_name="name")
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}
Om du skickar en tom lista till in_bulk()
får du en tom ordbok.
iterator()`
¶
- iterator(chunk_size=None)¶
- aiterator(chunk_size=None)¶
Asynkron version: aiterator()
Utvärderar QuerySet
(genom att utföra frågan) och returnerar en iterator (se :pep:`234``) över resultaten, eller en asynkron iterator (se :pep:`492``) om du anropar dess asynkrona version aiterator
.
En QuerySet
cachelagrar vanligtvis sina resultat internt så att upprepade utvärderingar inte resulterar i ytterligare förfrågningar. Däremot kommer iterator()
att läsa resultaten direkt, utan att göra någon cachelagring på QuerySet
-nivå (internt anropar standarditeratorn iterator()
och cachelagrar returvärdet). För en QuerySet
som returnerar ett stort antal objekt som du bara behöver komma åt en gång, kan detta resultera i bättre prestanda och en betydande minskning av minnet.
Observera att om du använder iterator()
på en QuerySet
som redan har utvärderats, tvingas den att utvärderas igen, vilket innebär att frågan upprepas.
iterator()
är kompatibel med tidigare anrop till prefetch_related()
så länge som chunk_size
anges. Större värden kräver färre frågor för att åstadkomma prefetching till priset av större minnesanvändning.
I vissa databaser (t.ex. Oracle, SQLite) kan det maximala antalet termer i en SQL IN
-klausul vara begränsat. Därför bör värden under denna gräns användas. (I synnerhet vid prefetching över två eller flera relationer bör en chunk_size
vara tillräckligt liten för att det förväntade antalet resultat för varje prefetched relation fortfarande faller under gränsen)
Så länge QuerySet inte hämtar några relaterade objekt i förväg, kommer Django att använda en implicit standard på 2000 om man inte anger något värde för chunk_size
.
Beroende på databasens backend kommer sökresultaten antingen att laddas på en gång eller strömmas från databasen med hjälp av cursorer på serversidan.
Med markörer på serversidan¶
Oracle och PostgreSQL använder markörer på serversidan för att strömma resultat från databasen utan att ladda hela resultatuppsättningen i minnet.
Oracle-databasdrivrutinen använder alltid markörer på serversidan.
Med markörer på serversidan anger parametern chunk_size
antalet resultat som ska cachas på databasdrivrutinsnivå. Genom att hämta större bitar minskas antalet rundresor mellan databasdrivrutinen och databasen, men det kostar minne.
På PostgreSQL kommer markörer på serversidan endast att användas när inställningen DISABLE_SERVER_SIDE_CURSORS <DATABASE-DISABLE_SERVER_SIDE_CURSORS>`
är False
. Läs Transaktionspoolning och cursorer på serversidan om du använder en anslutningspooler som är konfigurerad i transaktionspoolningsläge. När markörer på serversidan är inaktiverade är beteendet detsamma som i databaser som inte stöder markörer på serversidan.
Utan markörer på serversidan¶
MySQL stöder inte strömmande resultat, och därför laddar Python-databasdrivrutinen hela resultatuppsättningen i minnet. Resultatuppsättningen omvandlas sedan till Python-radobjekt av databasadaptern med hjälp av metoden fetchmany()
som definieras i PEP 249.
SQLite kan hämta resultat i satser med fetchmany()
, men eftersom SQLite inte tillhandahåller isolering mellan frågor inom en anslutning måste du vara försiktig när du skriver till den tabell som itereras över. Se Isolering vid användning av QuerySet.iterator() för mer information.
Parametern chunk_size
styr storleken på de batcher som Django hämtar från databasdrivrutinen. Större satser minskar omkostnaderna för att kommunicera med databasdrivrutinen på bekostnad av en liten ökning av minnesförbrukningen.
Så länge som QuerySet inte hämtar några relaterade objekt, kommer inget värde för chunk_size
att resultera i att Django använder en implicit standard på 2000, ett värde som härrör från en beräkning på psycopg-postlistan:
Om vi antar att raderna består av 10-20 kolumner med en blandning av text och numeriska data kommer 2000 att hämta mindre än 100 kB data, vilket verkar vara en bra kompromiss mellan antalet rader som överförs och den data som kasseras om loopen avslutas tidigt.
nyaste()
¶
- latest(*fields)¶
- alatest(*fields)¶
Asynkron version: alatest()
Returnerar det senaste objektet i tabellen baserat på det eller de fält som anges.
I detta exempel returneras det senaste Entry
i tabellen, enligt fältet pub_date
:
Entry.objects.latest("pub_date")
Du kan också välja den senaste baserat på flera fält. Till exempel:, för att välja den Entry
med det tidigaste expire_date
när två poster har samma pub_date
:
Entry.objects.latest("pub_date", "-expire_date")
Det negativa tecknet i '-expire_date'
betyder att expire_date
ska sorteras i fallande ordning. Eftersom latest()
får det sista resultatet, väljs det Entry
som har det tidigaste expire_date
.
Om din modells Meta specificerar get_latest_by
, kan du utelämna alla argument till earliest()
eller latest()
. De fält som anges i get_latest_by
kommer att användas som standard.
Liksom get()
, ger earliest()
och latest()
DoesNotExist
om det inte finns något objekt med de angivna parametrarna.
Observera att earliest()
och latest()
endast finns för bekvämlighetens och läsbarhetens skull.
earliest()
och latest()
kan returnera instanser med null-datum.
Eftersom beställningen delegeras till databasen kan resultat på fält som tillåter nollvärden beställas på olika sätt om du använder olika databaser. Till exempel: sorterar PostgreSQL och MySQL null-värden som om de är högre än icke-null-värden, medan SQLite gör motsatsen.
Du kanske vill filtrera bort nollvärden:
Entry.objects.filter(pub_date__isnull=False).latest("pub_date")
tidigaste()`
¶
- earliest(*fields)¶
- aearliest(*fields)¶
Asynkron version: aearliest()
Fungerar annars som latest()
förutom att riktningen är ändrad.
första()
¶
- first()¶
- afirst()¶
Asynkron version: afirst()
Returnerar det första objektet som matchas av queryset, eller None
om det inte finns något matchande objekt. Om QuerySet
inte har någon definierad ordning, ordnas frågeuppsättningen automatiskt efter primärnyckeln. Detta kan påverka aggregeringsresultat enligt beskrivningen i Interaktion med order_by().
Exempel:
p = Article.objects.order_by("title", "pub_date").first()
Observera att first()
är en bekvämlighetsmetod, följande kodprov är likvärdigt med ovanstående exempel:
try:
p = Article.objects.order_by("title", "pub_date")[0]
except IndexError:
p = None
slut()`
¶
- last()¶
- alast()¶
Asynkron version: alast()
Fungerar som first()
, men returnerar det sista objektet i frågeuppsättningen.
aggregat()`
¶
- aggregate(*args, **kwargs)¶
- aaggregate(*args, **kwargs)¶
Asynkron version: aaggregate()
Returnerar en ordbok med aggregerade värden (medelvärden, summor etc.) som beräknats över QuerySet
. Varje argument till aggregate()
anger ett värde som ska ingå i den ordbok som returneras.
De aggregeringsfunktioner som tillhandahålls av Django beskrivs i Aggregeringsfunktioner nedan. Eftersom aggregat också är query expressions, kan du kombinera aggregat med andra aggregat eller värden för att skapa komplexa aggregat.
Aggregat som anges med nyckelordsargument kommer att använda nyckelordet som namn på annoteringen. För anonyma argument genereras ett namn som baseras på namnet på aggregatfunktionen och det modellfält som aggregeras. Komplexa aggregat kan inte använda anonyma argument utan måste ange ett nyckelordsargument som alias.
Om du t.ex. arbetar med blogginlägg kanske du vill veta hur många författare som har skrivit blogginlägg:
>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry__authors"))
{'entry__authors__count': 16}
Genom att använda ett nyckelordsargument för att ange aggregeringsfunktionen kan du styra namnet på det aggregeringsvärde som returneras:
>>> Blog.objects.aggregate(number_of_authors=Count("entry__authors"))
{'number_of_authors': 16}
För en djupgående diskussion om aggregering, se the topic guide on Aggregation.
existerar()`
¶
- exists()¶
- aexists()¶
Asynkron version: aexists()
Returnerar True
om QuerySet
innehåller några resultat, och False
om inte. Detta försöker utföra frågan på enklast och snabbast möjliga sätt, men det kör nästan samma fråga som en normal QuerySet
-fråga.
exists()
är användbart för sökningar som gäller förekomsten av objekt i en QuerySet
, särskilt i samband med en stor QuerySet
.
För att ta reda på om en frågeuppsättning innehåller några objekt:
if some_queryset.exists():
print("There is at least one object in some_queryset")
Vilket kommer att vara snabbare än:
if some_queryset:
print("There is at least one object in some_queryset")
… men inte i någon större utsträckning (vilket innebär att det krävs en stor frågeuppsättning för effektivitetsvinster).
Dessutom, om en some_queryset
ännu inte har utvärderats, men du vet att den kommer att göra det någon gång, kommer det att göra mer totalt arbete att använda some_queryset.exists()
(en fråga för existenskontrollen plus en extra för att senare hämta resultaten) än att använda bool(some_queryset)
, som hämtar resultaten och sedan kontrollerar om några returnerades.
innehåller()`
¶
- contains(obj)¶
- acontains(obj)¶
Asynkron version: acontains()
Returnerar True
om QuerySet
innehåller obj
, och False
om inte. Detta försöker utföra frågan på det enklaste och snabbaste sättet som möjligt.
contains()
är användbart för att kontrollera ett objekts medlemskap i en QuerySet
, särskilt i samband med en stor QuerySet
.
För att kontrollera om en frågeuppsättning innehåller ett visst objekt:
if some_queryset.contains(obj):
print("Entry contained in queryset")
Detta går snabbare än följande, som kräver utvärdering och iteration genom hela frågeuppsättningen:
if obj in some_queryset:
print("Entry contained in queryset")
Precis som exists()
, om some_queryset
ännu inte har utvärderats, men du vet att det kommer att utvärderas någon gång, kommer användningen av some_queryset.contains(obj)
att göra en ytterligare databasförfrågan, vilket i allmänhet resulterar i långsammare prestanda.
uppdatera()
¶
- update(**kwargs)¶
- aupdate(**kwargs)¶
Asynkron version: aupdate()
Utför en SQL-uppdateringsfråga för de angivna fälten och returnerar antalet matchade rader (som kanske inte är lika med antalet uppdaterade rader om vissa rader redan har det nya värdet).
Om du t.ex. vill stänga av kommentarer för alla blogginlägg som publicerades 2010 kan du göra så här:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(Detta förutsätter att din Entry
-modell har fälten pub_date
och comments_on
)
Du kan uppdatera flera fält - det finns ingen begränsning för hur många. Här uppdaterar vi till exempel fälten comments_on
och headline
:
>>> Entry.objects.filter(pub_date__year=2010).update(
... comments_on=False, headline="This is old"
... )
Metoden update()
tillämpas direkt, och den enda begränsningen för QuerySet
som uppdateras är att den bara kan uppdatera kolumner i modellens huvudtabell, inte i relaterade modeller. Du kan till exempel inte göra så här:
>>> Entry.objects.update(blog__name="foo") # Won't work!
Det är dock fortfarande möjligt att filtrera baserat på relaterade fält:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
Du kan inte anropa update()
på en QuerySet
som har fått en slice tagen eller på annat sätt inte längre kan filtreras.
Metoden update()
returnerar antalet berörda rader:
>>> Entry.objects.filter(id=64).update(comments_on=True)
1
>>> Entry.objects.filter(slug="nonexistent-slug").update(comments_on=True)
0
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132
Om du bara uppdaterar en post och inte behöver göra något med modellobjektet är det effektivaste sättet att anropa update()
i stället för att ladda modellobjektet i minnet. Till exempel:, istället för att göra så här:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
…gör så här:
Entry.objects.filter(id=10).update(comments_on=False)
Genom att använda update()
förhindras också ett tävlingsförhållande där något kan ändras i din databas under den korta tidsperioden mellan laddning av objektet och anrop av save()
.
MySQL stöder inte självvalda uppdateringar
På MySQL kan QuerySet.update()
exekvera en SELECT
följt av en UPDATE
istället för en enda UPDATE
vid filtrering på relaterade tabeller, vilket kan införa ett tävlingsvillkor om samtidiga ändringar sker mellan frågorna. För att säkerställa atomicitet bör du överväga att använda transaktioner eller undvika sådana filtervillkor på MySQL.
Slutligen måste du inse att update()
gör en uppdatering på SQL-nivå och därmed inte anropar några save()
-metoder på dina modeller, och inte heller avger pre_save
eller post_save
-signalerna (som är en följd av att anropa Model.save()
). Om du vill uppdatera ett gäng poster för en modell som har en anpassad save()
-metod, loopa över dem och anropa save()
, så här:
for e in Entry.objects.filter(pub_date__year=2010):
e.comments_on = False
e.save()
Beställd queryset¶
Att kedja order_by()
med update()
stöds endast av MariaDB och MySQL, och ignoreras för andra databaser. Detta är användbart för att uppdatera ett unikt fält i den ordning som anges utan konflikter. Till exempel:
Entry.objects.order_by("-number").update(number=F("number") + 1)
Observera
order_by()
-satsen ignoreras om den innehåller annoteringar, ärvda fält eller uppslagningar som sträcker sig över relationer.
delete()`
¶
- delete()¶
- adelete()¶
Asynkron version: adelete()
Utför en SQL-borttagningsfråga på alla rader i QuerySet
och returnerar antalet borttagna objekt och en ordbok med antalet borttagningar per objekttyp.
Delete()
tillämpas omedelbart. Du kan inte anropa delete()
på en QuerySet
som har fått en slice tagen eller på annat sätt inte längre kan filtreras.
Till exempel: för att radera alla inlägg i en viss blogg:
>>> b = Blog.objects.get(pk=1)
# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})
Som standard emulerar Djangos ForeignKey
SQL-begränsningen ON DELETE CASCADE
- med andra ord kommer alla objekt med utländska nycklar som pekar på de objekt som ska raderas att raderas tillsammans med dem. Till exempel:
>>> blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})
Detta kaskadbeteende kan anpassas via argumentet on_delete
till ForeignKey
.
Metoden delete()
gör en massradering och anropar inte några delete()
-metoder på dina modeller. Den sänder dock ut signalerna pre_delete
och post_delete
för alla raderade objekt (inklusive kaskadraderingar).
Django behöver hämta objekt i minnet för att skicka signaler och hantera kaskader. Men om det inte finns några kaskader och inga signaler, kan Django ta en snabb väg och radera objekt utan att hämta i minnet. För stora raderingar kan detta resultera i betydligt minskad minnesanvändning. Mängden exekverade frågor kan också minskas.
ForeignKeys som är inställda på on_delete
DO_NOTHING
förhindrar inte att man tar den snabba vägen vid radering.
Observera att de frågor som genereras vid borttagning av objekt är en implementeringsdetalj som kan komma att ändras.
as_manager()`
¶
- classmethod as_manager()¶
Klassmetod som returnerar en instans av Manager
med en kopia av QuerySet
’s metoder. Se Skapa en manager med QuerySet-metoder för mer information.
Observera att till skillnad från de andra posterna i detta avsnitt har denna inte en asynkron variant eftersom den inte exekverar en fråga.
explain()
¶
- explain(format=None, **options)¶
- aexplain(format=None, **options)¶
Asynkron version: aexplain()
Returnerar en sträng av QuerySet
:s exekveringsplan, som innehåller information om hur databasen skulle exekvera frågan, inklusive eventuella index eller sammanfogningar som skulle användas. Om du känner till dessa detaljer kan det hjälpa dig att förbättra prestanda för långsamma frågor.
Till exempel: när du använder PostgreSQL:
>>> print(Blog.objects.filter(title="My Blog").explain())
Seq Scan on blog (cost=0.00..35.50 rows=10 width=12)
Filter: (title = 'My Blog'::bpchar)
Utdata skiljer sig avsevärt mellan olika databaser.
explain()
stöds av alla inbyggda databasbackends utom Oracle eftersom en implementering där inte är okomplicerad.
Parametern `` format`` ändrar utdataformatet från databasens standard, som vanligtvis är textbaserat. PostgreSQL stöder formaten 'TEXT'
, 'JSON'
, 'YAML'
och 'XML'
. MariaDB och MySQL stöder formaten 'TEXT'
(även kallat 'TRADITIONAL'
) och 'JSON'
. MySQL 8.0.16+ stöder också ett förbättrat 'TREE'
-format, som liknar PostgreSQL: s 'TEXT'
-utgång och används som standard, om det stöds.
Vissa databaser accepterar flaggor som kan ge mer information om frågan. Skicka dessa flaggor som nyckelordsargument. Till exempel: när du använder PostgreSQL:
>>> print(Blog.objects.filter(title="My Blog").explain(verbose=True, analyze=True))
Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
Output: id, title
Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms
På vissa databaser kan flaggor orsaka att frågan körs, vilket kan ha negativa effekter på din databas. Till exempel: kan flaggan ANALYZE
som stöds av MariaDB, MySQL 8.0.18+ och PostgreSQL resultera i ändringar av data om det finns triggers eller om en funktion anropas, även för en SELECT
-fråga.
Stöd för alternativet `` generic_plan`` på PostgreSQL 16+ lades till.
Stöd för alternativen `` minne`` och `` serialize`` på PostgreSQL 17+ lades till.
Field
uppslagningar¶
Fältuppslagningar är hur du specificerar innehållet i en SQL WHERE
klausul. De anges som nyckelordsargument till QuerySet
-metoderna filter()
, exclude()
och get()
.
För en introduktion, se dokumentation om modeller och databasfrågor.
Djangos inbyggda lookups listas nedan. Det är också möjligt att skriva custom lookups för modellfält.
Som en bekvämlighet när ingen uppslagstyp anges (som i Entry.objects.get(id=14)
) antas uppslagstypen vara exact
.
exakt
¶
Exakt matchning. Om det värde som anges för jämförelse är None
tolkas det som en SQL NULL
(se isnull`
för mer information).
Exempel:
Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)
SQL-ekvivalenter:
SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;
Jämförelser med MySQL
I MySQL avgör en databastabells ”collation”-inställning om exakt
-jämförelser är skiftlägeskänsliga. Detta är en databasinställning, inte en Django-inställning. Det är möjligt att konfigurera dina MySQL-tabeller för att använda skiftlägeskänsliga jämförelser, men vissa kompromisser är inblandade. För mer information om detta, se collation section i databases dokumentation.
iexakt
¶
Exakt matchning utan skiftlägeskänslighet. Om det värde som anges för jämförelse är None
tolkas det som en SQL NULL
(se isnull`
för mer information).
Exempel:
Blog.objects.get(name__iexact="beatles blog")
Blog.objects.get(name__iexact=None)
SQL-ekvivalenter:
SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;
Observera att den första frågan kommer att matcha 'Beatles Blog'
, 'beatles blog'
, 'BeAtLes BLoG'
, etc.
SQLite-användare
När du använder SQLite-backend och icke-ASCII-strängar, tänk på :ref:databasanteckning <sqlite-string-matching>
om strängjämförelser. SQLite gör inte skiftlägesokänslig matchning för icke-ASCII-strängar.
innehåller
¶
Case-sensitive containment test.
Exempel:
Entry.objects.get(headline__contains="Lennon")
SQL-ekvivalent:
SELECT ... WHERE headline LIKE '%Lennon%';
Observera att detta kommer att matcha rubriken 'Lennon hedrad idag'
men inte 'lennon hedrad idag'
.
SQLite-användare
SQLite stöder inte skiftlägeskänsliga LIKE
-satser; contains
fungerar som icontains
för SQLite. Se :ref:``database note <sqlite-string-matching>` för mer information.
ikoner
¶
Case-insensitive containment test.
Exempel:
Entry.objects.get(headline__icontains="Lennon")
SQL-ekvivalent:
SELECT ... WHERE headline ILIKE '%Lennon%';
SQLite-användare
När du använder SQLite-backend och icke-ASCII-strängar, tänk på :ref:database note <sqlite-string-matching>
om strängjämförelser.
in
¶
I en given iterabel; ofta en lista, tupel eller queryset. Det är inte ett vanligt användningsfall, men strängar (som är iterabla) accepteras.
Exempel:
Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in="abc")
SQL-ekvivalenter:
SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');
Du kan också använda en queryset för att dynamiskt utvärdera listan med värden i stället för att tillhandahålla en lista med bokstavliga värden:
inner_qs = Blog.objects.filter(name__contains="Cheddar")
entries = Entry.objects.filter(blog__in=inner_qs)
Detta queryset kommer att utvärderas som ett subselect-svar:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
Om du skickar in en QuerySet
som är resultatet av values()
eller values_list()
som värde till en __in
lookup, måste du se till att du bara extraherar ett fält i resultatet. Det här fungerar till exempel (filtrering på bloggnamn):
inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Detta exempel kommer att leda till ett undantag, eftersom den inre frågan försöker extrahera två fältvärden, där endast ett förväntas:
# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)
Överväganden om prestanda
Var försiktig med att använda nästlade frågor och förstå din databasservers prestandaegenskaper (om du är osäker, jämför!). Vissa databasbackends, framför allt MySQL, optimerar inte nästlade frågor särskilt bra. I dessa fall är det mer effektivt att extrahera en lista med värden och sedan skicka den till den andra frågan. Det vill säga, kör två frågor istället för en:
values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Notera list()
-anropet runt bloggen QuerySet
för att tvinga fram körning av den första frågan. Utan det skulle en nästlad fråga exekveras, eftersom ”QuerySet”: ”De är lata.
gt
¶
Större än.
Exempel:
Entry.objects.filter(id__gt=4)
SQL-ekvivalent:
SELECT ... WHERE id > 4;
gte
¶
Större än eller lika med.
lt
¶
Mindre än.
lte
¶
Mindre än eller lika med.
börjar med
¶
Case-sensitive börjar med.
Exempel:
Entry.objects.filter(headline__startswith="Lennon")
SQL-ekvivalent:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite stöder inte skiftlägeskänsliga LIKE
-satser; startswith
fungerar som istartswith
för SQLite.
istartswith
¶
Case-insensitive börjar med.
Exempel:
Entry.objects.filter(headline__istartswith="Lennon")
SQL-ekvivalent:
SELECT ... WHERE headline ILIKE 'Lennon%';
SQLite-användare
När du använder SQLite-backend och icke-ASCII-strängar, tänk på :ref:database note <sqlite-string-matching>
om strängjämförelser.
slutar med
¶
Case-sensitive slutar med.
Exempel:
Entry.objects.filter(headline__endswith="Lennon")
SQL-ekvivalent:
SELECT ... WHERE headline LIKE '%Lennon';
SQLite-användare
SQLite stöder inte skiftlägeskänsliga LIKE
-satser; endswith
fungerar som iendswith
för SQLite. Se :ref:``database note <sqlite-string-matching>`-dokumentationen för mer information.
”i vänskap med¶
Case-insensitive slutar med.
Exempel:
Entry.objects.filter(headline__iendswith="Lennon")
SQL-ekvivalent:
SELECT ... WHERE headline ILIKE '%Lennon'
SQLite-användare
När du använder SQLite-backend och icke-ASCII-strängar, tänk på :ref:database note <sqlite-string-matching>
om strängjämförelser.
intervall
¶
Avståndstest (inklusive).
Exempel:
import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
SQL-ekvivalent:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
Du kan använda range
överallt där du kan använda BETWEEN
i SQL - för datum, siffror och till och med tecken.
Varning
Filtrering av en DateTimeField
med datum kommer inte att inkludera objekt på den sista dagen, eftersom gränserna tolkas som ”0am på det angivna datumet”. Om pub_date
var en DateTimeField
skulle ovanstående uttryck omvandlas till denna SQL:
SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';
Generellt sett kan du inte blanda datum och datumtider.
datum
¶
För datetime-fält kastas värdet som datum. Tillåter kedjning av ytterligare fältuppslagningar. Tar emot ett datumvärde.
Exempel:
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
(Inget motsvarande SQL-kodfragment ingår för den här sökningen eftersom implementeringen av den relevanta frågan varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras fält till aktuell tidszon före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
år
¶
För datum- och datetime-fält, en exakt matchning av år. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltalsår.
Exempel:
Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)
SQL-ekvivalent:
SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
iso_year
¶
För datum- och datetime-fält, en exakt matchning av ISO 8601 veckonummer och år. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltalsår.
Exempel:
Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
månad
¶
För datum- och datetime-fält, en exakt matchning av månaden. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltal från 1 (januari) till 12 (december).
Exempel:
Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)
SQL-ekvivalent:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
dag
¶
För datum- och datetime-fält, en exakt matchning av dagen. Tillåter kedjning av ytterligare fältuppslagningar. Tar en heltalsdag.
Exempel:
Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)
SQL-ekvivalent:
SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
Observera att detta kommer att matcha alla poster med ett pub_date på den tredje dagen i månaden, t.ex. 3 januari, 3 juli etc.
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
vecka
¶
För datum- och datetime-fält returneras veckonumret (1-52 eller 53) enligt ISO-8601, dvs. veckorna börjar på en måndag och den första veckan innehåller årets första torsdag.
Exempel:
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(Inget motsvarande SQL-kodfragment ingår för den här sökningen eftersom implementeringen av den relevanta frågan varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
veckodag
¶
För datum- och datetime-fält, en matchning av ”veckodag”. Tillåter kedjning av ytterligare fältuppslagningar.
Tar ett heltalsvärde som representerar veckodagen från 1 (söndag) till 7 (lördag).
Exempel:
Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)
(Inget motsvarande SQL-kodfragment ingår för den här sökningen eftersom implementeringen av den relevanta frågan varierar mellan olika databasmotorer)
Observera att detta kommer att matcha alla poster med ett pub_date
som infaller på en måndag (dag 2 i veckan), oavsett vilken månad eller vilket år det inträffar. Veckodagar är indexerade så att dag 1 är söndag och dag 7 är lördag.
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
iso_week_day
¶
För datum- och datetime-fält, en exakt matchning av veckodag enligt ISO 8601. Tillåter kedjning av ytterligare fältuppslagningar.
Tar ett heltalsvärde som representerar veckodagen från 1 (måndag) till 7 (söndag).
Exempel:
Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)
(Inget motsvarande SQL-kodfragment ingår för den här sökningen eftersom implementeringen av den relevanta frågan varierar mellan olika databasmotorer)
Observera att detta kommer att matcha alla poster med ett pub_date
som infaller på en måndag (dag 1 i veckan), oavsett vilken månad eller vilket år det inträffar. Veckodagar är indexerade så att dag 1 är måndag och dag 7 är söndag.
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
kvartal
¶
För datum- och datetime-fält, en matchning av ”kvartal i året”. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltalsvärde mellan 1 och 4 som representerar kvartalet i året.
Exempel för att hämta poster under andra kvartalet (1 april till 30 juni):
Entry.objects.filter(pub_date__quarter=2)
(Inget motsvarande SQL-kodfragment ingår för den här sökningen eftersom implementeringen av den relevanta frågan varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
tid
¶
För datetime-fält kastas värdet som tid. Tillåter kedjning av ytterligare fältuppslagningar. Tar emot ett värde av datetime.time
.
Exempel:
Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))
(Inget motsvarande SQL-kodfragment ingår för den här sökningen eftersom implementeringen av den relevanta frågan varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras fält till aktuell tidszon före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
timme
¶
För datetime- och time-fält, en exakt matchning av timmar. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltal mellan 0 och 23.
Exempel:
Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)
SQL-ekvivalent:
SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
minut
¶
För datetime- och time-fält, en exakt minutmatchning. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltal mellan 0 och 59.
Exempel:
Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)
SQL-ekvivalent:
SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
sekund
¶
För datetime- och time-fält, en exakt andra matchning. Tillåter kedjning av ytterligare fältuppslagningar. Tar ett heltal mellan 0 och 59.
Exempel:
Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)
SQL-ekvivalent:
SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';
(Den exakta SQL-syntaxen varierar mellan olika databasmotorer)
När USE_TZ
är True
konverteras datetime-fält till den aktuella tidszonen före filtrering. Detta kräver :ref:tidszonsdefinitioner i databasen <database-time-zone-definitions>
.
isnull
¶
Tar antingen True
eller False
, vilket motsvarar SQL-frågorna IS NULL
respektive IS NOT NULL
.
Exempel:
Entry.objects.filter(pub_date__isnull=True)
SQL-ekvivalent:
SELECT ... WHERE pub_date IS NULL;
regex
¶
Skiftlägeskänslig matchning med reguljärt uttryck.
Syntaxen för reguljära uttryck är den som används i databasens backend. När det gäller SQLite, som inte har något inbyggt stöd för reguljära uttryck, tillhandahålls denna funktion av en (Python) användardefinierad REGEXP-funktion, och syntaxen för reguljära uttryck är därför den som används i Pythons modul re
.
Exempel:
Entry.objects.get(title__regex=r"^(An?|The) +")
SQL-ekvivalenter:
SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL
SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle
SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
Det rekommenderas att använda råa strängar (t.ex. r'foo'
i stället för 'foo'
) för att skicka in syntaxen för reguljära uttryck.
iregex
¶
Matchning av reguljära uttryck utan skiftlägeskänslighet.
Exempel:
Entry.objects.get(title__iregex=r"^(an?|the) +")
SQL-ekvivalenter:
SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL
SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle
SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL
SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Aggregeringsfunktioner¶
Django tillhandahåller följande aggregeringsfunktioner i modulen django.db.models
. För detaljer om hur du använder dessa aggregeringsfunktioner, se :doc:``ämnesguiden om aggregering </topics/db/aggregation>`. Se Aggregate
-dokumentationen för att lära dig hur du skapar dina aggregat.
Varning
SQLite kan inte hantera aggregering på datum/tid-fält direkt från start. Detta beror på att det inte finns några inbyggda datum/tid-fält i SQLite och Django emulerar för närvarande dessa funktioner med hjälp av ett textfält. Försök att använda aggregering på datum/tid-fält i SQLite kommer att ge upphov till NotSupportedError
.
Tomma querysets eller grupper
Aggregeringsfunktioner returnerar None
när de används med ett tomt QuerySet
eller en tom grupp. Aggregeringsfunktionen Sum
returnerar t.ex. None
istället för 0
om QuerySet
inte innehåller några poster eller för en tom grupp i ett icke-tomt QuerySet
. För att returnera ett annat värde istället, definiera argumentet default
. Count
är ett undantag från detta beteende; det returnerar 0
om QuerySet
är tomt eftersom Count
inte stöder default
argumentet.
Alla aggregat har följande parametrar gemensamt:
uttryck
¶
Strängar som refererar till fält i modellen, transformationer av fältet eller :doc:``frågeuttryck </ref/models/expressions>`.
utgångsfält
¶
Ett valfritt argument som representerar modellfältet i returvärdet
Observera
När du kombinerar flera fälttyper kan Django bara bestämma output_field
om alla fält är av samma typ. I annat fall måste du själv tillhandahålla output_field
.
filter
¶
Ett valfritt Q-objekt
som används för att filtrera de rader som aggregeras.
Se Villkorlig aggregering och Filtrering av anteckningar för exempel på användning.
standard
¶
Ett valfritt argument som gör det möjligt att ange ett värde som ska användas som standardvärde när frågeuppsättningen (eller grupperingen) inte innehåller några poster.
**extra
¶
Nyckelord som kan ge extra kontext för den SQL som genereras av aggregatet.
Avg
¶
- class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[source]¶
Returnerar medelvärdet av det angivna uttrycket, som måste vara numeriskt om du inte anger ett annat
output_field
.Standardalias:
<field>__avg
Typ av retur:
float
om indata ärint
, annars samma som indatafältet, elleroutput_field
om det anges. Om queryset eller grupperingen är tom returnerasdefault
.
- distinct¶
Valfritt. Om
distinct=True
returnerarAvg
medelvärdet av unika värden. Detta är SQL-ekvivalenten tillAVG(DISTINCT <field>)
. Standardvärdet ärFalse
.
Count
¶
- class Count(expression, distinct=False, filter=None, **extra)[source]¶
Returnerar antalet objekt som är relaterade med hjälp av det angivna uttrycket.
Count('*')
är likvärdigt med SQL-uttrycketCOUNT(*)
.Standardalias:
<field>__count
Typ av retur:
int
- distinct¶
Valfritt. Om
distinct=True
, kommer räkningen endast att omfatta unika instanser. Detta är SQL-ekvivalenten tillCOUNT(DISTINCT <field>)
. Standardvärdet ärFalse
.
Observera
Argumentet
default
stöds inte.
Max
¶
- class Max(expression, output_field=None, filter=None, default=None, **extra)[source]¶
Returnerar det maximala värdet för det angivna uttrycket.
Standardalias:
<field>__max
Typ av retur: samma som input-fältet, eller
output_field
om det anges. Om queryset eller grupperingen är tom returnerasdefault
.
Min
¶
StdDev
¶
- class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)[source]¶
Returnerar standardavvikelsen för data i det angivna uttrycket.
Standardalias:
<field>__stddev`
Typ av retur:
float
om indata ärint
, annars samma som indatafältet, elleroutput_field
om det anges. Om queryset eller grupperingen är tom returnerasdefault
.
- sample¶
Valfritt. Som standard returnerar
StdDev
populationens standardavvikelse. Men omsample=True
, kommer returvärdet att vara standardavvikelsen för urvalet.
Summa
¶
- class Sum(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[source]¶
Beräknar summan av alla värden för det angivna uttrycket.
Standardalias:
<field>__sum
Typ av retur: samma som input-fältet, eller
output_field
om det anges. Om queryset eller grupperingen är tom returnerasdefault
.
- distinct¶
Valfritt. Om
distinct=True
returnerarSum
summan av unika värden. Detta är SQL-ekvivalenten tillSUM(DISTINCT <field>)
. Standardvärdet ärFalse
.
Varians
¶
- class Variance(expression, output_field=None, sample=False, filter=None, default=None, **extra)[source]¶
Returnerar variansen för data i det angivna uttrycket.
Standardalias:
<field>__variance
Typ av retur:
float
om indata ärint
, annars samma som indatafältet, elleroutput_field
om det anges. Om queryset eller grupperingen är tom returnerasdefault
.
- sample¶
Valfritt. Som standard returnerar
Variance
populationsvariansen. Men omsample=True
kommer returvärdet att vara urvalsvariansen.