【问题标题】:How to fix error upgrading Wagtail 2.10.2 to 2.11.8?如何修复将 Wagtail 2.10.2 升级到 2.11.8 的错误?
【发布时间】:2021-06-24 13:39:56
【问题描述】:

我一直在从 Wagtail v1.13 / Django v1.11 / Python 3.5.2 升级以更新项目。

一切都很顺利我现在在 Wagtail 2.10.2 / Django 3.0.14 / Python 3.8.9

该项目使用 puput,所以在 puput 支持更新版本的 Django 之前,不能超越 Django 3.0.14。这不是问题,我现在对此很满意。

但是在安装 Wagtail 2.11.8 后,当我运行 makemigrations 时,我收到以下错误:

AttributeError: module 'wagtail.core.models' has no attribute 'MultiTableCopyMixin'

Wagtail 2.10.2/Django 3.0.14 组合创建了 0038_auto_20210624_0634.py,其中包含以下行:

bases=(wagtail.core.models.MultiTableCopyMixin, models.Model),

Wagtail 2.10.2 中果然存在 wagtail.core.models.MultiTableCopyMixin,但是在 Wagtail 2.11.* MultiTableCopyMixin 已经被移除了。

我也尝试将 Django 保持在 2.2.24 版本,但仍然遇到同样的问题。

有什么想法吗?

下面自动生成的迁移的完整内容,请参见操作数组的第二个条目:

# Generated by Django 2.2.24 on 2021-06-24 14:07

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields
import wagtail.core.models


class Migration(migrations.Migration):

    dependencies = [
        ('contenttypes', '0002_remove_content_type_name'),
        ('auth', '0011_update_proxy_permissions'),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('wagtailcore', '0037_auto_20210624_0316'),
    ]

    operations = [
        migrations.CreateModel(
            name='Task',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=255, verbose_name='name')),
                ('active', models.BooleanField(default=True, help_text='Active tasks can be added to workflows. Deactivating a task does not remove it from existing workflows.', verbose_name='active')),
                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wagtail_tasks', to='contenttypes.ContentType', verbose_name='content type')),
            ],
            options={
                'verbose_name': 'task',
                'verbose_name_plural': 'tasks',
            },
        ),
        migrations.CreateModel(
            name='TaskState',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('status', models.CharField(choices=[('in_progress', 'In progress'), ('approved', 'Approved'), ('rejected', 'Rejected'), ('skipped', 'Skipped'), ('cancelled', 'Cancelled')], default='in_progress', max_length=50, verbose_name='status')),
                ('started_at', models.DateTimeField(auto_now_add=True, verbose_name='started at')),
                ('finished_at', models.DateTimeField(blank=True, null=True, verbose_name='finished at')),
                ('comment', models.TextField(blank=True)),
                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wagtail_task_states', to='contenttypes.ContentType', verbose_name='content type')),
                ('finished_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='finished_task_states', to=settings.AUTH_USER_MODEL, verbose_name='finished by')),
                ('page_revision', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_states', to='wagtailcore.PageRevision', verbose_name='page revision')),
                ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_states', to='wagtailcore.Task', verbose_name='task')),
            ],
            options={
                'verbose_name': 'Task state',
                'verbose_name_plural': 'Task states',
            },
            bases=(wagtail.core.models.MultiTableCopyMixin, models.Model),
        ),
        migrations.CreateModel(
            name='Workflow',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=255, verbose_name='name')),
                ('active', models.BooleanField(default=True, help_text='Active workflows can be added to pages. Deactivating a workflow does not remove it from existing pages.', verbose_name='active')),
            ],
            options={
                'verbose_name': 'workflow',
                'verbose_name_plural': 'workflows',
            },
        ),
        migrations.AlterField(
            model_name='site',
            name='site_name',
            field=models.CharField(blank=True, default='Default', help_text='Human-readable name for the site.', max_length=255, verbose_name='site name'),
            preserve_default=False,
        ),
        migrations.CreateModel(
            name='GroupApprovalTask',
            fields=[
                ('task_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Task')),
            ],
            options={
                'verbose_name': 'Group approval task',
                'verbose_name_plural': 'Group approval tasks',
            },
            bases=('wagtailcore.task',),
        ),
        migrations.CreateModel(
            name='WorkflowState',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('status', models.CharField(choices=[('in_progress', 'In progress'), ('approved', 'Approved'), ('needs_changes', 'Needs changes'), ('cancelled', 'Cancelled')], default='in_progress', max_length=50, verbose_name='status')),
                ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
                ('current_task_state', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wagtailcore.TaskState', verbose_name='current task state')),
                ('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workflow_states', to='wagtailcore.Page', verbose_name='page')),
                ('requested_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='requested_workflows', to=settings.AUTH_USER_MODEL, verbose_name='requested by')),
                ('workflow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workflow_states', to='wagtailcore.Workflow', verbose_name='workflow')),
            ],
            options={
                'verbose_name': 'Workflow state',
                'verbose_name_plural': 'Workflow states',
            },
        ),
        migrations.CreateModel(
            name='WorkflowPage',
            fields=[
                ('page', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='wagtailcore.Page', verbose_name='page')),
                ('workflow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workflow_pages', to='wagtailcore.Workflow', verbose_name='workflow')),
            ],
            options={
                'verbose_name': 'workflow page',
                'verbose_name_plural': 'workflow pages',
            },
        ),
        migrations.AddField(
            model_name='taskstate',
            name='workflow_state',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='task_states', to='wagtailcore.WorkflowState', verbose_name='workflow state'),
        ),
        migrations.CreateModel(
            name='PageLogEntry',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('label', models.TextField()),
                ('action', models.CharField(blank=True, db_index=True, max_length=255)),
                ('data_json', models.TextField(blank=True)),
                ('timestamp', models.DateTimeField(verbose_name='timestamp (UTC)')),
                ('content_changed', models.BooleanField(db_index=True, default=False)),
                ('deleted', models.BooleanField(default=False)),
                ('content_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='contenttypes.ContentType', verbose_name='content type')),
                ('page', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='wagtailcore.Page')),
                ('revision', models.ForeignKey(db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='wagtailcore.PageRevision')),
                ('user', models.ForeignKey(db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'verbose_name': 'page log entry',
                'verbose_name_plural': 'page log entries',
                'ordering': ['-timestamp', '-id'],
            },
        ),
        migrations.CreateModel(
            name='WorkflowTask',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
                ('task', models.ForeignKey(limit_choices_to={'active': True}, on_delete=django.db.models.deletion.CASCADE, related_name='workflow_tasks', to='wagtailcore.Task', verbose_name='task')),
                ('workflow', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='workflow_tasks', to='wagtailcore.Workflow', verbose_name='workflow_tasks')),
            ],
            options={
                'verbose_name': 'workflow task order',
                'verbose_name_plural': 'workflow task orders',
                'ordering': ['sort_order'],
                'abstract': False,
                'unique_together': {('workflow', 'task')},
            },
        ),
        migrations.AddConstraint(
            model_name='workflowstate',
            constraint=models.UniqueConstraint(condition=models.Q(('status', 'in_progress'), ('status', 'needs_changes'), _connector='OR'), fields=('page',), name='unique_in_progress_workflow'),
        ),
        migrations.AddField(
            model_name='groupapprovaltask',
            name='groups',
            field=models.ManyToManyField(help_text='Pages at this step in a workflow will be moderated or approved by these groups of users', to='auth.Group', verbose_name='groups'),
        ),
    ]

showmigrations 的输出如下,在 Wagtail 2.10.2 上运行,尝试在 2.11.8 上运行会抛出与之前相同的错误:

admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
home
 [X] 0001_initial
 [X] 0002_contentpage
 [X] 0003_auto_20170427_1205
 [X] 0004_auto_20170427_1210
 [X] 0005_auto_20170427_1214
 [X] 0006_auto_20170427_1215
 [X] 0007_auto_20170427_1216
 [X] 0008_auto_20170430_0530
 [X] 0009_auto_20170430_0551
 [X] 0010_auto_20170430_0639
 [X] 0011_auto_20170430_0642
 [X] 0012_auto_20170501_1035
 [X] 0013_auto_20170501_1046
 [X] 0014_auto_20170501_1055
 [X] 0015_auto_20170501_1101
 [X] 0016_auto_20170501_1103
 [X] 0017_auto_20170501_1106
 [X] 0018_auto_20170501_2305
 [X] 0019_auto_20170501_2325
 [X] 0020_auto_20170501_2350
 [X] 0021_auto_20170501_2354
 [X] 0022_auto_20170502_0000
 [X] 0023_auto_20170502_0012
 [X] 0024_auto_20170502_0030
 [X] 0025_auto_20170502_0054
 [X] 0026_auto_20170502_0237
 [X] 0027_auto_20170502_0524
 [X] 0028_auto_20170502_0853
 [X] 0029_auto_20170502_0856
 [X] 0030_auto_20170511_0012
 [X] 0031_auto_20170511_0017
 [X] 0032_auto_20170511_0021
 [X] 0033_auto_20170511_0023
 [X] 0034_auto_20170511_0025
 [X] 0035_auto_20170511_0027
 [X] 0036_auto_20170511_0030
 [X] 0037_auto_20170511_0032
 [X] 0038_auto_20170511_0034
 [X] 0039_auto_20170511_0035
 [X] 0040_auto_20170511_0037
 [X] 0041_auto_20170511_0039
 [X] 0042_auto_20170511_0045
 [X] 0043_auto_20170511_0048
 [X] 0044_auto_20170511_0054
 [X] 0045_auto_20170511_0056
 [X] 0046_auto_20170511_0105
 [X] 0047_auto_20170511_0106
 [X] 0048_auto_20170511_0111
 [X] 0049_auto_20170511_0113
 [X] 0050_auto_20170511_0114
 [X] 0051_auto_20170513_0708
 [X] 0052_auto_20170513_0709
 [X] 0053_auto_20170515_2351
 [X] 0054_auto_20170516_0021
 [X] 0055_auto_20170516_0344
 [X] 0056_contactpage
 [X] 0057_auto_20170719_1137
 [X] 0058_auto_20170824_0004
 [X] 0059_auto_20170824_0014
 [X] 0060_auto_20171016_0146
 [X] 0061_auto_20171120_0657
 [X] 0062_auto_20171120_0709
 [X] 0063_auto_20171120_0711
 [X] 0064_auto_20171120_0719
 [X] 0065_auto_20171120_0720
 [X] 0066_auto_20171120_0725
 [X] 0067_auto_20171126_0205
 [X] 0068_auto_20171127_2239
 [X] 0069_auto_20171207_0317
 [X] 0070_auto_20180122_0204
 [X] 0071_auto_20180204_2258
 [X] 0072_auto_20180204_2306
 [X] 0073_donatepage
 [X] 0074_contact2page
 [X] 0075_auto_20180705_0128
 [X] 0076_auto_20190926_1406
 [X] 0077_auto_20190926_1557
 [X] 0078_auto_20191001_0448
 [X] 0079_auto_20191003_1227
 [X] 0080_auto_20200211_1115
 [X] 0081_auto_20210217_1427
 [X] 0082_contentholdercategory_contentholderdetailpage_contentholderlistingpage
 [X] 0083_contentholderdetailpage_show_categories
 [X] 0084_auto_20210310_0455
 [X] 0085_contentholderlistingpage_body2
 [X] 0086_flexiblecontactpage
 [X] 0087_auto_20210501_0155
 [X] 0088_auto_20210503_1053
 [X] 0089_auto_20210503_1123
 [X] 0090_auto_20210511_1644
 [X] 0091_auto_20210511_1656
 [X] 0092_auto_20210519_1637
 [X] 0093_auto_20210525_0709
 [X] 0094_footersettings
 [X] 0095_auto_20210607_1158
 [X] 0096_auto_20210623_0242
leads
 [X] 0001_initial
 [X] 0002_auto_20170524_0535
 [X] 0003_auto_20170525_0041
 [X] 0004_auto_20170525_0131
 [X] 0005_auto_20170525_0142
 [X] 0006_auto_20170525_0326
 [X] 0007_leaddb_referer
 [X] 0008_auto_20170525_0851
 [X] 0009_auto_20170526_0230
 [X] 0010_auto_20170526_0232
 [X] 0011_auto_20170526_0313
 [X] 0012_auto_20170526_0321
 [X] 0013_auto_20170526_0324
 [X] 0014_auto_20180322_0049
 [X] 0015_auto_20180713_0351
 [X] 0016_auto_20180713_0357
 [X] 0017_auto_20180713_0708
 [X] 0018_auto_20180713_0715
 [X] 0019_auto_20180713_0754
 [X] 0020_auto_20180713_0803
 [X] 0021_auto_20180713_0804
 [X] 0022_leaddb_other
 [X] 0023_auto_20180720_0341
 [X] 0024_auto_20180724_0224
 [X] 0025_auto_20190717_1540
 [X] 0026_auto_20190717_1616
 [X] 0027_auto_20190717_1618
 [X] 0028_auto_20190718_1533
 [X] 0029_auto_20190721_1146
 [X] 0030_auto_20190924_1501
 [X] 0031_auto_20210217_1427
 [X] 0032_flexibleleaddb
 [X] 0033_auto_20210519_1637
 [X] 0034_auto_20210621_1407
 [X] 0035_auto_20210621_1534
postgres_search
 [X] 0001_initial
 [X] 0002_add_autocomplete
 [X] 0003_title
puput
 [X] 0001_initial
 [X] 0002_blogpage_short_feed_description
 [X] 0003_remove_blogpage_short_feed_description
 [X] 0004_blogpage_short_feed_description
 [X] 0005_auto_20210620_1525
sessions
 [X] 0001_initial
sites
 [X] 0001_initial
 [X] 0002_alter_domain_unique
taggit
 [X] 0001_initial
 [X] 0002_auto_20150616_2121
 [X] 0003_taggeditem_add_unique_index
wagtailadmin
 [X] 0001_create_admin_access_permissions
wagtailcore
 [X] 0001_squashed_0016_change_page_url_path_to_text_field (16 squashed migrations)
 [X] 0017_change_edit_page_permission_description
 [X] 0018_pagerevision_submitted_for_moderation_index
 [X] 0019_verbose_names_cleanup
 [X] 0020_add_index_on_page_first_published_at
 [X] 0021_capitalizeverbose
 [X] 0022_add_site_name
 [X] 0023_alter_page_revision_on_delete_behaviour
 [X] 0024_collection
 [X] 0025_collection_initial_data
 [X] 0026_group_collection_permission
 [X] 0027_fix_collection_path_collation
 [X] 0024_alter_page_content_type_on_delete_behaviour
 [X] 0028_merge
 [X] 0029_unicode_slugfield_dj19
 [X] 0030_index_on_pagerevision_created_at
 [X] 0031_add_page_view_restriction_types
 [X] 0032_add_bulk_delete_page_permission
 [X] 0033_auto_20170401_0651
 [X] 0034_auto_20170510_0533
 [X] 0035_auto_20170822_1810
 [X] 0036_auto_20210624_0046
 [X] 0037_auto_20210624_0316
 [X] 0038_auto_20210624_0634
wagtaildocs
 [X] 0001_initial
 [X] 0002_initial_data
 [X] 0003_add_verbose_names
 [X] 0004_capitalizeverbose
 [X] 0005_document_collection
 [X] 0006_copy_document_permissions_to_collections
 [X] 0005_alter_uploaded_by_user_on_delete_action
 [X] 0007_merge
 [X] 0008_document_file_size
 [X] 0009_document_verbose_name_plural
 [X] 0010_document_file_hash
wagtailembeds
 [X] 0001_initial
 [X] 0002_add_verbose_names
 [X] 0003_capitalizeverbose
 [X] 0004_embed_verbose_name_plural
 [X] 0005_specify_thumbnail_url_max_length
wagtailforms
 [X] 0001_initial
 [X] 0002_add_verbose_names
 [X] 0003_capitalizeverbose
 [X] 0004_add_verbose_name_plural
wagtailimages
 [X] 0001_squashed_0021 (21 squashed migrations)
 [X] 0022_uploadedimage
wagtailmenus
 [X] 0001_initial
 [X] 0002_auto_20160129_0901
 [X] 0003_auto_20160129_2339
 [X] 0004_auto_20160130_0024
 [X] 0005_auto_20160130_2209
 [X] 0006_auto_20160131_1347
 [X] 0007_auto_20160131_2000
 [X] 0008_auto_20160131_2327
 [X] 0009_auto_20160201_0859
 [X] 0010_auto_20160201_1558
 [X] 0011_auto_20160415_1519
 [X] 0012_auto_20160419_0039
 [X] 0013_auto_20160423_1124
 [X] 0014_auto_20160423_1339
 [X] 0015_auto_20160423_1348
 [X] 0016_auto_20160930_0645
 [X] 0017_auto_20161013_1658
 [X] 0018_auto_20161204_2043
 [X] 0019_auto_20161204_2143
 [X] 0020_auto_20161210_0004
 [X] 0021_auto_20170106_2352
 [X] 0022_auto_20170913_2125
 [X] 0023_remove_use_specific
wagtailmetadata
 [X] 0001_initial
 [X] 0002_auto_20160607_2150
 [X] 0003_auto_20160909_1000
 [X] 0004_remove_sitemetadatapreferences
 [X] 0005_metadatasettings
 [X] 0006_drop_metadatasettings
wagtailredirects
 [X] 0001_initial
 [X] 0002_add_verbose_names
 [X] 0003_make_site_field_editable
 [X] 0004_set_unique_on_path_and_site
 [X] 0005_capitalizeverbose
 [X] 0006_redirect_increase_max_length
wagtailsearch
 [X] 0001_initial
 [X] 0002_add_verbose_names
 [X] 0003_remove_editors_pick
 [X] 0004_querydailyhits_verbose_name_plural
wagtailusers
 [X] 0001_initial
 [X] 0002_add_verbose_name_on_userprofile
 [X] 0003_add_verbose_names
 [X] 0004_capitalizeverbose
 [X] 0005_make_related_name_wagtail_specific
 [X] 0006_userprofile_prefered_language
 [X] 0007_userprofile_current_time_zone
 [X] 0008_userprofile_avatar
 [X] 0009_userprofile_verbose_name_plural

在看到最新版本的 wagtail 没有 'bases' 行后,我发现如果我在添加到我的项目中的 wagtailcore_migrations 中注释掉 bases 行,错误就会消失。

但我随后被问到:

You are trying to add a non-nullable field 'locale' to page without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py

当我选择 1 时,我得到:

Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now

我尝试输入“en-us”和 timezone.now。但是我在运行 migrate 时总是出错:

TypeError: Field 'id' expected a number but got...

后跟

  • 当我输入'en-us'时'en-us'
  • datetime.datetime 当我进入 timezone.now 时

我在这里放什么?

我认为它不是在创建 Locale 数据库表。

我注意到它在 home/wagtailcore_migrations 中创建文件,这些文件主要复制 site-packages/wagtail/core/migrations 中的文件。怎么会这样?

【问题讨论】:

  • 您能否分享完整的0038_auto_20210624_0634.py(或至少有足够的上下文来查看bases 选项定义在哪个类/模型上)?
  • 按要求添加了完整的 0038_auto_20210624_0634.py。
  • 啊 - 这是在 wagtailcore 内部创建的迁移?这不应该发生——除了 Wagtail 包本身包含的迁移之外,wagtailcore 永远不应该进行迁移,否则您将遇到迁移历史的一致性问题。我怀疑这是一个 Puput 错误...
  • 是的,从 wagtail 核心内部自动生成。我检查过,它来自 /wagtail/core/migrations/0047_add_workflow_models.py 中的 wagtail 分布。
  • 我不确定您是如何最终得到一个与 the same table creations as Wagtail's own migrations 重复的自动生成迁移,除非您之前曾使用过该迁移文件夹来解决早期的迁移冲突 - 其中如果问题可以追溯到更远的地方,这可能会变得非常棘手。你能分享一下运行./manage.py showmigrations的输出吗?

标签: django wagtail


【解决方案1】:

这个问题的根本原因可以追溯到 2017 年,当时您的项目在 Wagtail 1.9 上,并且您项目中的某些东西 - 很可能是 this Puput bug - 在 wagtailcore 中生成了虚假的 0033_auto_20170401_0651 迁移。

由于某种原因,这种迁移的存在阻止了 Django 看到 wagtailcore 中的后续迁移,这些迁移在后来的 Wagtail 版本中提供。 (这不是我期望发生的事情:我希望它注意到存在多个迁移 0033s 没有共享历史记录,并因迁移冲突而失败。)相反,运行 @987654324 @ 导致自动生成额外的迁移,复制通常由 Wagtail 提供的迁移处理的架构更改。这是一件坏事,有几个原因:

  • Wagtail 自己的迁移包括一些自动生成的迁移不会复制的数据迁移。 (例如,Wagtail 1.12 引入了一个“草稿标题”字段,并从主标题字段填充此字段;由于您的版本中错过了后一步,您最终可能会在管理员中出现带有空白标题的页面。 )
  • 如果您曾经在新环境中安装项目并在此时执行 Wagtail 包的全新安装,您现有的代码库和数据库将包含对该环境中不存在的自动生成迁移的引用,这将导致./manage.py migrate 的一致性错误。

由于这是一个可以追溯到多年前的根深蒂固的问题,它可能对您的项目产生了连锁反应,但在这里并不明显,我不能保证 100% 可靠的步骤来解决这个问题,但以下应该让你走上正轨。我建议备份您的数据库并保存自动生成的 wagtailcore 迁移的副本(在您的代码库之外它们不会干扰的地方),如果可能的话,从您的代码库/数据库版本开始这些步骤Wagtail 1.13,在您开始当前升级之前。 (如上所述,问题甚至在此之前就开始了,但是这样您的迁移就不会走“错误的道路”那么远。)

  • 在您的项目代码库中搜索您自己的应用程序中引用自动生成的迁移 0033_auto_20170401_06510034_auto_20170510_05330035_auto_20170822_18100036_auto_20210624_00460037_auto_20210624_03160038_auto_20210624_0634 的任何迁移 - 例如:

    dependencies = [
        ('home', '0123_some_other_migration'),
        ('wagtailcore', '0034_auto_20170510_0533'),  # <- change this line
    ]
    

    将这些更改为'0032_add_bulk_delete_page_permission' - 这样,您指定这些迁移应在 Wagtail 1.9 的最后一次“真正”迁移之后运行,但不依赖于自动生成的迁移,从而可以回滚自动生成的迁移迁移而不会还原您自己的项目迁移并可能丢失数据。

  • 运行./manage.py migrate wagtailcore 0032 - 这应该会显示自动生成的 wagtailcore 迁移正在回滚,没有别的。

  • 使用pip uninstall wagtail 卸载 Wagtail 包,然后重新安装您拥有的相同版本 - 这应该会删除自动生成的迁移。仔细检查pip 的输出 - 它可能会停止并提示您自动生成的迁移文件将被留下,如果是这样,请退出,手动删除这些文件,然后重试卸载命令。

  • 运行 ./manage.py migrate - 希望现在应该应用来自 wagtailcore 的真正迁移,而不是自动生成的迁移。

  • 像以前一样运行 Wagtail 升级序列,一次升级一个版本,然后在每个版本之后运行 ./manage.py makemigrations./manage.py migrate。如果一切正常,makemigrations 不应在任何时候在 wagtailcore(或任何其他 Wagtail 自己的应用程序)中创建任何迁移。

【讨论】:

    猜你喜欢
    • 2021-03-21
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 2019-09-20
    • 2023-04-01
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多