2009-03-07 6 views
16

Ho una tabella con una IntegerField (hit_count), e quando una pagina viene visitata (ad esempio, http://site/page/3) voglio ID della hit_count colonna 3 della nella base di dati per incrementare di 1.Incremento Pagina Hit Count in Django

La query dovrebbe essere come:

update table set hit_count = hit_count + 1 where id = 3 

Posso fare questo con le convenzioni standard Django modello? O dovrei semplicemente scrivere la domanda a mano?

+0

È utile se si fornisce il modello stesso. –

+0

Eventuali duplicati di [incremento atomica di un contatore in Django] (http://stackoverflow.com/questions/1598932/atomic-increment-of-a-counter-in-django) –

risposta

31

Se si utilizza Django 1.1+, basta usare F expressions:

from django.db.models import F 
... 
MyModel.objects.filter(id=...).update(hit_count=F('hit_count')+1) 

Ciò eseguire una singola query di database atomica.

Come gerdemb dice, si dovrebbe valutare l'ipotesi di questo in un middleware per renderlo facilmente riutilizzabile in modo da non ingombrare il backup di tutti i vostri punti di vista.


+1

+1: http://docs.djopoproject.com/en/dev/topics/db/queries/#filters-can-reference-fields-on-the-model –

+0

Grazie - significava collegarlo ma dimenticato. Lo aggiungerò –

+1

Quello che penso tu voglia è 'MyModel.objects.get (id = ...)' al contrario di 'filter'; se sappiamo che è una singola riga, perché non chiarire? –

0

I modelli di convenzione non saranno atomica; scrivere a mano:

BEGIN 
SELECT * FROM table WHERE id=3 FOR UPDATE 
UPDATE table SET hit_count=hit_count+1 WHERE id=3 
COMMIT 
+1

ORM di Django ha il supporto per questa query (in trunk, e presto v1.1) - non è necessario scriverlo a mano. –

0

Vorrei iniziare a guardare la documentazione per middleware. Il commento di Ignacio sulla mancanza di transazioni atomiche è vero, ma questo è un problema con l'intera struttura di Django. A meno che tu non sia preoccupato di avere un contatore preciso al 100%, non mi preoccuperei di questo.

+0

In che modo si tratta di un "problema dell'intero framework Django?" È possibile avere una transazione atomica per richiesta con TransactionMiddleware oppure ottenere un controllo più dettagliato con le funzioni in django.db.transaction. –

+0

Sicuro di poter avere transazioni, ma non sono abilitate di default. Se costruisci una semplice applicazione CRUD usando l'admin integrato di Django, avrai delle condizioni di gara. Anche il tutorial nella documentazione di Django ha questo tipo di problemi. – user27478

+0

Il modo in cui hai formulato rende il suono come un problema inevitabile, che è ovviamente fuorviante a qualcuno che non può sapere tanto di Django come te. – Jordan

4

Come gerdemb dice, si dovrebbe scrivere in un middleware per renderlo veramente riutilizzabile. O (più semplice) scrivi un decoratore di funzioni. In effetti, ci sono adattatori per usare un middleware come decoratore e viceversa.

Ma se siete preoccupati per le prestazioni e si desidera mantenere le query DB per pagina colpito basso, è possibile utilizzare di operazione di incremento atomica memcached. ovviamente, in questo caso, devi prenderti cura della persistenza da solo.

+0

Per buone prestazioni, la soluzione memcached è di gran lunga migliore, ma è più complicata. –