Django
F () Ausdrücke
Suche…
Einführung
Mit einem F () - Ausdruck kann Django mithilfe eines Python-Objekts auf den Wert des Modellfelds oder der kommentierten Spalte in der Datenbank verweisen, ohne den Wert in den Python-Speicher ziehen zu müssen. Dadurch können Entwickler bestimmte Race-Bedingungen vermeiden und Ergebnisse basierend auf Modellfeldwerten filtern.
Syntax
- von django.db.models importieren F
Rennbedingungen vermeiden
Sehen Sie sich diese Q & A-Frage an, wenn Sie nicht wissen, welche Wettlaufbedingungen gelten.
Der folgende Code kann Rennbedingungen unterliegen:
article = Article.objects.get(pk=69)
article.views_count += 1
article.save()
Wenn views_count
gleich 1337
, führt dies zu einer solchen Abfrage:
UPDATE app_article SET views_count = 1338 WHERE id=69
Wenn zwei Clients gleichzeitig auf diesen Artikel zugreifen, kann es passieren, dass die zweite HTTP-Anforderung Article.objects.get(pk=69)
ausführt, bevor die erste article.save()
. Daher haben beide Anforderungen views_count = 1337
, views_count = 1337
sie und speichern views_count = 1338
in der Datenbank, während es eigentlich 1339
.
Um dies zu beheben, verwenden Sie einen F()
Ausdruck:
article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()
Dies führt andererseits zu einer solchen Abfrage:
UPDATE app_article SET views_count = views_count + 1 WHERE id=69
Abfrageset in großen Mengen aktualisieren
Nehmen wir an, wir wollen mit der ID 51
aus allen Artikeln des Autors 2 Upvotes entfernen.
Wenn Sie dies nur mit Python tun, werden N
Abfragen ausgeführt ( N
ist die Anzahl der Artikel im Abfrageset):
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.
Was wäre, wenn anstatt alle Artikel in Python zu ziehen, über sie hinweg zu schleifen, die Upvotes zu verringern und jeden aktualisierten Artikel in der Datenbank zu speichern, es einen anderen Weg gab?
Mit einem F()
Ausdruck können Sie dies in einer Abfrage tun:
Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)
Was kann in der folgenden SQL-Abfrage übersetzt werden:
UPDATE app_article SET upvotes = upvotes - 2 WHERE author_id = 51
Warum ist das besser?
- Anstatt Python die Arbeit zu erledigen, übergeben wir die Last in die Datenbank, die für solche Abfragen fein abgestimmt ist.
- Reduziert effektiv die Anzahl der Datenbankabfragen, die zum Erreichen des gewünschten Ergebnisses erforderlich sind.
Arithmetische Operationen zwischen Feldern ausführen
F()
-Ausdrücke können verwendet werden, um arithmetische Operationen ( +
, -
, *
usw.) zwischen Modellfeldern auszuführen, um eine algebraische Suche / Verbindung zwischen ihnen zu definieren.
Das Modell sei:
class MyModel(models.Model): int_1 = models.IntegerField() int_2 = models.IntegerField()
MyModel
wir nun an, dass wir alle Objekte derMyModel
Tabelleint_1
int_2
Felderint_1
undint_2
dieser Gleichung entsprechen:int_1 + int_2 >= 5
. Mitannotate()
undfilter()
wir:result = MyModel.objects.annotate( diff=F(int_1) + F(int_2) ).filter(diff__gte=5)
result
enthält jetzt alle zuvor genannten Objekte.
Obwohl das Beispiel Integer
Felder verwendet, funktioniert diese Methode für jedes Feld, auf das eine arithmetische Operation angewendet werden kann.