Django选择字段意外行为(bug?)

时间:2014-12-01 14:55:12

标签: django

我在使用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管理界面出错。

1 个答案:

答案 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)))