【问题标题】:Django South - Create Not Null ForeignKeyDjango South - 创建非空外键
【发布时间】:2013-04-19 01:59:55
【问题描述】:

我有一个模型

class Mystery(models.Model):
    first = models.CharField(max_length=256)
    second = models.CharField(max_length=256)
    third = models.CharField(max_length=256)
    player = models.ForeignKey(Player)

我添加了播放器 ForeignKey,但是当我尝试使用 South 迁移它时,似乎无法使用 null=False 创建它。我有这条消息:

“Mystery.player”字段没有指定默认值,但 非空。由于您要添加此字段,因此您必须指定默认值 用于现有行的值。你愿意:
1. 现在退出,并在models.py中的字段中添加一个默认值
2. 为现有列指定一次性值

我使用这个命令:

manage.py schemamigration myapp --auto

非常感谢!

【问题讨论】:

  • 如果您的数据库已经包含神秘对象,那么南必须知道在player 字段中输入了什么值,因为它不能为空。一种可能的解决方案:选择 2。指定一次性 ...,然后输入 1。因此,您所有现有的神秘对象现在都将指向具有 pk = 1 的 Player。然后您可以在管理员中更改(如果需要)这个。
  • 非常感谢您的帮助!
  • 我把它写成答案

标签: django django-models django-south


【解决方案1】:

这最好在 3 次迁移中完成。

步骤 1. 创建新模型并允许玩家为空:player = models.ForeignKey(Player, null=True)

第 2 步。运行./manage.py schemamigration <app> --auto

第 3 步。运行./manage.py datamigration <app> set_default_players

第 4 步。在<app>/migrations/<number>_set_default_players.py 中向前和向后更新以使用您喜欢的任何逻辑来设置默认播放器。确保每个Mystery 对象都有player 的值。

第 5 步。更新Mystery 模型,使player 具有null=False

第 6 步。运行./manage.py schemamigration <app> --auto

第 7 步。运行./manage.py migrate <app>

【讨论】:

  • 这个答案似乎比公认的要好。我建议的唯一更改是如果意图允许空值,“null=True”应该是“blank=True”。 (直觉?没有。)
  • 你能解释一下你为什么这么想吗? blank 仅影响验证,因此不应在该字段可为空的短暂时间内适用。见docs.djangoproject.com/en/1.8/ref/models/fields/#blank
  • 我的错。再次被严重损坏的 django 文档所吸引。 null=True 是正确的。
【解决方案2】:

另一种选择是在添加 ForeignKey 之前创建一个data migration,您可以在其中创建一个具有特定 id 的新 Player 实例。确保该 ID 以前不存在于您的数据库中。

1.创建数据迁移文件

$ ./manage.py datamigration myapp add_player
Created 00XX_add_player.py

2.编辑文件的forwardsbackwards方法:

def forwards(self, orm):
    orm['myapp.Player'].objects.create(name=u'Very misterious player', id=34)

def backwards(self, orm):
    # Haven't tested this one yet
    orm['myapp.Player'].objects.filter(id=34).delete()

3.将 ForeignKey 添加到您的 Misery 类并再次迁移架构。它将要求您的数据迁移 id 的默认值,在本例中为 34。

 $ ./manage.py schemamigration --auto myapp
 ? The field 'Mistery.player' does not have a default specified, yet is NOT NULL.
 ? Since you are adding this field, you MUST specify a default
 ? value to use for existing rows. Would you like to:
 ?  1. Quit now, and add a default to the field in models.py
 ?  2. Specify a one-off value to use for existing columns now
 ? Please select a choice: 2
 ? Please enter Python code for your one-off default value.
 ? The datetime module is available, so you can do e.g. datetime.date.today()
 >>> 34
 + Added field player on myapp.Mistery
Created 0010_auto__add_field_mistery_player.py. You can now apply this migration with: ./manage.py migrate myapp

4.最后运行 migrate 命令,它将按顺序执行迁移,插入新 Player 并使用对新 Player 的引用更新所有 Mistery 行。

【讨论】:

  • 请不要这样做。将来当其他人运行迁移时,此解决方案很容易咬到您。例如,如果他们已经有一个带有 ID 的对象怎么办?通常,选择任意 ID 并将其放入迁移中可能应该被认为是一种非常糟糕的做法。请参阅我建议的解决方案。
【解决方案3】:

如果您的数据库已经包含神秘对象,那么南必须知道在player 字段中输入了什么值,因为它不能为空。

一种可能的解决方案:

选择

    2. Specify a one-off value to use for existing columns now

然后输入 1。因此,您所有现有的神秘对象现在都将指向 pk = 1 的玩家。然后您可以在管理页面中更改(如果需要)。

【讨论】:

    猜你喜欢
    • 2014-01-17
    • 2012-04-11
    • 2013-04-04
    • 2022-12-09
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    相关资源
    最近更新 更多