Django
F () uttryck
Sök…
Introduktion
Ett F () -uttryck är ett sätt för Django att använda ett Python-objekt för att hänvisa till värdet på modellfältet eller den kommenterade kolumnen i databasen utan att behöva dra värdet till Python-minnet. Detta gör det möjligt för utvecklare att undvika vissa tävlingsförhållanden och även filtrera resultat baserat på modellfältvärden.
Syntax
- från django.db.models import F
Undvika rasförhållanden
Se denna fråga och fråga om du inte vet vad rasförhållandena är.
Följande kod kan vara föremål för tävlingsvillkor:
article = Article.objects.get(pk=69)
article.views_count += 1
article.save()
Om views_count
är lika med 1337
kommer detta att resultera i en sådan fråga:
UPDATE app_article SET views_count = 1338 WHERE id=69
Om två klienter har åtkomst till den här artikeln samtidigt, kan det hända att den andra HTTP-begäran kör Article.objects.get(pk=69)
innan den första kör article.save()
. Således kommer båda förfrågningarna att ha views_count = 1337
, öka det och spara views_count = 1338
i databasen, medan det faktiskt bör vara 1339
.
För att fixa detta använder du ett F()
-uttryck:
article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()
Detta kommer å andra sidan att resultera i en sådan fråga:
UPDATE app_article SET views_count = views_count + 1 WHERE id=69
Uppdaterar queryset i bulk
Låt oss anta att vi vill ta bort två kommentarer från alla författarens artiklar med id 51
.
Om du bara gör detta med Python skulle exekvera N
frågor ( N
är antalet artiklar i frågeställningen):
for article in Article.objects.filter(author_id=51):
article.upvotes -= 2
article.save()
# Note that there is a race condition here but this is not the focus
# of this example.
Vad händer om istället för att dra alla artiklarna i Python, slingra över dem, minska uppvotterna och spara varje uppdaterad tillbaka till databasen, fanns det ett annat sätt?
Med ett F()
-uttryck kan du göra det i en fråga:
Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)
Vilket kan översättas i följande SQL-fråga:
UPDATE app_article SET upvotes = upvotes - 2 WHERE author_id = 51
Varför är det bättre?
- Istället för att Python gör arbetet, överför vi lasten till databasen som är finjusterad för att göra sådana frågor.
- Minskar effektivt antalet databasfrågor som behövs för att uppnå det önskade resultatet.
Utför aritmetiska operationer mellan fält
F()
-uttryck kan användas för att utföra aritmetiska operationer ( +
, -
, *
etc.) bland modellfält för att definiera en algebraisk uppslag / anslutning mellan dem.
Låt modellen vara:
class MyModel(models.Model): int_1 = models.IntegerField() int_2 = models.IntegerField()
Låt oss nu anta att vi vill hämta alla objekt i
MyModel
tabellen som ärint_1
ochint_2
fält som uppfyller denna ekvation:int_1 + int_2 >= 5
. Genom att användaannotate()
ochfilter()
vi:result = MyModel.objects.annotate( diff=F(int_1) + F(int_2) ).filter(diff__gte=5)
result
innehåller nu alla ovannämnda objekt.
Även om exemplet använder Integer
, kommer den här metoden att fungera på alla fält på vilka en aritmetisk operation kan tillämpas.