Stai tentando di aggiungere un campo non annullabile "new_field" a userprofile senza un valore predefinito


109

So che da Django 1.7 non ho bisogno di usare South o qualsiasi altro sistema di migrazione, quindi sto solo usando un semplice comando python manage.py makemigrations

Tuttavia, tutto ciò che ottengo è questo errore:

You are trying to add a non-nullable field 'new_field' to userprofile without a default;
we can't do that (the database needs something to populate existing rows).

Ecco models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True)
    new_field = models.CharField(max_length=140)

Quali sono le opzioni?


3
Volevo aggiungere che il problema si verifica quando modifichi una tabella esistente, non quando ne crei una nuova.
x-yuri

Risposte:


91

Devi fornire un valore predefinito:

new_field = models.CharField(max_length=140, default='SOME STRING')

E se avessi bisogno di new_field una copia del campo di un sito web. Come dovrebbe apparire? default = websitenon fa il lavoro
Irmantas Želionis

7
Dovresti prima eseguire la migrazione con un valore predefinito fasullo, quindi creare una migrazione dei dati per scorrere ogni record e impostare new_fieldsu website.
dgel

il valore predefinito dovrebbe essere facoltativo per CharField
Florent

88

Se sei nel ciclo di sviluppo iniziale e non ti interessano i dati del tuo database corrente , puoi semplicemente rimuoverli e quindi migrare. Ma prima devi pulire la directory delle migrazioni e rimuovere le sue righe dalla tabella (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate

8
Un'altra cosa. È necessario pulire la tabella delle migrazioni, ad esempio:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
helpse

Questo è il modo. Penso che Django faccia schifo nella migrazione e nel rilevamento dei modelli, ecc. Voglio un aggiornamento importante per questo.
WesternGun

Ho cancellato tutti i file dalle migrazioni e tutte le righe da django_migrations e ora ricevo "django.db.migrations.exceptions.NodeNotFoundError: Migration stories.0001_initial dependencies reference inexistent parent node ('sources', '0002_auto_20180903_1224')" when running migrazione.
brainLoop

1
Anche essere sicuri di non elimina il __init__.py da migrazioni, oppure, si ripristina subito dopo, altrimenti makemigrations non funziona stackoverflow.com/a/46362750/1649917
nmu

python manage.py sqlmigrate name_of_your_app nb_of_the_migrationè anche richiesto
zar3bski

37

Un'opzione è dichiarare un valore predefinito per "new_field":

new_field = models.CharField(max_length=140, default='DEFAULT VALUE')

un'altra opzione è dichiarare 'new_field' come campo nullable:

new_field = models.CharField(max_length=140, null=True)

Se decidi di accettare "new_field" come campo nullable, potresti voler accettare "no input" come input valido per "new_field". Quindi devi aggiungere anche la blank=Truedichiarazione:

new_field = models.CharField(max_length=140, blank=True, null=True)

Anche con null=Truee / o blank=Truepuoi aggiungere un valore predefinito se necessario:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)

7
«Evita di usare null su campi basati su stringa come CharField e TextField. Se un campo basato su stringa ha null = True, significa che ha due possibili valori per "nessun dato": NULL e la stringa vuota. » - Riferimento campo modello
Chema

7

Se sei all'inizio del ciclo di sviluppo, puoi provare questo:

Rimuovi / commenta quel modello e tutti i suoi utilizzi. Applica migrazioni. Ciò eliminerebbe quel modello e quindi aggiungerebbe di nuovo il modello, eseguirà le migrazioni e avrai un modello pulito con il nuovo campo aggiunto.


E ripulisci la tabella delle migrazioni django_migrations come descritto qui: stackoverflow.com/questions/26185687/… Oppure usa semplicemente una GUI ed elimina le righe richieste.
RusI

5

Nel caso in cui qualcuno stia impostando un ForeignKey, puoi semplicemente consentire i campi nullable senza impostare un valore predefinito:

new_field = models.ForeignKey(model, null=True)

Se hai già dati memorizzati nel database, puoi anche impostare un valore predefinito:

new_field = models.ForeignKey(model, default=<existing model id here>)

4

Se "sito web" può essere vuoto new_field, anche questo dovrebbe essere vuoto.

Ora, se vuoi aggiungere la logica al salvataggio dove if new_fieldè vuoto per prendere il valore da "sito web", tutto ciò che devi fare è sovrascrivere la funzione di salvataggio per il tuo Modelcome questo:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True, default='DEFAULT VALUE')
    new_field = models.CharField(max_length=140, blank=True, default='DEFAULT VALUE')

    def save(self, *args, **kwargs):
        if not self.new_field:
            # Setting the value of new_field with website's value
            self.new_field = self.website

        # Saving the object with the default save() function
        super(UserProfile, self).save(*args, **kwargs)

3

Non è possibile aggiungere riferimenti a tabelle che contengono già dati all'interno.
Modificare:

user = models.OneToOneField(User)

per:

user = models.OneToOneField(User, default = "")

fare:

python manage.py makemigrations
python manage.py migrate

cambia di nuovo:

user = models.OneToOneField(User)

esegui di nuovo la migrazione:

python manage.py makemigrations
python manage.py migrate

2

In new_file aggiungere la proprietà booleana null.

new_field = models.CharField(max_length=140, null=True)

dopo aver eseguito un ./manage.py syncdbaggiornamento del database. e finalmente corri ./manage.py makemigrations e./manage.py migrate



2

Hai già voci di database nella tabella UserProfile? Se è così, quando aggiungi nuove colonne il DB non sa su cosa impostarlo perché non può esserlo NULL. Quindi ti chiede cosa vuoi impostare quei campi nella colonna new_fields. Ho dovuto eliminare tutte le righe da questa tabella per risolvere il problema.

(So ​​che è stata risolta qualche tempo fa, ma mi sono imbattuto in questo problema e questa era la mia soluzione. Spero che possa aiutare chiunque lo veda)


1
Non ho inserito righe nella tabella e ottengo ancora questo. Devo eliminare tutta la cronologia della migrazione, pulire la tabella di migrazione per modificare il modello, come suggerito da Tomasz.
WesternGun

1

Onestamente, il modo migliore per aggirare questo problema è stato semplicemente creare un altro modello con tutti i campi richiesti e denominati leggermente diversi. Esegui migrazioni. Elimina il modello inutilizzato ed esegui nuovamente le migrazioni. Ecco.


1

Se stai bene con il troncamento della tabella del modello in questione, puoi specificare un valore predefinito una tantum di Nonenel prompt. La migrazione sarà superflua default=Nonementre il tuo codice non ha alcun valore predefinito. Può essere applicato perfettamente perché non ci sono più dati nella tabella che richiederebbero un'impostazione predefinita.


1

Ero all'inizio del mio ciclo di sviluppo, quindi potrebbe non funzionare per tutti (ma non vedo perché non lo sarebbe).

Ho aggiunto blank=True, null=Truealle colonne in cui stavo ottenendo l'errore. Quindi ho eseguito il python manage.py makemigrationscomando.

Immediatamente dopo aver eseguito questo comando (e prima di eseguire python manage.py migrate), ho rimosso il blank=True, null=Trueda tutte le colonne. Poi ho corso di python manage.py makemigrationsnuovo. Mi è stata data un'opzione per cambiare solo le colonne da solo, che ho selezionato.

Poi ho corso python manage.py migratee tutto ha funzionato bene!


0

Quello che Django in realtà dice è:

La tabella del profilo utente contiene dati e potrebbero esserci new_fieldvalori nulli, ma non lo so, quindi sei sicuro di voler contrassegnare la proprietà come non annullabile, perché se lo fai potresti ottenere un errore se ci sono valori con NULL

Se sei sicuro che nessuno dei valori nella userprofiletabella sia NULL, puoi liberarti e ignorare l'avviso.

La migliore pratica in questi casi sarebbe creare una migrazione RunPython per gestire valori vuoti come indicato nell'opzione 2

2) Ignora per ora e lasciami gestire le righe esistenti con NULL da solo (ad esempio perché hai aggiunto un'operazione RunPython o RunSQL per gestire i valori NULL in una precedente migrazione dei dati)

Nella migrazione RunPython devi trovare tutte le UserProfileistanze con un new_fieldvalore vuoto e inserire un valore corretto lì (o un valore predefinito come Django ti chiede di impostare nel modello). Otterrai qualcosa del genere:

# please keep in mind that new_value can be an empty string. You decide whether it is a correct value.
for profile in UserProfile.objects.filter(new_value__isnull=True).iterator():
    profile.new_value = calculate_value(profile)
    profile.save() # better to use batch save

Divertiti!


Non riesco a trovare dove sia scritto nella documentazione. Puoi pubblicare il link per favore
Cody

0

In models.py

class UserProfile(models.Model): user = models.OneToOneField(User) website = models.URLField(blank=True) new_field = models.CharField(max_length=140, default="some_value")

È necessario aggiungere alcuni valori come predefiniti.


-1

Se l'SSH ti dà 2 opzioni, scegli il numero 1 e metti "Nessuno". Solo questo ... per il momento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.