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
MyModeltabellen som ärint_1ochint_2fä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)resultinnehå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.