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 är int_1 och int_2 fält som uppfyller denna ekvation: int_1 + int_2 >= 5 . Genom att använda annotate() och filter() 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.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow