Django:您正试图在没有默认值的情况下将 non-nullable 字段 'slug' 添加到 post;我们不能那样做

Django: You are trying to add a non-nullable field 'slug' to post without a default; we can't do that

我正在尝试添加 slug,以便 post 的标题出现在 url 中,但我在控制台上收到此消息:

You are trying to add a non-nullable field 'slug' to post without a default; we can't do that Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py

models.py

class Post(models.Model):
    
    title = models.CharField(max_length=100)   
    date_posted = models.DateTimeField(default=timezone.now)    
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    slug = models.SlugField(unique=True)

    def save(self, *args, **kwargs):
        self.slug = self.slug or slugify(self.title)
        super().save(*args, **kwargs)

如果此处不允许 null 值,Django 无法自行添加新字段,尤其是当您在此字段上设置了 unique=True 时。要解决该问题,您必须按以下步骤执行:

  1. 添加具有 null=True 或不具有 unique=True 并具有一些默认值的列
  2. 确保数据库中的所有记录都具有唯一值。
  3. 将字段更改为最终状态。

您可以通过 3 次迁移完成所有这些操作。以下是执行此操作的详细步骤。在继续之前,请确保删除之前为解决该问题而尝试创建的所有迁移。您可能必须从能够成功应用它们的环境中撤消这些迁移。

1。添加具有 null=True 或不具有 unique=True 且具有一些默认值

的列

您可以让 Django 为您创建此迁移。只需将您的字段编辑为:

    slug = models.SlugField(unique=True, null=True)

然后 运行 ./manage.py makemigrations 之后

2。确保数据库中的所有记录都具有唯一值。

这一步在一定程度上需要手工制作。首先要求 Django 通过调用 ./manage.py makemigrations YOUR_APP_NAME --empty 为您创建新的空迁移。现在打开这个新的迁移文件并在 Migration class:

之前添加此代码(根据您的需要进行调整,特别是确保为每条记录生成唯一值)
def populate_posts_slug_field(apps, schema_editor):
    for post in apps.get_model('YOUR_APP_NAME.post'):
        post.slug =  # generate a unique value for every post here
        post.save()

现在,添加一个操作,在执行此迁移时将 运行 上面定义的代码。为此,请将此条目添加到迁移的 Migration class 中的 operations 列表中:

migrations.RunPython(populate_posts_slug_field, migrations.RunPython.noop),

RunPython 的第二个参数是一个特殊的函数,它什么都不做,当你想取消应用这个迁移时它会被执行)。

3。将字段更改为最终状态。

这也可以由Django 自己处理。将您的字段更改为最终状态(如您的问题所示)并再次 运行 ./manage.py makemigrations

大功告成。 运行 ./manage.py migrate 现在应该成功了。

注意:可以 运行 在单个迁移文件中执行所有 3 个操作,但应避免这样做。 运行 一次迁移中的数据和架构更改都可能导致某些数据库后端出现问题,因此应完全避免。

这意味着您尝试在数据库中添加一个新列,但是 table Post 中存在另一个旧数据。所以旧数据对列 slug.

没有价值

在这种情况下你需要:

  • 添加null=Trueslug = models.SlugField(unique=True, null=True)
  • 迁移您的数据库 py manage.py makemigrationspy manage.py migrate
  • 为现有行填充 slug 的数据。
  • 删除null=Trueslug = models.SlugField(unique=True)
  • 再次迁移。

尝试转换,转到 models.py 并将“默认”设置为空字符串:

author = models.ForeignKey(User, on_delete=models.CASCADE, default="")

运行 在 shell 上进行迁移。 返回 models.py 并删除默认值。 运行 再次进行迁移。 那应该已经解决了。

如果您不关心您现有的数据,也不关心您的迁移历史,最简单的解决方案是将其全部删除并重新开始。

  1. 删除数据库
  2. 删除您的迁移
  3. 运行 ./manage.py makemigrations
  4. 运行 ./manage.py migrate