2016-07-07 43 views
5

Sono in procinto di aggiornare il mio progetto da Django 1.8.2 a 1.9.7 e sto ottenendo questo avvertimento:Django: timezone.now vs timezone.now()

WARNINGS: 
my_app.my_model.date_available: (fields.W161) Fixed default value provided. 
HINT: It seems you set a fixed date/time/datetime value as default for this field. This may not be what you want. 
If you want to have the current date as default, use `django.utils.timezone.now 

Ecco la linea da my_app/models.py:

from django.utils import timezone 
... 
class my_model(models.Model): 
    ... 
    datetime_released = models.DateTimeField(default=timezone.now()) 

Se rimuovo le parentesi e di utilizzare invece:

datetime_released = models.DateTimeField(default=timezone.now) 

L'avvertimento Django va via. Qual è la differenza tra i due?


In un'altra zona del mio progetto sto usando timezone.now() in un filtro set di query:

def date_available(self): 
     return self.filter(date_available__lte = timezone.now()) 

Qui, se tolgo le parentesi, viene generato un errore:

TypeError: expected string or buffer


posso ottenere entrambi questi due lavorano con l'aggiunta/rimozione la parentesi come richiedono d, ma qual è la differenza tra timezone.now() e timezone.now e perché causano avvertimenti/errori in questi casi?

+0

type (now()) consente di rieseguire un oggetto datetime. type (now) ripete ora il metodo – gtalarico

risposta

9

In python tutto è un oggetto, comprese le funzioni.Ciò significa che è possibile influenzare una funzione a una variabile:

>>> from django.utils import timezone 
>>> foo = timezone.now 
>>> foo 
<function django.utils.timezone.now> 
>>> foo() 
datetime.datetime(2016, 7, 7, 9, 11, 6, 489063) 

Una funzione è un oggetto invocabile:

>>> callable(foo) 
True 
>>> callable(foo()) 
False 

Quando default riceve un callable, il callable viene chiamato ogni volta che viene richiesto un valore predefinito.

D'altra parte, quando si chiama timezone.now() prima dell'impostazione di default, il valore viene assegnato e risolto. Come promemoria, la riga seguente viene eseguita una sola volta sul server di avvio, dal momento che è un attributo di classe:

datetime_released = models.DateTimeField(default=timezone.now()) 

e quindi timezone.now() viene eseguito solo una volta. Passare un callable timezone.now rende possibile ricalcolare il valore ogni volta che deve essere.

8

La differenza è che timezone.now è un callable che viene eseguito in fase di esecuzione, mentre timezone.now() restituisce l'output di tale funzione.

Per il models.DateTimeField, è necessario utilizzare il callable. Meglio ancora, è sufficiente impostare auto_now_add che fa questo per voi:

datetime_released = models.DateTimeField(auto_now_add=True) 

Il filtro d'altra parte non accetta un callable - si richiede un valore. Quindi è necessario valutare timezone.now() quando si passa questo argomento come argomento al filtro.

+0

La cosa che vale la pena menzionare qui è che quando si passa a 'timezone.now()', si sta effettivamente passando l'output di quella funzione nel momento in cui si avvia django (questo è quando diventa valutato), mentre quando passi 'timezone.now' stai passando l'oggetto funzione che viene pigramente valutato da django. – samu

1

now() viene eseguito quando il modello viene caricato e restituisce una stringa datetime object/time al momento del caricamento. (Da qui il Django avvertimento!) (Il file di modello se interamente eseguito all'avvio del server)

ora passerà sulla ormai metodo, e andranno eseguiti solo quando la classe/modello viene istanziato, creando il timestamp a il momento giusto (il modo corretto e ciò che la maggior parte delle persone sta cercando di ottenere).

Nell'esempio del filtro, viene chiamato solo quando viene chiamata la funzione filtro. se non eseguito (now()) e alimenterà il metodo e non genererà mai l'oggetto datetime richiesto. (errore, previsto una stringa, ottenuto, qualcos'altro)

1

In self.filter(date_available__lte = timezone.now()) si desidera eseguire una query sul database in base all'ora corrente. Quindi ne hai bisogno in formato stringa.

In datetime_released = models.DateTimeField(default=timezone.now) si desidera che il valore predefinito sia l'ora corrente. Quindi non puoi avere una stringa lì. Invece si fornisce una funzione che può restituire l'ora corrente.