【问题标题】:How to manage third party app migrations with custom WAGTAILIMAGES_IMAGE_MODEL如何使用自定义 WAGTAILIMAGES_IMAGE_MODEL 管理第三方应用迁移
【发布时间】:2019-04-17 09:30:25
【问题描述】:

情况

我有一个自定义图像和再现模型,并按照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* 迁移分叉了历史

问题

有没有办法克服这个问题?或者推荐的做法?

此时我处于早期测试阶段,因此如果推荐的策略是从一开始就设置它以避免问题,我可以转储整个数据库并重新开始。

感谢大家的帮助!

【问题讨论】:

    标签: wagtail django-migrations


    【解决方案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 自动创建的。 get_image_model_string 需要在影响该 FK 的每个迁移中都像这样使用,通过库的整个迁移历史进行。

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

    它的缺点是需要控制第三方库。对于像puput 这样的项目,我不会屏息以待,要回去更改他们的早期迁移历史以允许可交换的图像模型(puput 的初始迁移硬代码wagtailimages.Image)。但我已经为wagtail_events(我自己的项目)实现了这个功能,以节省其他人的麻烦。

    答案 2 - 如果您无法控制

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

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

    在我的场景中,我获取了 puput 的整个迁移历史并将所有文件复制到一个单独的文件夹 root/custom_puput_migrations/。我设置了

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

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

    ...
    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) 这种方法让您很容易受到开发人员升级库版本要求的影响,而没有意识到他们还必须手动跨迁移文件进行复制。我建议在允许应用程序启动之前检查(确保默认迁移文件夹中的文件数与自定义文件夹中的文件数相同),以确保您的开发和生产数据库都在同一组迁移。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-25
      • 2018-04-19
      • 2022-11-04
      • 1970-01-01
      • 2015-09-12
      • 2021-10-08
      • 2014-05-12
      相关资源
      最近更新 更多