【问题标题】:Django: You are trying to add a non-nullable field 'slug' to post without a default; we can't do thatDjango:您正在尝试添加一个不可为空的字段“slug”以在没有默认值的情况下发布;我们不能那样做
【发布时间】:2021-06-21 08:54:44
【问题描述】:

我正在尝试添加 slug,以便帖子的标题出现在 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)

【问题讨论】:

  • 我现在收到此错误“django.db.utils.IntegrityError: UNIQUE constraint failed: new__blog_post.slug”
  • 这能回答你的问题吗? Updating django models
  • 如何“填充现有行”?这是 Celcuk 答案的第 3 步,因为它已成功迁移,但在删除 'null=True' 后显示相同的错误
  • 您必须输入现有行所需的值,或者可能编写脚本来为您更新值。对于现有行的 slug 应该是什么,没有一个内置的想法。

标签: python django slug


【解决方案1】:

如果此处不允许使用 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 类之前添加此代码(根据您的需要进行调整,特别是确保为每条记录生成唯一值):

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 类中的 operations 列表中:

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

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

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

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

你已经准备好了。现在运行./manage.py migrate 应该会成功。

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

【讨论】:

    【解决方案2】:

    这意味着您尝试在数据库中添加一个新列,但表 Post 中存在另一个旧数据。所以旧数据对于列 slug 没有价值。

    在这种情况下,您需要:

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2021-09-06
          • 2021-11-16
          • 1970-01-01
          • 2016-01-04
          • 2021-08-25
          • 2020-07-12
          • 2020-06-03
          • 1970-01-01
          • 2021-11-10
          相关资源
          最近更新 更多