我在使用Django 1.7进行迁移时遇到了一些奇怪的行为。这是一个应该报告的合法错误吗?
总结:我使用了模块级CHOICE字段,我最初在一个Model类中引用了该字段。接下来我做了一些修改,并在另一个Model类中引用了CHOICE集。在迁移中,这不仅导致添加新字段,而且还导致更改现有字段,从而不再引用CHOICE集。
解决此问题的唯一方法是添加一个重复的CHOICE集(使用不同的名称)并引用相应模型中的不同CHOICE集。
初始代码:
GRADE_CHOICES = zip(range(1, 7), range(1, 7))
# grade 1 to 6
class ModelA(models.Model):
name = models.CharField(max_length=50)
class ModelB(models.Model):
name = models.CharField(max_length=10)
grade = models.IntegerField(choices=GRADE_CHOICES)
这可以按预期工作。接下来的模型改动:
GRADE_CHOICES = zip(range(1, 7), range(1, 7))
class ModelA(models.Model):
name = models.CharField(max_length=50)
grade = models.IntegerField(choices=GRADE_CHOICES)
# ^ this line is added
class ModelB(models.Model):
name = models.CharField(max_length=10)
grade = models.IntegerField(choices=GRADE_CHOICES)
生成的迁移将字段和选项添加到ModelA(如预期的那样),但是从ModelB中删除选项,将其减少为仅仅IntegerField。这是解决这个问题的唯一方法。
GRADE_CHOICES = zip(range(1, 7), range(1, 7))
GRADE_CHOICES_DUPLICATE = zip(range(1, 7), range(1, 7))
# Do Repeat Yourself
class ModelA(models.Model):
name = models.CharField(max_length=50)
grade = models.IntegerField(choices=GRADE_CHOICES)
# ^ this line is added
class ModelB(models.Model):
name = models.CharField(max_length=10)
grade = models.IntegerField(choices=GRADE_CHOICES_DUPLICATE)
所以问题是:这种行为是否出乎意料。有人想尝试复制这个吗?
另外编辑: 选择集的丢失在迁移中反映如下:
operations = [
migrations.AddField(
model_name='modelA',
name='grade',
field=models.IntegerField(choices=[(1, 1), (2, 2), (3, 3) ]),
),
migrations.AlterField(
model_name='modelB',
name='grade',
field=models.IntegerField(),
),
]
违规部分是AlterField部分,现在省略了选项。我知道数据库没有什么不同,但它确实导致Django管理界面出错。
答案 0 :(得分:2)
如果你正在使用Python 3,那么zip
会返回一个迭代器。
>>> GRADE_CHOICES = zip(range(1, 7), range(1, 7))
>>> print(GRADE_CHOICES)
<zip object at 0x7fd0dffd8308>
第一次使用迭代器(例如在您的第一个模型中,或通过调用列表在shell中),您将获得预期的结果。第二次使用迭代器时,会得到一个空列表。
>>> print(list(GRADE_CHOICES))
[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
>>> print(list(GRADE_CHOICES))
[]
您可以通过在模型中将GRADE_CHOICES列为一个列表来解决此问题。
GRADE_CHOICES = list(zip(range(1, 7), range(1, 7)))