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?


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

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

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)

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.


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

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)

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

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



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)


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.


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.


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!


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!


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.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.