Sie versuchen, dem Benutzerprofil ein nicht nullwertfähiges Feld 'new_field' ohne Standard hinzuzufügen

108

Ich weiß, dass ich ab Django 1.7 weder South noch ein anderes Migrationssystem verwenden muss, also verwende ich nur einen einfachen Befehl python manage.py makemigrations

Ich erhalte jedoch nur diesen Fehler:

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).

Hier ist models.py:

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

Was sind Optionen?

Irmantas Želionis
quelle
3
Ich wollte hinzufügen, dass das Problem auftritt, wenn Sie eine vorhandene Tabelle ändern, nicht, wenn Sie eine neue erstellen.
X-Yuri

Antworten:

90

Sie müssen einen Standardwert angeben:

new_field = models.CharField(max_length=140, default='SOME STRING')
dgel
quelle
Was ist, wenn ich new_field als Kopie eines Website-Felds benötige? Wie soll das aussehen? default = websitemacht den Job nicht
Irmantas Želionis
7
Sie würden wollen zunächst mit einem falschen Standardwert die Migration zu tun, dann eine erstellen Datenmigration zu durchlaufen jeden Datensatz und Satz new_fieldzu website.
dgel
Die Standardeinstellung sollte für CharField
Florent
87

Wenn Sie sich in einem frühen Entwicklungszyklus befinden und sich nicht um Ihre aktuellen Datenbankdaten kümmern, können Sie diese einfach entfernen und dann migrieren. Aber zuerst müssen Sie das Migrationsverzeichnis bereinigen und die Zeilen aus der Tabelle entfernen (django_migrations).

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
Tomasz
quelle
8
Eine Sache noch. Sie müssen die Migrationstabelle bereinigen, zB:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
Helpse
Das ist der Weg. Ich denke, Django nervt mit Migration und Modellerkennung usw. Willst du ein großes Update dafür?
WesternGun
Ich habe alle Dateien aus Migrationen und alle Zeilen aus django_migrations gelöscht und erhalte jetzt beim Ausführen "django.db.migrations.exceptions.NodeNotFoundError: Migrationsgeschichten.0001_initiale Abhängigkeiten verweisen auf nicht vorhandenen übergeordneten Knoten ('Quellen', '0002_auto_20180903_1224')" Migration.
brainLoop
1
__init__.py Stellen Sie außerdem sicher, dass Sie die Migrationen nicht löschen oder anschließend wiederherstellen, da Makemigrationen sonst nicht funktionieren. Stackoverflow.com/a/46362750/1649917
nmu
python manage.py sqlmigrate name_of_your_app nb_of_the_migrationist auch erforderlich
zar3bski
37

Eine Möglichkeit besteht darin, einen Standardwert für 'new_field' zu deklarieren:

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

Eine andere Möglichkeit besteht darin, 'new_field' als nullbares Feld zu deklarieren:

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

Wenn Sie 'new_field' als nullbares Feld akzeptieren, möchten Sie möglicherweise 'no input' als gültige Eingabe für 'new_field' akzeptieren. Dann müssen Sie auch die blank=TrueAnweisung hinzufügen :

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

Auch mit null=Trueund / oder können blank=TrueSie bei Bedarf einen Standardwert hinzufügen:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)
Tobi
quelle
7
«Vermeiden Sie die Verwendung von null in stringbasierten Feldern wie CharField und TextField. Wenn ein auf Zeichenfolgen basierendes Feld null = True hat, bedeutet dies, dass es zwei mögliche Werte für "keine Daten" hat: NULL und die leere Zeichenfolge. » - Modellfeldreferenz
Chema
7

Wenn Sie früh im Entwicklungszyklus sind, können Sie dies versuchen -

Entfernen / kommentieren Sie dieses Modell und alle seine Verwendungen. Migrationen anwenden. Das würde dieses Modell löschen und dann das Modell erneut hinzufügen, Migrationen ausführen und Sie haben ein sauberes Modell mit dem neuen Feld hinzugefügt.

Hart
quelle
Bereinigen Sie die Migrationstabelle django_migrations wie hier beschrieben: stackoverflow.com/questions/26185687/… Oder verwenden Sie einfach eine GUI und löschen Sie die erforderlichen Zeilen.
RusI
4

Wenn "Website" leer new_fieldsein kann, sollte auch "leer" gesetzt werden.

Wenn Sie nun beim Speichern eine Logik hinzufügen möchten, bei der if new_fieldleer ist, um den Wert von "website" abzurufen, müssen Sie lediglich die Speicherfunktion für Folgendes überschreiben Model:

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)
Alex Carlos
quelle
4

Wenn jemand a ForeignKeyfestlegt, können Sie einfach nullbare Felder zulassen, ohne einen Standard festzulegen:

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

Wenn Sie bereits Daten in der Datenbank gespeichert haben, können Sie auch einen Standardwert festlegen:

new_field = models.ForeignKey(model, default=<existing model id here>)
Justin Lange
quelle
3

Sie können keinen Verweis auf eine Tabelle hinzufügen, in der sich bereits Daten befinden.
Veränderung:

user = models.OneToOneField(User)

zu:

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

machen:

python manage.py makemigrations
python manage.py migrate

wieder ändern:

user = models.OneToOneField(User)

Führen Sie die Migration erneut durch:

python manage.py makemigrations
python manage.py migrate
E. Kristiyono
quelle
2

Fügen Sie in new_file die boolesche Eigenschaft null hinzu.

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

Nachdem Sie eine ./manage.py syncdbAktualisierung der Datenbank ausgeführt haben. und schließlich rennst du ./manage.py makemigrations und./manage.py migrate

gerachev
quelle
2

Haben Sie bereits Datenbankeinträge in der Tabelle UserProfile? Wenn ja, wenn Sie neue Spalten hinzufügen, weiß die Datenbank nicht, auf was sie eingestellt werden soll, da dies nicht möglich ist NULL. Daher werden Sie gefragt, auf was Sie diese Felder in der Spalte setzen möchten new_fields. Ich musste löschen alle Zeilen aus dieser Tabelle , um das Problem zu lösen.

(Ich weiß, dass dies vor einiger Zeit beantwortet wurde, aber ich bin gerade auf dieses Problem gestoßen und dies war meine Lösung. Hoffentlich hilft es jedem, der dies sieht.)

Arnold Lam
quelle
1
Ich habe keine Zeilen in die Tabelle eingefügt und bekomme diese trotzdem. Ich muss den gesamten Migrationsverlauf löschen und die Migrationstabelle löschen, um das Modell zu ändern, wie von Tomasz vorgeschlagen.
WesternGun
1

Ich glaube ehrlich, der beste Weg, dies zu umgehen, bestand darin, einfach ein anderes Modell mit allen Feldern zu erstellen, die Sie benötigen, und etwas anders zu benennen. Führen Sie Migrationen aus. Löschen Sie nicht verwendetes Modell und führen Sie die Migrationen erneut aus. Voila.

Josh
quelle
1

Wenn Sie die Tabelle des betreffenden Modells abschneiden können, können Sie Nonein der Eingabeaufforderung einen einmaligen Standardwert von angeben . Die Migration ist überflüssig, default=Nonewährend Ihr Code keine Standardeinstellung hat. Es kann problemlos angewendet werden, da die Tabelle keine Daten mehr enthält, für die eine Standardeinstellung erforderlich wäre.

jnns
quelle
1

Ich war früh in meinem Entwicklungszyklus, daher funktioniert dies möglicherweise nicht für alle (aber ich verstehe nicht, warum dies nicht der Fall ist).

Ich habe blank=True, null=Truezu den Spalten hinzugefügt, in denen ich den Fehler erhalten habe. Dann habe ich den python manage.py makemigrationsBefehl ausgeführt.

Unmittelbar nach dem Ausführen dieses Befehls (und vor dem Ausführen python manage.py migrate) habe ich das blank=True, null=Trueaus allen Spalten entfernt. Dann rannte ich python manage.py makemigrationswieder. Ich hatte die Möglichkeit, die von mir ausgewählten Spalten einfach selbst zu ändern.

Dann bin ich gelaufen python manage.py migrateund alles hat gut funktioniert!

Joseph Gill
quelle
0

Was Django tatsächlich sagt, ist:

Die Benutzerprofiltabelle enthält Daten, und es gibt möglicherweise new_fieldWerte, die null sind, aber ich weiß es nicht. Sind Sie also sicher, dass Sie die Eigenschaft als nicht nullwertfähig markieren möchten, da in diesem Fall möglicherweise eine Fehlermeldung angezeigt wird, wenn Werte mit NULL vorhanden sind

Wenn Sie sicher sind, dass keiner der Werte in der userprofileTabelle NULL ist, können Sie die Warnung ignorieren.

In solchen Fällen empfiehlt es sich, eine RunPython-Migration zu erstellen, um leere Werte zu verarbeiten, wie in Option 2 angegeben

2) Ignorieren Sie dies zunächst und lassen Sie mich vorhandene Zeilen mit NULL selbst behandeln (z. B. weil Sie eine RunPython- oder RunSQL-Operation hinzugefügt haben, um NULL-Werte in einer vorherigen Datenmigration zu verarbeiten).

Bei der RunPython-Migration müssen Sie alle UserProfileInstanzen mit leerem new_fieldWert finden und dort einen korrekten Wert eingeben (oder einen Standardwert, den Django im Modell festlegen soll). Sie werden so etwas bekommen:

# 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

Habe Spaß!

Taras Matsyk
quelle
Ich kann anscheinend nicht finden, wo dies in der Dokumentation geschrieben steht. Können Sie den Link bitte posten
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")

Sie müssen standardmäßig einige Werte hinzufügen.

George Devasia
quelle
-1

Wenn die SSH Ihnen 2 Optionen bietet, wählen Sie Nummer 1 und geben Sie "Keine" ein. Nur das ... für den Moment.

Geovanni Atavales
quelle