Как управлять миграциями сторонних приложений с помощью пользовательского WAGTAILIMAGES_IMAGE_MODEL - PullRequest
1 голос
/ 17 апреля 2019

Ситуация

У меня есть пользовательское изображение и модель воспроизведения, и я следую руководству по трясогузке v2.4 , чтобы реализовать их:

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'

Но у меня установлены два плагина сторонних производителей: puput и wagtail_events , каждый из которых использует внешний ключ для изображений трясогузки.

Когда я запускаю makemigrations `manage.py, в папках 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 выпускает новую версию, тогда история миграции становится поврежденной - например, мой автоматически сгенерированный 0006* Миграция на куколку и их новый 0006 * Миграция форка истории

Вопрос

Есть ли способ преодолеть это?Или рекомендуемая практика для того, что делать?

На данный момент я нахожусь в очень ранней бета-версии, поэтому я мог бы сбросить всю БД и начать заново, если рекомендуемая стратегия состоит в том, чтобы установить это с самого начала, чтобы избежатьвопрос.

Спасибо за любую помощь, ребята!

1 Ответ

1 голос
/ 17 апреля 2019

Ответ 1 - если у вас есть контроль над сторонними библиотеками

Первоначальная миграция в сторонней библиотеке должна определять заменяемую зависимость, например: из wagtail.images import 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())),
        ],
        ...
    ),

Это не создается автоматически при миграции. get_image_model_string необходимо использовать таким образом при каждой миграции, затрагивающей этот FK, через всю историю миграции библиотеки.

Если вы измените настройку в какой-то момент в проекте, вам все равно нужно будет выполнить миграцию данных ( «Миграция существующей подкачиваемой зависимости» может помочь), но это решает проблему разветвления, описанную выше если начинать с чистого листа.

Недостатком является требование контроля над сторонней библиотекой. Я не затаив дыхание на такой проект, как puput, чтобы вернуться и изменить историю их ранней миграции, чтобы позволить заменяемую модель изображения (жесткие коды начальной миграции куколки wagtailimages.Image). Но я реализовал это для wagtail_events (мой собственный проект), чтобы спасти других людей от этой проблемы.

Ответ 2 - если у вас нет контроля

Тьфу. Я работал над этим некоторое время, и все варианты решения довольно ужасны. Я подумал о том, чтобы получить свой собственный класс изображений для олицетворения wagtail.images.model.Image с помощью мета-атрибутов db_table и даже путем создания другого приложения, которое по существу дублирует изображения трясогузки. Это либо много работы, либо супер хаки.

Я решил перенести миграцию вручную, используя параметр 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)),
            ],
     ...

1036 * Недостатки * 1) Фактическое созданное табличное отношение не строго определяется файлом миграции, но параметром, который может изменяться независимо. Если вы предпочитаете избегать этого, вместо этого вы можете просто жестко закодировать указанную модель в пользовательской миграции. 2) Этот подход делает вас довольно уязвимыми для разработчиков, которые обновляют требования к версии библиотеки, не осознавая, что им также придется вручную копировать файлы миграции. Я предлагаю проверить (f / ex, чтобы убедиться, что количество файлов в папке миграций по умолчанию совпадает с количеством файлов в пользовательской папке), прежде чем разрешить загрузку приложения, чтобы убедиться, что все базы данных разработки и производства работают на тот же набор миграций.

...