Anda mencoba menambahkan bidang non-nullable 'new_field' ke profil pengguna tanpa default

109

Saya tahu bahwa dari Django 1.7 saya tidak perlu menggunakan Selatan atau sistem migrasi lainnya, jadi saya hanya menggunakan perintah sederhana python manage.py makemigrations

Namun, yang saya dapatkan hanyalah kesalahan ini:

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

Berikut adalah models.py:

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

Apa sajakah pilihan?

Irmantas Želionis
sumber
3
Saya ingin menambahkan bahwa masalah terjadi saat Anda mengubah tabel yang ada, bukan saat Anda membuat yang baru.
x-yuri

Jawaban:

91

Anda perlu memberikan nilai default:

new_field = models.CharField(max_length=140, default='SOME STRING')
dgel
sumber
Bagaimana jika saya perlu memiliki new_field salinan dari bidang situs web. Bagaimana seharusnya terlihat? default = websitetidak melakukan pekerjaan itu
Irmantas Želionis
7
Anda ingin melakukan migrasi terlebih dahulu dengan nilai default palsu, lalu membuat migrasi data untuk melakukan iterasi melalui setiap record dan setel new_fieldke website.
dgel
default harus opsional untuk CharField
Florent
88

Jika Anda berada dalam siklus pengembangan awal dan tidak peduli dengan data database Anda saat ini, Anda dapat menghapusnya lalu bermigrasi. Tetapi pertama-tama Anda perlu membersihkan dir migrasi dan menghapus barisnya dari tabel (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate
Tomasz
sumber
8
Satu hal lagi. Anda perlu membersihkan tabel migrasi misalnya:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
helpse
Ini caranya. Saya pikir Django menyebalkan pada migrasi dan deteksi model, dll. Ingin pembaruan besar untuk ini.
WesternGun
Saya telah menghapus semua file dari migrasi dan menghapus semua baris dari django_migrations dan sekarang saya mendapatkan "django.db.migrations.exceptions.NodeNotFoundError: Migration stories.0001_initial dependencies mereferensikan node induk yang tidak ada ('sources', '0002_auto_20180903_1224')" saat menjalankan migrasi.
brainLoop
1
Juga pastikan Anda tidak menghapus __init__.py migrasi dari, atau, Anda memulihkannya setelah itu, jika tidak, migrasi tidak akan berfungsi stackoverflow.com/a/46362750/1649917
nmu
python manage.py sqlmigrate name_of_your_app nb_of_the_migrationjuga diperlukan
zar3bski
37

Salah satu opsinya adalah mendeklarasikan nilai default untuk 'new_field':

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

pilihan lain adalah mendeklarasikan 'new_field' sebagai bidang nullable:

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

Jika Anda memutuskan untuk menerima 'new_field' sebagai field nullable, Anda mungkin ingin menerima 'no input' sebagai input yang valid untuk 'new_field'. Kemudian Anda harus menambahkan blank=Truepernyataan itu juga:

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

Bahkan dengan null=Truedan / atau blank=TrueAnda dapat menambahkan nilai default jika perlu:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)
Tobi
sumber
7
«Hindari menggunakan null pada bidang berbasis string seperti CharField dan TextField. Jika kolom berbasis string memiliki null = True, itu berarti kolom tersebut memiliki dua kemungkinan nilai untuk "tidak ada data": NULL, dan string kosong. » - Referensi lapangan model
Chema
7

Jika Anda berada di awal siklus pengembangan, Anda dapat mencoba ini -

Hapus / komentari model itu dan semua penggunaannya. Terapkan migrasi. Itu akan menghapus model itu dan kemudian menambahkan model itu lagi, menjalankan migrasi dan Anda memiliki model bersih dengan bidang baru ditambahkan.

Keras
sumber
Dan bersihkan tabel migrasi django_migrations seperti yang dijelaskan di sini: stackoverflow.com/questions/26185687/… Atau cukup gunakan GUI dan hapus baris yang diperlukan.
RusI
4

Jika "situs web" bisa kosong maka new_fieldharus disetel menjadi kosong.

Sekarang jika Anda ingin menambahkan logika pada save where if new_fieldis empty untuk mengambil nilai dari "website" yang perlu Anda lakukan adalah mengganti fungsi save untuk Anda Modelseperti ini:

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
sumber
4

Jika ada yang menyetel ForeignKey, Anda bisa mengizinkan bidang nullable tanpa menyetel default:

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

Jika Anda sudah memiliki data yang disimpan dalam database, Anda juga bisa menyetel nilai default:

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

Anda tidak dapat menambahkan referensi ke tabel yang sudah memiliki data di dalamnya.
Perubahan:

user = models.OneToOneField(User)

untuk:

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

melakukan:

python manage.py makemigrations
python manage.py migrate

ubah lagi:

user = models.OneToOneField(User)

lakukan migrasi lagi:

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

Dalam new_file tambahkan properti boolean null.

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

setelah Anda menjalankan ./manage.py syncdbuntuk menyegarkan DB. dan akhirnya Anda lari ./manage.py makemigrations dan./manage.py migrate

gerachev
sumber
2

Apakah Anda sudah memiliki entri database di tabel UserProfile? Jika demikian, ketika Anda menambahkan kolom baru, DB tidak tahu harus mengaturnya karena tidak bisa NULL. Oleh karena itu, ia menanyakan apa yang ingin Anda setel bidang tersebut di kolom new_fields. Saya harus menghapus semua baris dari tabel ini untuk menyelesaikan masalah.

(Saya tahu ini telah dijawab beberapa waktu yang lalu, tetapi saya baru saja mengalami masalah ini dan ini adalah solusi saya. Semoga ini akan membantu siapa pun yang baru melihat ini)

Arnold Lam
sumber
1
Saya belum memasukkan baris ke dalam tabel dan masih mendapatkan ini. Saya harus menghapus semua riwayat migrasi, membersihkan tabel migrasi untuk mengubah model, seperti yang disarankan oleh Tomasz.
WesternGun
1

Sejujurnya saya menemukan cara terbaik untuk menyiasati ini adalah dengan hanya membuat model lain dengan semua bidang yang Anda butuhkan dan diberi nama yang sedikit berbeda. Jalankan migrasi. Hapus model yang tidak digunakan dan jalankan migrasi lagi. Voila.

Josh
sumber
1

Jika Anda tidak keberatan memotong tabel model yang dimaksud, Anda dapat menentukan nilai default satu kali Nonedi prompt. Migrasi akan menjadi berlebihan default=Nonesementara kode Anda tidak memiliki default. Ini dapat diterapkan dengan baik karena tidak ada lagi data dalam tabel yang memerlukan default.

jnns
sumber
1

Saya masih awal dalam siklus pengembangan saya, jadi ini mungkin tidak berfungsi untuk semua orang (tetapi saya tidak mengerti mengapa tidak).

Saya menambahkan blank=True, null=Trueke kolom di mana saya mendapatkan kesalahan. Lalu aku menjalankan python manage.py makemigrationsperintah.

Segera setelah menjalankan perintah ini (dan sebelum menjalankan python manage.py migrate), saya menghapus blank=True, null=Truedari semua kolom. Lalu aku lari python manage.py makemigrationslagi. Saya diberi opsi untuk hanya mengubah kolom sendiri, yang saya pilih.

Kemudian saya berlari python manage.py migratedan semuanya bekerja dengan baik!

Joseph Gill
sumber
0

Apa yang sebenarnya Django katakan adalah:

Tabel Userprofile memiliki data di dalamnya dan mungkin ada new_fieldnilai yang null, tapi saya tidak tahu, jadi apakah Anda yakin ingin menandai properti sebagai non nullable, karena jika Anda melakukannya Anda mungkin mendapatkan kesalahan jika ada nilai dengan NULL

Jika Anda yakin bahwa tidak ada nilai dalam userprofiletabel yang NULL - bebas dan abaikan peringatan.

Praktik terbaik dalam kasus seperti itu adalah membuat migrasi RunPython untuk menangani nilai kosong seperti yang dinyatakan dalam opsi 2

2) Abaikan untuk saat ini, dan biarkan saya menangani sendiri baris yang ada dengan NULL (misalnya karena Anda menambahkan operasi RunPython atau RunSQL untuk menangani nilai NULL dalam migrasi data sebelumnya)

Dalam migrasi RunPython Anda harus menemukan semua UserProfilecontoh dengan new_fieldnilai kosong dan meletakkan nilai yang benar di sana (atau nilai default seperti yang diminta Django untuk Anda setel dalam model). Anda akan mendapatkan sesuatu seperti ini:

# 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

Selamat bersenang-senang!

Taras Matsyk
sumber
Saya tidak bisa menemukan di mana ini tertulis dalam dokumentasi. Bisakah Anda memposting tautannya
Cody
0

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

Anda perlu menambahkan beberapa nilai sebagai default.

George Devasia
sumber
-1

Jika SSH itu memberi Anda 2 pilihan, pilih nomor 1, dan masukkan "Tidak Ada". Hanya itu ... untuk saat ini.

Geovanni Atavales
sumber