Django
F () espressioni
Ricerca…
introduzione
Un'espressione F () è un modo per Django di utilizzare un oggetto Python per fare riferimento al valore del campo del modello o della colonna annotata nel database senza dover inserire il valore nella memoria di Python. Ciò consente agli sviluppatori di evitare determinate condizioni di gara e di filtrare i risultati in base ai valori del campo del modello.
Sintassi
- da django.db.models import F
Evitare le condizioni di gara
Vedi questa domanda Q & A se non sai quali sono le condizioni di gara.
Il seguente codice può essere soggetto a condizioni di gara:
article = Article.objects.get(pk=69)
article.views_count += 1
article.save()
Se views_count
è uguale a 1337
, ciò comporterà una query di questo tipo:
UPDATE app_article SET views_count = 1338 WHERE id=69
Se due client accedono contemporaneamente a questo articolo, ciò che potrebbe accadere è che la seconda richiesta HTTP esegua Article.objects.get(pk=69)
prima che il primo esegua article.save()
. Pertanto, entrambe le richieste avranno views_count = 1337
, incrementarlo e salvare views_count = 1338
nel database, mentre in realtà dovrebbe essere 1339
.
Per risolvere questo problema, usa un'espressione F()
:
article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()
Questo, d'altra parte, si tradurrà in tale query:
UPDATE app_article SET views_count = views_count + 1 WHERE id=69
Aggiornamento di queryset in blocco
Supponiamo di voler rimuovere 2 upvotes da tutti gli articoli dell'autore con id 51
.
Farlo solo con Python eseguirà N
query ( N
è il numero di articoli nel queryset):
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.
Cosa succede se invece di trascinare tutti gli articoli in Python, passandoci sopra, diminuendo gli upvotes e salvando ogni aggiornato nel database, c'era un altro modo?
Usando un'espressione F()
, puoi farlo in una query:
Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)
Quale può essere tradotto nella seguente query SQL:
UPDATE app_article SET upvotes = upvotes - 2 WHERE author_id = 51
Perché è meglio?
- Invece di fare il lavoro in Python, passiamo il carico nel database che è messo a punto per fare queste domande.
- Riduce efficacemente il numero di query del database necessarie per ottenere il risultato desiderato.
Esegui operazioni aritmetiche tra i campi
F()
espressioni F()
possono essere utilizzate per eseguire operazioni aritmetiche ( +
, -
, *
ecc.) Tra i campi del modello, al fine di definire una ricerca / connessione algebrica tra di esse.
Lascia che il modello sia:
class MyModel(models.Model): int_1 = models.IntegerField() int_2 = models.IntegerField()
Ora lascia supporre che vogliamo recuperare tutti gli oggetti di
MyModel
tabella che diint_1
eint_2
campi soddisfano questa equazione:int_1 + int_2 >= 5
. Utilizzandoannotate()
efilter()
otteniamo:result = MyModel.objects.annotate( diff=F(int_1) + F(int_2) ).filter(diff__gte=5)
result
ora contiene tutti gli oggetti di cui sopra.
Sebbene l'esempio utilizzi i campi Integer
, questo metodo funzionerà su ogni campo in cui è possibile applicare un'operazione aritmetica.