2015-07-19 18 views
13

Così qualche tempo un paio di migrazioni dopo il mio primo, ho deciso che volevo includere questi campi:Migrazioni di Django 1.8. Aggiunta di DateTimeField dopo la creazione di db. Migliori pratiche?

created = models.DateTimeField(auto_now_add=True) 
modified = models.DateTimeField(auto_now=True) 

in uno dei miei modelli. Quando ho makemigrations che mi ha dato You are trying to add a non-nullable field 'created' to episode without a default; we can't do that (the database needs something to populate existing rows).

Così ho poi cambiato in

created = models.DateTimeField(auto_now_add=True, default=datetime.now) 

Dopo aver cercato di makemigrations ancora una volta, ha detto che at_api.Episode.modified: (fields.E160) The options auto_now, auto_now_add, and default are mutually exclusive. Only one of these options may be present.

Va bene, quindi ho solo andato avanti e ha rimosso il auto_now_add

created = models.DateTimeField(default=datetime.now) 

ora potevo makemigrations senza alcun problema. E in seguito ho rimosso default=datetime.now e lo ho sostituito con auto_now_add=True e ho eseguito di nuovo la migrazione senza problemi. Tuttavia, non posso fare a meno di pensare che questo potrebbe non essere il modo migliore di fare le cose. Sento che qualcosa potrebbe andare storto in seguito nel progetto.

risposta

7

Penso che la migliore pratica sarebbe stata quella di rendere nullable i campi. Che cosa significa il tuo campo created al momento: "L'ora in cui è stata creata l'istanza, o l'ora arbitraria in cui ho eseguito la migrazione." Il modo standard per rappresentare la mancanza di un valore è NULL, anziché un valore arbitrario.

Detto questo, se si desidera utilizzare un valore arbitrario, è necessario comunicare a Django cosa è. Solitamente makemigrations ti dà la possibilità di indicare un valore unico da utilizzare per le righe esistenti - non è successo?

Un metodo più laborioso sarebbe quello di dichiarare il campo nullable, quindi creare una migrazione dei dati per riempire il valore desiderato e quindi renderlo non annullabile. Quello che hai fatto è fondamentalmente una versione semplificata di quello. Non vedo che creare problemi nell'andare oltre il problema di created non sia realmente il momento in cui è stata creata l'istanza.

+0

Sì, Django mi ha chiesto un valore unico per le righe esistenti. Ho provato 'datetime.now' ma non sembrava funzionare. Ma suppongo che tutto sia nel complesso ok, allora? È tipico impostare 'null = True' come un" segnaposto "per i valori di riga esistenti e quindi rimuoverlo in seguito per sostituirlo con qualcos'altro? – pyramidface

+0

'datetime.now()' avrebbe funzionato (nota le parentesi - si desidera * chiamare * la funzione e usare il suo valore di ritorno). Aggiungere e rimuovere 'null = True' nei casi più complicati in cui si desidera assegnare un valore diverso a righe diverse. Ad esempio, supponiamo che tu abbia memorizzato la data di creazione effettiva in un file. Scriveresti una migrazione dei dati che, per ogni riga, cercava la data nel file e poi la inserisce nel database. Successivamente, è possibile rimuovere 'null = True' e migrare di nuovo. –

+0

Ahh okay, lo terrò a mente per i progetti futuri. Grazie!! – pyramidface

1

Ho appena avuto il problema esatto. Io uso Django 1.10. Ho letto la risposta di Kevin e ho provato a inserire il valore predefinito quando Django mi ha chiesto di riempirlo come stringa datetime.now. e sono rimasto sorpreso perché, per quei campi, Django si chiederà automaticamente se si desidera utilizzare come predefinito datetime.now:

$ ./manage.py makemigrations 
You are trying to add the field 'date_created' with 'auto_now_add=True' to projectasset without a default; the database needs something to populate existing rows. 

1) Provide a one-off default now (will be set on all existing rows) 
2) Quit, and let me add a default in models.py 
Select an option: 1 
Please enter the default value now, as valid Python 
You can accept the default 'timezone.now' by pressing 'Enter' or you can provide another value. 
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now 
Type 'exit' to exit this prompt 
[default: timezone.now] >>> 

Allora, ho appena confermo che e tutto sembra funzionare bene!

Problemi correlati