Próbujesz dodać niedopuszczalne pole „new_field” do profilu użytkownika bez wartości domyślnej

109

Wiem, że od Django 1.7 nie muszę używać South ani żadnego innego systemu migracji, więc używam tylko prostego polecenia python manage.py makemigrations

Jednak wszystko co otrzymuję to ten błąd:

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

Oto models.py:

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

Jakie są opcje?

Irmantas Želionis
źródło
3
Chciałem dodać, że problem pojawia się, gdy zmieniasz istniejącą tabelę, a nie tworzysz nową.
x-yuri

Odpowiedzi:

93

Musisz podać wartość domyślną:

new_field = models.CharField(max_length=140, default='SOME STRING')
dgel
źródło
A co jeśli potrzebuję new_field kopię pola witryny internetowej. Jak to powinno wyglądać? default = websitenie spełnia swojej
roli
8
Chciałbyś najpierw przeprowadzić migrację z fałszywą wartością domyślną, a następnie utworzyć migrację danych, aby iterować przez każdy rekord i ustawić new_fieldna website.
dgel
domyślnie powinno być opcjonalne dla CharField
Florent
90

Jeśli jesteś na wczesnym etapie rozwoju i nie interesują Cię aktualne dane bazy danych, możesz je po prostu usunąć, a następnie przeprowadzić migrację. Ale najpierw musisz wyczyścić katalog migracji i usunąć jego wiersze z tabeli (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
Tomasz
źródło
8
Jeszcze jedna rzecz. Musisz wyczyścić tabelę migracji, np .:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
helpse
To jest sposób. Myślę, że Django jest do bani w migracji i wykrywaniu modeli itp. Potrzebujesz dużej aktualizacji do tego.
WesternGun
Usunąłem wszystkie pliki z migracji i wszystkie wiersze z django_migrations, a teraz podczas uruchamiania otrzymuję komunikat „django.db.migrations.exceptions.NodeNotFoundError: Migration stories.0001_initial dependencies referencies nieistniejący węzeł nadrzędny ('sources', '0002_auto_20180903_1224')” migracja.
brainLoop,
1
Upewnij się również, że nie usuniesz __init__.py pliku z migracji lub przywrócisz go później, w przeciwnym razie makemigrations nie będzie działać stackoverflow.com/a/46362750/1649917
nmu
python manage.py sqlmigrate name_of_your_app nb_of_the_migrationjest również wymagane
zar3bski
38

Jedną z opcji jest zadeklarowanie domyślnej wartości dla „nowego_pola”:

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

inną opcją jest zadeklarowanie „new_field” jako pola dopuszczającego wartość null:

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

Jeśli zdecydujesz się zaakceptować „nowe_pole” jako pole dopuszczające wartość null, możesz zaakceptować „brak danych wejściowych” jako poprawne dane wejściowe dla „nowego_pola”. Następnie musisz dodać również blank=Trueoświadczenie:

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

Nawet z null=Truei / lub blank=Truew razie potrzeby możesz dodać wartość domyślną:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)
Tobi
źródło
7
«Unikaj używania wartości null w polach opartych na ciągach, takich jak CharField i TextField. Jeśli pole tekstowe ma wartość null = True, oznacza to, że ma dwie możliwe wartości dla „brak danych”: NULL i pusty ciąg. » - Odniesienie do modelu
Chema
7

Jeśli jesteś na wczesnym etapie cyklu rozwojowego, możesz spróbować tego -

Usuń / skomentuj ten model i wszystkie jego zastosowania. Zastosuj migracje. To spowodowałoby usunięcie tego modelu, a następnie ponowne dodanie modelu, uruchomienie migracji i uzyskanie czystego modelu z dodanym nowym polem.

Szorstki
źródło
I wyczyść tabelę migracji django_migrations, jak opisano tutaj: stackoverflow.com/questions/26185687/ ... Lub po prostu użyj GUI i usuń wymagane wiersze.
RusI
5

W przypadku, gdy ktoś ustawia a ForeignKey, możesz po prostu zezwolić na pola dopuszczające wartość null bez ustawiania wartości domyślnej:

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

Jeśli masz już dane przechowywane w bazie danych, możesz również ustawić wartość domyślną:

new_field = models.ForeignKey(model, default=<existing model id here>)
Justin Lange
źródło
4

Jeśli „witryna” może być pusta, to new_fieldrównież powinna być pusta.

Teraz, jeśli chcesz dodać logikę przy zapisywaniu, gdzie jeśli new_fieldjest puste, aby pobrać wartość z „strony internetowej”, wszystko, co musisz zrobić, to nadpisać funkcję zapisywania w Modelnastępujący sposób:

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
źródło
3

Nie możesz dodać odwołania do tabeli, która zawiera już dane.
Zmiana:

user = models.OneToOneField(User)

do:

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

robić:

python manage.py makemigrations
python manage.py migrate

zmień ponownie:

user = models.OneToOneField(User)

ponownie wykonaj migrację:

python manage.py makemigrations
python manage.py migrate
E. Kristiyono
źródło
2

W new_file dodaj właściwość logiczną null.

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

po uruchomieniu ./manage.py syncdbdla odświeżyć DB. i wreszcie biegniesz ./manage.py makemigrations i./manage.py migrate

gerachev
źródło
2

Czy masz już wpisy bazy danych w tabeli UserProfile? Jeśli tak, po dodaniu nowych kolumn baza danych nie wie, na co ją ustawić, ponieważ nie może NULL. Dlatego zapyta Cię, do czego chcesz ustawić te pola w kolumnie new_fields. Musiałem usunąć wszystkie wiersze z tej tabeli, aby rozwiązać problem.

(Wiem, że odpowiedź na to pytanie udzielono jakiś czas temu, ale właśnie napotkałem ten problem i to było moje rozwiązanie. Mam nadzieję, że pomoże to każdemu nowemu, który to zobaczy)

Arnold Lam
źródło
1
Nie wstawiłem wierszy do tabeli i nadal to rozumiem. Muszę usunąć całą historię migracji, wyczyścić tabelę migracji, żeby zmienić model, tak jak sugeruje Tomasz.
WesternGun
1

Szczerze mówiąc, najlepszym sposobem obejścia tego problemu było po prostu utworzenie kolejnego modelu ze wszystkimi wymaganymi polami i nazwanymi nieco innymi. Uruchom migracje. Usuń nieużywany model i ponownie uruchom migracje. Voila.

Josh
źródło
1

Jeśli możesz skrócić tabelę danego modelu, możesz określić jednorazową domyślną wartość Nonew monicie. Migracja będzie zbędna, default=Nonepodczas gdy Twój kod nie ma wartości domyślnych. Można go zastosować dobrze, ponieważ w tabeli nie ma już danych, które wymagałyby ustawienia domyślnego.

jnns
źródło
1

Byłem na wczesnym etapie mojego cyklu rozwojowego, więc może to nie działać dla wszystkich (ale nie rozumiem, dlaczego by nie działało).

Dodałem blank=True, null=Truedo kolumn, w których otrzymywałem błąd. Następnie uruchomiłem python manage.py makemigrationspolecenie.

Natychmiast po uruchomieniu tego polecenia (i przed uruchomieniem python manage.py migrate) usunąłem blank=True, null=Trueze wszystkich kolumn. Potem uciekłempython manage.py makemigrations znowu . Dostałem możliwość samodzielnej zmiany kolumn, które wybrałem.

Potem pobiegłem python manage.py migratei wszystko działało dobrze!

Joseph Gill
źródło
0

Django tak naprawdę mówi:

Tabela profilu użytkownika zawiera dane i mogą być new_fieldwartości, które są zerowe, ale nie wiem, więc czy na pewno chcesz oznaczyć właściwość jako nieprzekraczającą wartości null, ponieważ jeśli to zrobisz, możesz otrzymać błąd, jeśli istnieją wartości z wartością NULL

Jeśli jesteś pewien, że żadna z wartości w userprofiletabeli nie ma wartości NULL - spadła swobodnie i zignoruj ​​ostrzeżenie.

Najlepszą praktyką w takich przypadkach byłoby utworzenie migracji RunPython do obsługi pustych wartości, zgodnie z opcją 2

2) Na razie zignoruj ​​i pozwól mi samodzielnie obsłużyć istniejące wiersze z NULL (np. Ponieważ dodałeś operację RunPython lub RunSQL do obsługi wartości NULL w poprzedniej migracji danych)

W migracji RunPython musisz znaleźć wszystkie UserProfileinstancje z pustą new_fieldwartością i umieścić tam poprawną wartość (lub wartość domyślną, ponieważ Django poprosi Cię o ustawienie w modelu). Otrzymasz coś takiego:

# 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

Baw się dobrze!

Taras Matsyk
źródło
Nie mogę znaleźć miejsca, w którym jest to napisane w dokumentacji. Można zamieszczać linku proszę
Cody
0

W 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")

Musisz domyślnie dodać niektóre wartości.

George Devasia
źródło
-1

Jeśli SSH daje 2 opcje, wybierz numer 1 i wpisz „Brak”. Tylko to ... na razie.

Geovanni Atavales
źródło