Django -> Model erweitert -> makemigrations -> non-nullable field

Django, Flask, Bottle, WSGI, CGI…
Antworten
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

Hallo.

Ich bin gerade auf nen kleinen Fehler gestoßen, den ich nicht ganz verstehe.
Folgende Situation:

Meine models.py VORHER:

Code: Alles auswählen

class Video(models.Model):
	title = models.CharField(max_length=150)
	description = models.TextField(blank=True)
Meine models.py NACHHER:

Code: Alles auswählen

class Video(models.Model):
   title = models.CharField(max_length=150)
   description = models.TextField(blank=True)
   source_video = models.URLField(default="blabla")
Ich habe also lediglich die Zeile "source_video = models.URLField()" hinzugefügt.

makemigrations spuckt mir dann allerdings folgende Fehlermeldung aus:

Code: Alles auswählen

You are trying to add a non-nullable field 'source_video' to video without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 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:
Ich habe bisher schon herausgefunden, dass die Fehlermeldung wohl nur deswegen erscheint, weil ich das Model "Video" erweitert habe. Hätte ich das beim allerersten migrate schon drin gehabt, hätte es keine Probleme gegeben. Und ich habe auch verstanden, dass ein "source_video = models.URLField(default="blabla") " das Problem lösen würde, aber: Warum?

1. Wieso brauch ich beim hinzufügen auf einmal ein default value, während ich beim allerersten Mal keines gebraucht hätte?
2. Angenommen ich habe schon 5 Einträge in der Datenbank...wird das "blabla" dann auch für diese Einträge übernommen insofern Sie bisher leer waren?
3. Was soll das? Welchen Sinn hat das?
4. Kann ich einfach ein default-value setzen...migrate-en und dann das default wieder entfernen? Oder widerspricht das irgendwelchen Programmier-Ethik-Richtlinien?

Ihr seht schon es geht hier nicht darum dass ich Probleme mit Python/Django hätte, ich verstehe einfach nur nicht genau welchen Sinn das hat. Hängt ja anscheinend mit der DB zusammen?!

Vielen Dank schonmal!

P.S. Und ja klar, könnte ich einfach die DB löschen und "neu" migrate-en, aber wenn ich dann doch mal ein Produktivsystem habe, muss ich es ja auch lösen können.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Die Fehlermeldung sagt doch eindeutig was das Problem ist. Es könnten schon Zeilen in der Tabelle sein und darauf musst du in der Migration Rücksicht nehmen. Deswegen kannst du nicht eine neue Spalte hinzufügen ohne zu definieren welcher Wert in dieser Spalte für die schon existierenden Spalten stehen soll, den du hast ja selbst definiert dass dieser Wert nicht NULL sein darf.
4. Kann ich einfach ein default-value setzen...migrate-en und dann das default wieder entfernen? Oder widerspricht das irgendwelchen Programmier-Ethik-Richtlinien?
Nein, damit verschiebst du das Problem nur.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das `default` für die Spalte wird auch nur für komplett neue Datensätze übernommen, nicht für bestehende, die um die Spalte erweitert werden.

Von daher solltest du das machen, was Django dir anbietet, nämlich die Option 1 wählen und dann den Default-Wert für existierende Zeilen dort eingeben.

Gruß, noisefloor
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

Hmm verstehe.

Dann wäre dies also ein Fall wo man die Kombi (null=True, blank=False) verwenden könnte?
Ich will erstmal nix neues in der DB stehen haben, wenn es aber um die Validation von neuen Einträgen geht, soll schon kontrolliert werden dass es auch eine URL ist?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@SnakeBite: wenn die URL optional ist, dann ist Du NULL ganz in Ordnung.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ich will erstmal nix neues in der DB stehen haben
Das ist aber IMHO weder konsequent noch "logisch".

Um bei deinem Beispiel zu bleiben: Du hast 5 Einträge in der DB nach dem alten Modell und erweiterst es dann um die eine Spalte, die einen Default-Wert hat. _Warum_ brauchst du für neue Einträge einen Default-Wert, für die alten aber nicht? Entweder oder, IMHO. Sonst fehlt da die Konsequenz in dem, was in der DB stehen soll.

Von daher ist das, was Django bei der Migration forciert, schon völlig richtig.
Dann wäre dies also ein Fall wo man die Kombi (null=True, blank=False) verwenden könnte?
Die Django-Doku rät davon ab: https://docs.djangoproject.com/en/1.8/r ... elds/#null

Gruß, noisefloor
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

Danke Euch Beiden. Ihr scheint das zwar jeweils etwas anders zu sehen, aber auch das hilft mir weiter. Bei den meisten Sachen verstehe ich was sie machen, aber der Sinn dahinter bleibt mir manchmal verschlossen.

Zum Beispiel das Thema mit Null/Blank. Hier mal alle Überlegungen:

Code: Alles auswählen

null=True and blank=True -> OK (Es muss nix in der DB stehen, wird auch beim eingeben nicht so verlangt)
null=True and blank=False -> kein Sinn (Es muss nix in der DB stehen, beim eingeben wird aber ein Wert verlangt)
null=False and blank=True -> kein Sinn (Es muss was in der DB stehen, beim eingeben wird aber nicht darauf geachtet)
null=False and blank=False -> OK (Es muss was in der DB stehen, wird beim eingeben auch so verlangt)
Das ist doch so richtig?
Welchen Sinn macht denn dann #2 und #3? Bei #2 ist es ja nicht so tragisch, weil einfach ein Wert eingeschrieben wird obwohl eigentlich keiner verlangt wird.
Aber was ist mit #3? Wenn beim eingeben nicht drauf geachtet wird, ob was in der DB stehen muss, die DB es aber so verlangt? "Übertrumpft" hier dann das null statement das blank statement oder gibt es einfach nen Error?

Haben #2 und #3 überhaupt je einen praktischen Nutzen? Und wenn ja wann wäre das der Fall?
BlackJack

@SnakeBite:Bei #2 könnte man erzwingen das eine neu eingeführte Spalte auch eingegeben wird, aber man kann für bereits bestehende Einträge keinen sinnvollen Wert eintragen. So etwas wie: neue Benutzer müssen bei der Anmeldung ab sofort zwingend ihre Lieblingseissorte angeben, aber für die bestehenden Benutzer haben wir die Information leider nicht, also steht da NULL in der Datenbank.

Bei #3 kann der Benutzer ein Feld leer lassen und die Anwendung könnte dann dafür einen Wert erstellen. Beispielsweise wenn der neue Benutzer eines Webproviders Vorname und Name angeben muss, und optional eine E-Mail-Adresse die er dort haben möchte, und wenn er dafür nichts eingibt, wird automatisch vorname.nachname@provider von der Anwendung eingetragen.
SnakeBite
User
Beiträge: 46
Registriert: Mittwoch 4. März 2009, 18:26

@BlackJack: Danke für den Input.

Dann werd ich mein obiges non_nullable field Problem wohl am Besten doch mit (null=True, blank=False) lösen.

Vielen Dank, hat mir geholfen!
Antworten