Django不允许我运行迁移,因为check函数检测到对我要添加的新字段的引用

时间:2018-07-18 14:35:18

标签: django django-migrations

我正在为模型添加一个新字段,但无法进行迁移

sqlite3.OperationalError: no such column: main_language.iso639_1

我只能通过注释掉对代码中对新字段的所有引用来生成带有makemigration的迁移文件,但是现在我必须在不将字段注释掉的情况下运行迁移。

这是不可接受的,因为引用我的新字段显然需要最终出现在我的代码中,而其他任何使用最新版本代码库的人在尝试运行迁移时都将获得未注释的代码。

尽管多次向模型中添加新字段,但我没有遇到这个问题,不确定这次为什么会发生这种情况:

# iso639_1 is the new field

class Language(TranslatableMixin, models.Model):
    ENGLISH = 1 # id for English should always be 1
    ISO_HELP_TEXT = _("Please find the correct code at: https://www.loc.gov/standards/iso639-2/php/code_list.php")

    title = models.ForeignKey('main.Sentence', on_delete=models.PROTECT, related_name='LanguageTitle')
    iso639_2 = models.CharField(max_length=8, help_text=ISO_HELP_TEXT)
    iso639_1  = models.CharField(max_length=8, blank=True, default='', help_text=ISO_HELP_TEXT)
    author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    created = models.DateTimeField(auto_now_add=True)
    objects = LanguageManager()

尝试运行“ python manage.py migration”时收到错误:

Traceback (most recent call last):
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 303, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such column: main_language.iso639_1

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\__init__.py", line 371, in execute_from_command_line
    utility.execute()
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\__init__.py", line 365, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\base.py", line 288, in run_from_argv
    self.execute(*args, **cmd_options)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\base.py", line 332, in execute
    self.check()
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\base.py", line 364, in check
    include_deployment_checks=include_deployment_checks,
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\commands\migrate.py", line 58, in _run_checks
    issues.extend(super()._run_checks(**kwargs))
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\management\base.py", line 351, in _run_checks
    return checks.run_checks(**kwargs)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\checks\registry.py", line 73, in run_checks
    new_errors = check(app_configs=app_configs)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\checks\urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\core\checks\urls.py", line 23, in check_resolver
    return check_method()
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\urls\resolvers.py", line 399, in check
    for pattern in self.url_patterns:
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\utils\functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\urls\resolvers.py", line 540, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\utils\functional.py", line 36, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\urls\resolvers.py", line 533, in urlconf_module
    return import_module(self.urlconf_name)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\lang\urls.py", line 3, in <module>
    from lang import views as core_views
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\lang\views.py", line 9, in <module>
    from main.views import background_tasks
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\views\__init__.py", line 1, in <module>
    from .assess import *
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\views\assess.py", line 6, in <module>
    from .main import move_to_next_mode
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\views\main.py", line 4, in <module>
    from main.forms import SignUpCourseForm, SelectClassForm
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\forms.py", line 25, in <module>
    class InviteDetailsForm(forms.Form):
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\forms.py", line 36, in InviteDetailsForm
    label = _('Which language should the invitation email be sent in?'), 
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\forms\fields.py", line 758, in __init__
    self.choices = choices
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\forms\fields.py", line 775, in _set_choices
    value = list(value)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\models\query.py", line 272, in __iter__
    self._fetch_all()
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\models\query.py", line 1179, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\models\query.py", line 53, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\models\sql\compiler.py", line 1068, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\utils.py", line 100, in execute
    return super().execute(sql, params)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\utils.py", line 68, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\utils.py", line 77, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\db\backends\sqlite3\base.py", line 303, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such column: main_language.iso639_1
Finished "C:\Users\Win7\OneDrive\Programming\Git\lang\manage.py migrate" execution.

LanguageManager中存在引发错误的代码。

class LanguageManager(models.Manager):
    def interface_language_choices(self):
        localizations = [x[0] for x in settings.LANGUAGES]
        return Language.objects.filter(iso639_1__in=localizations)

如果我注释掉 def interface_language_choices(self)的主体并替换为 pass ,则会收到与该函数有关的错误,这些错误均未提供返回值。为什么甚至坚持只运行我的代码来进行迁移?

我的迁移文件:

from django.db import migrations, models

def populate_iso(apps, schema_editor):
    Language = apps.get_model('main', 'Language')

    for x in (('eng','en'),('tur','tr'),('rus','ru'),('fra','fr'),('uzb','uz'),('spa','es')):
        L = Language.objects.get(iso639_2=x[0])
        L.iso639_1 = x[1]
        L.save()    


class Migration(migrations.Migration):

    dependencies = [
        ('main', '0030_auto_20180620_1649'),
    ]

    operations = [
        migrations.AddField(
            model_name='language',
            name='iso639_1',
            field=models.CharField(blank=True, default='', help_text='Please find the correct code at: https://www.loc.gov/standards/iso639-2/php/code_list.php', max_length=8),
        ),
        migrations.RunPython(populate_iso),
    ]

1 个答案:

答案 0 :(得分:1)

来自the FineManual

  

更改数据的迁移通常称为“数据迁移”; 最好将它们编写为单独的迁移,与模式迁移并列。

IOW:将您的迁移分为两部分-第一个添加字段,第二个添加相关数据。

但是这实际上不是您的问题。从您的追溯:

  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\forms.py", line 25, in <module>
    class InviteDetailsForm(forms.Form):
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\main\forms.py", line 36, in InviteDetailsForm
    label = _('Which language should the invitation email be sent in?'), 
  File "C:\Users\Win7\OneDrive\Programming\Git\lang\.venv\lib\site-packages\django\forms\fields.py", line 758, in __init__
    self.choices = choices

您的InviteDetailsForm代码显然是在类顶层进行数据库查询 来填充字段的选择-我假设类似:

class InviteDetailsForm(forms.Form):
    # ...
    something = forms.ChoiceField(
        choice= Language.objects.interface_languages_choices()
        # ...
        )

此代码在导入模块时执行(这是正常的Python操作-class是可执行语句),这会导致问题。解决方法是pass the method itself instead of passing it's result

    something = forms.ChoiceField(
        # notice the absence of parens !
        choice= Language.objects.interface_languages_choices, 
        # ...
        )

或者使用ModelChoiceField代替ChoiceField(前者不会强制执行查询集的评估,而后者会强制执行)。

  

为什么甚至要坚持运行我的代码只是为了进行迁移

因为“它”需要加载应用程序和模型以及url conf,这将导入视图,这将导入表单模块,并在您的表单类的顶层执行代码,从而调用您的方法。