为啥 Django makemigrations 每次运行时都会检测到由于 help_text/verbose_name 属性中的重音而导致的更改?

Posted

技术标签:

【中文标题】为啥 Django makemigrations 每次运行时都会检测到由于 help_text/verbose_name 属性中的重音而导致的更改?【英文标题】:Why Django makemigrations detect changes everytime it is run due to accent in help_text/verbose_name attributes?为什么 Django makemigrations 每次运行时都会检测到由于 help_text/verbose_name 属性中的重音而导致的更改? 【发布时间】:2015-12-06 20:05:24 【问题描述】:

我正在使用Python-2.7 并在help_textverbose_name 属性中获得了一个带有法语字符串( 重音)的models.py 文件。

models.py

完成models.py is available as a gist。摘录如下:

# -*- coding: utf-8 -*-

class Checkpoint(models.Model):
    name = models.CharField(max_length=128, help_text=_('Nom du repère/checkpoint'))
    passed = models.BooleanField(default=False, help_text=_('Le checkpoint a t-il était validé?'))
    site = models.ForeignKey('Site', null=True, help_text=_('Entité concernée par le checkpoint'))

    def __unicode__(self):
        return u'%s' % self.name

manage.py makemigrations

每次我运行 ./manage.py makemigrations 时,我都会得到一个 AlterField 用于所有模型字段的重音字符:

    migrations.AlterField(
        model_name='checkpoint',
        name='name',
        field=models.CharField(help_text='Nom du rep\xe8re/checkpoint', max_length=128),
    ),

试用 #1:将 é 和其他替换为反斜杠等效的 \xe9

我明白了:

Traceback (most recent call last):
  File "/home/elopez/apps/pycharm-4.5.2/helpers/pycharm/django_manage.py", line 41, in <module>
    run_module(manage_file, None, '__main__', True)
  File "/usr/lib/python2.7/runpy.py", line 176, in run_module
    fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 82, in _run_module_code
    mod_name, mod_fname, mod_loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/home/elopez/projects/evrpa/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/core/management/commands/makemigrations.py", line 125, in handle
    migration_name=self.migration_name,
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/db/migrations/autodetector.py", line 43, in changes
    changes = self._detect_changes(convert_apps, graph)
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/db/migrations/autodetector.py", line 186, in _detect_changes
    self.generate_altered_fields()
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/db/migrations/autodetector.py", line 850, in generate_altered_fields
    if old_field_dec != new_field_dec:
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/utils/functional.py", line 165, in __eq__
    return self.__cast() == other
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/utils/functional.py", line 151, in __cast
    return self.__bytes_cast()
  File "/home/elopez/.env/evrpa/local/lib/python2.7/site-packages/django/utils/functional.py", line 144, in __bytes_cast
    return bytes(func(*self.__args, **self.__kw))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe8' in position 10: ordinal not in range(128)

试用 #1:将字符串标记为带有 u 前缀的 unicode

给出同样的错误

问题

如何防止 Django 迁移以检测那些误报修改?

【问题讨论】:

【参考方案1】:

建议help_textverbose_name 使用unicode 字符串。

尝试使用 u 前缀将字符串标记为 unicode,然后找到之前将详细名称设置为字节字符串的迁移,并将其也更改为 unicode 字符串。由于编辑 help_textverbose_name 不需要任何架构更改,因此这样做应该是安全的。

    migrations.AddField(
        model_name='datedmodel',
        name='created',
        field=models.DateTimeField(default=datetime.datetime(2015, 9, 10, 14, 8, 23, 349990, tzinfo=utc), verbose_name='Créé le', auto_now_add=True),
        preserve_default=False,
    ),

迁移文件中不需要 u'' 前缀,因为它有 from __future__ import unicode_literals

然后,当您重新运行 makemigrations 时,Django 会很有希望地说“未检测到更改”。

【讨论】:

help_textverbose_name 前缀+编辑迁移都没有解决问题 我仍然认为将help_textverbose_name 名称切换到unicode 是正确的方法。看看 Django 应用程序,例如auth models。他们使用from __future__ import unicode_literals,因此所有帮助字符串和详细名称都是unicode。必须将encode('utf-8') 添加到您的字符串中感觉非常脆弱。仅仅因为它没有解决您的问题而拒绝我的回答不会鼓励我再为您提供帮助。希望你能解决你的问题。 您编辑了问题以关注verbose_name,而忽略了我的问题在于help_text这一事实。无论如何,我承认-1 有点苛刻,但你最后的评论比你的回答更有意义 我编辑了这个问题,因为你最初的问题中的代码根本没有使用 help_text,它不是为了冒犯你。 在顶部添加from __future__ import unicode_literals UnicodeEncodeError: 'ascii' codec can't encode character u'\xe8' in position 10: ordinal not in range(128) makemigrations【参考方案2】:

附加.encode('utf-8') 可以防止错误,但makemigrations 仍然会在每次运行时检测到更改

class Checkpoint(models.Model):
    name = models.CharField(max_length=128, help_text=_('Nom du repère/checkpoint'.encode('utf-8')))
    passed = models.BooleanField(default=False, help_text=_('Le checkpoint a t-il était validé?'.encode('utf-8')))
    site = models.ForeignKey('Site', null=True, help_text=_('Entité concernée par le checkpoint'.encode('utf-8')))

【讨论】:

以上是关于为啥 Django makemigrations 每次运行时都会检测到由于 help_text/verbose_name 属性中的重音而导致的更改?的主要内容,如果未能解决你的问题,请参考以下文章

Django:啥时候运行makemigrations?

Django 1.7 - makemigrations 为非托管模型创建迁移

Django 1.8 - migrate 和 makemigrations 有啥区别?

Django 1.7 makemigrations 没有效果

Django Makemigrations 和 Migrate 不断重复

Django 上的 MakeMigration 错误 - ImportError:无法从“django.db.models”导入名称“FieldDoesNotExist”