如果 AddField 引用“相同”列,则带有“--fake-initial”的 Django 迁移不起作用

Posted

技术标签:

【中文标题】如果 AddField 引用“相同”列,则带有“--fake-initial”的 Django 迁移不起作用【英文标题】:Django migration with "--fake-initial" is not working if AddField referes to "same" column 【发布时间】:2019-03-05 22:50:38 【问题描述】:

我正在玩 django(我是一个非常新的初学者),在网上冲浪时,我阅读了它可以将我们内部的 camelCase 命名约定保留在 mysql 数据库中,也可以将模型名称保留在模型中。 py

好吧,几天后我可以得出结论,最好保留它们的设计并使用inspectdb 生成的标准输出而不对其代码进行任何更改(我删除了.lower() 函数:-))

无论如何,出于好奇,如果有人能解释我为什么下面的内容不起作用,我将不胜感激。简而言之,在我看来,负责迁移的代码没有正确检查(?)如果列名已经在数据库中,或者至少它以区分大小写的方式进行比较。这是设计的吗?

我正在使用来自互联网https://datascience.blog.wzb.eu/2017/03/21/using-django-with-an-existinglegacy-database/的本指南

mysql 使用选项" --lower-case-table-names=0" 运行,排序规则不区分大小写。

models.py里面我有这个

class City(models.Model):
    id = models.AutoField(db_column='ID', primary_key=True)
    name = models.CharField(db_column='Name', max_length=35)
    countrycode = models.ForeignKey(Country, db_column='CountryCode')
    district = models.CharField(db_column='District', max_length=20)
    population = models.IntegerField(db_column='Population', default=0)

    def __str__(self):
        return self.name

    class Meta:
        managed = True
        db_table = 'city'
        verbose_name_plural = 'Cities'
        ordering = ('name', )

如果我将引用 'db_column' 更改为 db_column='countryCode'(注意较低的 "c" )然后我运行

./manage.py migrate --database world_data --fake-initial worlddata

我收到错误提示“django.db.utils.OperationalError: (1050, "Table 'city' already exists")'

只有使用--fake-initial 选项才会出现问题

在分析“...django/db/migrations/executor.py”后,我发现那些检查列是否已经在现有列中的行

column_names = [
    column.name for column in
    self.connection.introspection.get_table_description(self.co$
]
if field.column not in column_names:
    return False, project_state

据我所知,这里没有区分大小写的比较,因此在"column_names" 中找不到"countryCode" 列:

-> if field.column not in column_names:
(Pdb) field.column
'countryCode'
(Pdb) column_names
['ID', 'Name', 'CountryCode', 'District', 'Population']

【问题讨论】:

【参考方案1】:

首先,我要祝贺您完成第一个问题!许多年长的贡献者没有你那么深入。


所以首先让我们把事情弄清楚。您提到 --lower-case-table-names=0 已启用,但排序规则不区分大小写。 From the docs 我看到该选项强制表名区分大小写。我可能只是读错了,但看起来你说一切都应该不区分大小写。此外,排序规则通常指的是数据本身,而不是列名,以防您不知道。

据我所知,所有数据库都以不区分大小写的方式处理列名(我刚刚在 SQLite 中进行了测试),因此您可能刚刚发现了 Django 中的一个错误!我查看了该文件的历史,在该代码存在的 5 多年中,我想没有人遇到过这个问题。这是可以理解的,因为通常人们要么 a) 让 django 从头开始​​创建数据库,因此一切都是同步的,或者 b) 他们使用 inspectdb 为列生成具有正确大小写的代码。

看起来你只是在玩,所以我认为你不是在寻找特定的解决方案。也许下一步是file a bug ;)?据我所知,在那里添加不区分大小写的比较不会有任何不利之处,但是从事 Django 24/7 工作的人可能会有不同的意见。

【讨论】:

年长的贡献者我猜他们知道他们做什么并且不会像我一样受到impostor syndrome 的影响,所以在询问/发布之前,我会仔细检查并调试所有内容 :-) 我注册了一个帐户并提交了一个ticket@django,让我们看看他们是怎么想的,同时我使用 django 的套管样式作为列和模型。感谢您的回答! 对新用户的另一个提示 - 如果您对答案感到满意,请单击左侧的复选标记。它有助于改善已解决问题与未解决问题的统计数据。

以上是关于如果 AddField 引用“相同”列,则带有“--fake-initial”的 Django 迁移不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如果 char(2) 的列具有两个空格的默认值,则 Linq 引用不返回任何项目

Laravel 8 如果标题相同,则合并 HTML 表格列

Pandas df 操作:如果其他列行重复,则带有值列表的新列 [重复]

如果列有 2 个相同的记录,则选择最新记录

r如果存 在,则更改列名列表

遍历字典列表并 1) 将流值与流列元素进行比较 2) 如果匹配,则附加一个带有数据的新列表