Szukaj…


Wprowadzenie

Wyrażenie F () jest sposobem na użycie przez Django obiektu Python w celu odniesienia się do wartości pola modelu lub kolumny z adnotacjami w bazie danych bez konieczności pobierania wartości do pamięci Python. Dzięki temu programiści mogą unikać określonych warunków wyścigu, a także filtrować wyniki na podstawie wartości pola modelu.

Składnia

  • z importu django.db.models F

Unikanie warunków wyścigu

Zobacz to pytanie, jeśli nie wiesz, jakie są warunki wyścigu.

Poniższy kod może podlegać warunkom wyścigu:

article = Article.objects.get(pk=69)
article.views_count += 1
article.save()

Jeśli liczba views_count jest równa 1337 , spowoduje to takie zapytanie:

UPDATE app_article SET views_count = 1338 WHERE id=69

Jeśli dwóch klientów uzyskuje dostęp do tego artykułu w tym samym czasie, może się zdarzyć, że drugie żądanie HTTP wykona Article.objects.get(pk=69) przed pierwszym uruchomieniem article.save() . Zatem oba żądania będą miały wartość views_count = 1337 , views_count = 1337 ją i views_count = 1338 w bazie danych, podczas gdy faktycznie powinna to być 1339 .

Aby to naprawić, użyj wyrażenia F() :

article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()

To z kolei spowoduje takie zapytanie:

UPDATE app_article SET views_count = views_count + 1 WHERE id=69

Zbiorcza aktualizacja zestawu zapytań

Załóżmy, że chcemy usunąć 2 głosy poparcia ze wszystkich artykułów autora o id 51 .
Wykonanie tego tylko przy użyciu Pythona spowodowałoby wykonanie N zapytań ( N oznacza liczbę artykułów w zestawie zapytań):

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.

Co jeśli zamiast wciągania wszystkich artykułów do Pythona, zapętlania ich, zmniejszania głosów pozytywnych i zapisywania każdego zaktualizowanego z powrotem do bazy danych, istnieje inny sposób?
Używając wyrażenia F() , możesz to zrobić w jednym zapytaniu:

Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)

Które można przetłumaczyć w następującym zapytaniu SQL:

UPDATE app_article SET upvotes = upvotes - 2 WHERE author_id = 51

Dlaczego to jest lepsze?

  • Zamiast wykonywać pracę w Pythonie, przekazujemy obciążenie do bazy danych, która jest dostosowana do wykonywania takich zapytań.
  • Skutecznie zmniejsza liczbę zapytań do bazy danych potrzebnych do osiągnięcia pożądanego rezultatu.

Wykonuj operacje arytmetyczne między polami

F() można używać do wykonywania operacji arytmetycznych ( + , - , * itd.) Między polami modelu, w celu zdefiniowania wyszukiwania algebraicznego / połączenia między nimi.

  • Niech model będzie:

    class MyModel(models.Model):
        int_1 = models.IntegerField()
        int_2 = models.IntegerField()
    
  • Załóżmy teraz, że chcemy pobrać wszystkie obiekty tabeli MyModel które są int_1 i int_2 spełniają to równanie: int_1 + int_2 >= 5 . Używając annotate() i filter() otrzymujemy:

    result = MyModel.objects.annotate(
                 diff=F(int_1) + F(int_2)
             ).filter(diff__gte=5)
    

    result zawiera teraz wszystkie wyżej wymienione obiekty.

Chociaż w przykładzie wykorzystano pola Integer , ta metoda będzie działać na każdym polu, na którym można zastosować operację arytmetyczną.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow