如何使用自定义WAGTAILIMAGES_IMAGE_MODEL管理第三方应用程序迁移

时间:2019-04-17 09:30:25

标签: wagtail django-migrations

情况

我有一个自定义图像和渲染模型,并遵循the wagtail v2.4 guide来实现它们:

class AccreditedImage(AbstractImage):
    """
    AccreditedImage - Customised image model with optional caption and accreditation
    """
    caption = models.CharField(max_length=255, blank=True)
    accreditation = models.CharField(max_length=255, blank=True, null=True)
    admin_form_fields = Image.admin_form_fields + (
        'caption',
        'accreditation',
    )

    class Meta:
        verbose_name = 'Accredited image'
        verbose_name_plural = 'Accredited images'

    def __str__(self):
        credit = ' ({})'.format(self.accreditation) if (self.accreditation is not None) and (len(self.accreditation) > 0) else ''
        return '{}{}'.format(self.title, credit)


class AccreditedRendition(AbstractRendition):
    """
    AccreditedRendition - stores renditions for the AccreditedImage model
    """
    image = models.ForeignKey(AccreditedImage, on_delete=models.CASCADE, related_name='renditions')

    class Meta:
        unique_together = (('image', 'filter_spec', 'focal_point_key'),)
        verbose_name = 'Accredited Image Rendition'
        verbose_name_plural = 'Accredited Image Renditions'

settings中,我有:

WAGTAILIMAGES_IMAGE_MODEL = 'cms.AccreditedImage'

但是,我安装了两个第三方插件:puputwagtail_events,每个插件都使用外键来编辑图像。

当我运行`manage.py makemigrations时,会在puput和wagtail_events site_packages文件夹中创建其他迁移,以处理FK中的更改。迁移看起来像这样:

from django.db import migrations, models
import django.db.models.deletion

class Migration(migrations.Migration):

    dependencies = [
        ('puput', '0005_blogpage_main_color'),
    ]

    operations = [
        migrations.AlterField(
            model_name='blogpage',
            name='header_image',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='cms.AccreditedImage', verbose_name='Header image'),
        ),
        migrations.AlterField(
            model_name='entrypage',
            name='header_image',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='cms.AccreditedImage', verbose_name='Header image'),
        ),
    ]

问题

如果我实际应用了这些迁移,则puput或wagtail_events会发布新版本,那么迁移历史记录将被破坏-例如我在puput上自动生成的0006 *迁移及其新的0006 *迁移产生了历史

问题

有办法克服吗?还是推荐的操作方法?

这时我还处于测试阶段,因此,如果建议的策略是从一开始就进行设置以避免问题,那么我可以转储整个数据库并重新开始。

谢谢大家!

1 个答案:

答案 0 :(得分:1)

答案1-如果您可以控制第三方库

第三方库中的初始迁移应定义可交换的依赖关系,例如:     从wagtail.images导入get_image_model_string

dependencies = [
    migrations.swappable_dependency(get_image_model_string()),
]
operations = [
    migrations.CreateModel(
        name='ThirdPartyModel',
        fields=[
            ...
            ('image', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, to=get_image_model_string())),
        ],
        ...
    ),

makemigrations不会自动创建。通过库的整个迁移历史记录,在影响FK的每次迁移中都需要这样使用get_image_model_string

如果您在项目中的某个位置更改设置,您仍然需要进行数据迁移('Migrate an existing swappable dependency'可能会有所帮助),但这可以解决上述从头开始的分叉问题。

它的缺点是需要控制第三方库。我没有屏息等待像puput这样的项目返回并更改其早期迁移历史,以允许使用可交换的映像模型(puput的初始迁移硬代码wagtailimages.Image)。但是我已经为wagtail_events(我自己的项目)实施了此操作,以免给其他人带来麻烦。

答案2-如果您没有控制权

U。我已经做了一段时间了,所有候选解决方案都非常糟糕。我考虑过让我的自定义图像类通过db_table meta属性来模拟wagtail.images.model.Image,甚至通过创建另一个本质上是复制w图像的应用程序。这要么是很多工作,要么是超级骇客。

我选择使用MIGRATION_MODULES设置手动接管迁移。

对于我的情况,我已获取了puput的整个迁移历史记录,并将所有文件复制到了单独的文件夹root/custom_puput_migrations/中。我设置

MIGRATION_MODULES = {
    'puput': 'custom_puput_migrations'
}
WAGTAILIMAGES_IMAGE_MODEL = 'otherapp.AccreditedImage'

然后,我通过编辑该文件夹中的0001_initial.py来拉动所有开关,以通过设置而不是通过硬编码来引用模型:

...
from wagtail.images import get_image_model_string

class Migration(migrations.Migration):

    dependencies = [
        ...
        migrations.swappable_dependency(get_image_model_string())
    ]

    operations = [
        migrations.CreateModel(
            name='BlogPage',
            fields=[
                ...
                ('header_image', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, verbose_name='Header image', blank=True, to=get_image_model_string(), null=True)),
            ],
     ...

缺点

1)创建的实际表关系不是严格由迁移文件确定的,而是由可以独立更改的设置确定的。如果您希望避免这种情况,可以直接在自定义迁移中对引用的模型进行硬编码。

2)这种方法使您很容易受到开发人员升级库版本要求的困扰,而没有意识到他们还必须跨迁移文件手动复制。我建议在允许应用启动之前进行检查(f / ex确保默认迁移文件夹中的文件数量与自定义文件夹中的文件数量相同),以确保开发和生产数据库全部在同一组迁移。