Bạn đang cố thêm trường không thể nullable 'new_field' vào tệp người dùng mà không có mặc định


108

Tôi biết rằng từ Django 1.7, tôi không cần sử dụng South hoặc bất kỳ hệ thống di chuyển nào khác, vì vậy tôi chỉ sử dụng lệnh đơn giản python manage.py makemigrations

Tuy nhiên, tất cả những gì tôi nhận được là lỗi này:

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

Đây là models.py:

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

Các tùy chọn là gì?


3
Tôi muốn nói thêm rằng sự cố xảy ra khi bạn thay đổi bảng hiện có, không phải khi bạn tạo một bảng mới.
x-yuri

Câu trả lời:


91

Bạn cần cung cấp giá trị mặc định:

new_field = models.CharField(max_length=140, default='SOME STRING')

Điều gì sẽ xảy ra nếu tôi cần new_field một bản sao của một trường trang web. Nó sẽ trông như thế nào? default = websitekhông thực hiện công việc
Irmantas Želionis

7
Trước tiên, bạn muốn thực hiện di chuyển với giá trị mặc định không có thật, sau đó tạo di chuyển dữ liệu để lặp qua từng bản ghi và đặt new_fieldthành website.
dgel

mặc định phải là tùy chọn cho CharField
Florent

87

Nếu bạn đang trong chu kỳ phát triển ban đầu và không quan tâm đến dữ liệu cơ sở dữ liệu hiện tại của mình, bạn có thể xóa nó và sau đó di chuyển. Nhưng trước tiên, bạn cần làm sạch dir dir và xóa các hàng của nó khỏi bảng (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate

8
Một điều nữa. Bạn cần dọn dẹp bảng di chuyển, ví dụ:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
helpse

Đây là con đường. Tôi nghĩ Django tệ ở việc di chuyển và phát hiện mô hình, v.v. Muốn có một bản cập nhật lớn cho điều này.
WesternGun

Tôi đã xóa tất cả các tệp khỏi quá trình di chuyển và xóa tất cả các hàng khỏi django_migrations và bây giờ tôi nhận được "django.db.migrations.exceptions.NodeNotFoundError: Migration story.0001_initial dependencies tham chiếu nút cha không tồn tại ('sources', '0002_auto_20180903_1224')" khi chạy sự di cư.
brainLoop,

1
Ngoài ra, hãy chắc chắn rằng bạn không xóa __init__.py khỏi quá trình di chuyển, hoặc bạn khôi phục nó sau đó, nếu không makemigrations sẽ không hoạt động stackoverflow.com/a/46362750/1649917
nmu

python manage.py sqlmigrate name_of_your_app nb_of_the_migrationcũng được yêu cầu
zar3bski

37

Một tùy chọn là khai báo giá trị mặc định cho 'new_field':

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

một tùy chọn khác là khai báo 'new_field' dưới dạng trường nullable:

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

Nếu bạn quyết định chấp nhận 'new_field' là trường có thể làm trống, bạn có thể muốn chấp nhận 'no input' làm đầu vào hợp lệ cho 'new_field'. Sau đó, bạn cũng phải thêm blank=Truecâu lệnh:

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

Ngay cả với null=Truevà / hoặc blank=Truebạn có thể thêm giá trị mặc định nếu cần:

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

7
«Tránh sử dụng null trên các trường dựa trên chuỗi như CharField và TextField. Nếu một trường dựa trên chuỗi có null = True, điều đó có nghĩa là nó có hai giá trị có thể cho “không có dữ liệu”: NULL và chuỗi trống. » - Tham chiếu trường mô hình
Chema

7

Nếu bạn mới bắt đầu chu kỳ phát triển, bạn có thể thử điều này -

Xóa / nhận xét mô hình đó và tất cả các cách sử dụng của nó. Áp dụng di chuyển. Điều đó sẽ xóa mô hình đó và sau đó thêm lại mô hình, chạy di chuyển và bạn có một mô hình rõ ràng với trường mới được thêm vào.


Và dọn dẹp bảng di chuyển django_migrations như được nêu ở đây: stackoverflow.com/questions/26185687/… Hoặc chỉ sử dụng GUI và xóa các hàng bắt buộc.
RusI

4

Nếu "trang web" có thể trống hơn new_fieldthì cũng nên được đặt thành trống.

Bây giờ nếu bạn muốn thêm logic vào lưu ở nơi nếu new_fieldtrống để lấy giá trị từ "trang web", tất cả những gì bạn cần làm là ghi đè chức năng lưu cho Modelnhư thế này:

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)

4

Trong trường hợp có ai đó đang đặt a ForeignKey, bạn chỉ có thể cho phép các trường có thể trống mà không cần đặt mặc định:

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

Nếu bạn đã có dữ liệu được lưu trữ trong cơ sở dữ liệu, bạn cũng có thể đặt giá trị mặc định:

new_field = models.ForeignKey(model, default=<existing model id here>)

3

Bạn không thể thêm tham chiếu vào bảng đã có dữ liệu bên trong.
Thay đổi:

user = models.OneToOneField(User)

đến:

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

làm:

python manage.py makemigrations
python manage.py migrate

thay đổi lại:

user = models.OneToOneField(User)

thực hiện di chuyển lại:

python manage.py makemigrations
python manage.py migrate

2

Trong new_file, thêm thuộc tính boolean null.

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

sau khi bạn chạy một ./manage.py syncdbđể làm mới DB. và cuối cùng bạn chạy ./manage.py makemigrations./manage.py migrate



2

Bạn đã có các mục nhập cơ sở dữ liệu trong bảng UserProfile? Nếu vậy, khi bạn thêm các cột mới, DB không biết phải đặt nó thành gì vì nó không thể được NULL. Do đó, nó sẽ hỏi bạn muốn đặt các trường đó trong cột new_fieldsthành gì. Tôi đã phải xóa tất cả các hàng khỏi bảng này để giải quyết vấn đề.

(Tôi biết điều này đã được trả lời cách đây một thời gian, nhưng tôi chỉ gặp sự cố này và đây là giải pháp của tôi. Hy vọng rằng nó sẽ giúp ích cho bất kỳ ai mới gặp vấn đề này)


1
Tôi chưa chèn các hàng vào bảng và vẫn nhận được điều này. Tôi phải xóa tất cả lịch sử di chuyển, xóa bảng di chuyển để thay đổi mô hình, theo đề xuất của Tomasz.
WesternGun

1

Tôi thành thật cho rằng cách tốt nhất để giải quyết vấn đề này là chỉ tạo một mô hình khác với tất cả các trường mà bạn yêu cầu và đặt tên hơi khác một chút. Chạy di chuyển. Xóa mô hình không sử dụng và chạy lại quá trình di chuyển. Thì đấy.


1

Nếu bạn thấy ổn với việc cắt bớt bảng của mô hình được đề cập, bạn có thể chỉ định giá trị mặc định một lần Nonetrong lời nhắc. Việc di chuyển sẽ không cần thiết default=Nonetrong khi mã của bạn không có mặc định. Nó có thể được áp dụng tốt vì không có dữ liệu trong bảng nữa mà sẽ yêu cầu mặc định.


1

Tôi đang ở giai đoạn đầu trong chu kỳ phát triển của mình, vì vậy điều này có thể không hiệu quả với tất cả mọi người (nhưng tôi không hiểu tại sao nó lại không).

Tôi đã thêm blank=True, null=Truevào các cột mà tôi gặp lỗi. Sau đó, tôi chạy python manage.py makemigrationslệnh.

Ngay sau khi chạy lệnh này (và trước khi chạy python manage.py migrate), tôi đã xóa dấu blank=True, null=Truekhỏi tất cả các cột. Sau đó tôi python manage.py makemigrationslại chạy . Tôi được cung cấp một tùy chọn để chỉ tự thay đổi các cột mà tôi đã chọn.

Sau đó, tôi chạy python manage.py migratevà mọi thứ hoạt động tốt!


0

Những gì Django thực sự nói là:

Bảng tệp hồ sơ người dùng có dữ liệu trong đó và có thể có new_fieldgiá trị là null, nhưng tôi không biết, vì vậy bạn có chắc chắn muốn đánh dấu thuộc tính là không thể null không, vì nếu bạn làm vậy, bạn có thể gặp lỗi nếu có giá trị bằng NULL

Nếu bạn chắc chắn rằng không có giá trị nào trong userprofilebảng là NULL - không có giá trị và bỏ qua cảnh báo.

Phương pháp hay nhất trong những trường hợp như vậy là tạo một quá trình di chuyển RunPython để xử lý các giá trị trống như nó nêu trong tùy chọn 2

2) Bỏ qua ngay bây giờ và để tôi tự xử lý các hàng hiện có với NULL (ví dụ: vì bạn đã thêm thao tác RunPython hoặc RunSQL để xử lý các giá trị NULL trong lần di chuyển dữ liệu trước đó)

Trong quá trình di chuyển RunPython, bạn phải tìm tất cả các UserProfiletrường hợp có new_fieldgiá trị trống và đặt một giá trị chính xác ở đó (hoặc một giá trị mặc định do Django yêu cầu bạn đặt trong mô hình). Bạn sẽ nhận được một cái gì đó như thế này:

# 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

Chúc vui vẻ!


Tôi dường như không thể tìm thấy điều này được viết ở đâu trong tài liệu. Bạn có thể đăng liên kết được không
Cody

0

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

Bạn cần thêm một số giá trị làm mặc định.


-1

Nếu SSH nó cung cấp cho bạn 2 tùy chọn, hãy chọn số 1 và đặt "Không có". Chỉ là ... trong lúc này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.