Миграции Django и настраиваемые многократно используемые приложения

Я начал писать свое первое приложение многоразового использования около 3 недель назад, и у меня возникли проблемы с миграцией.

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

Это приводит к тому, что некоторые поля моей модели выглядят так:

attachment = models.FilePathField(
    path=conf.ATTACHMENTS_DIR, recursive=True)

template_file = models.FileField(
    upload_to=conf.TEMPLATES_UPLOAD_DIR, blank=True)

prefix_subject = models.BooleanField(
    default=True, verbose_name=_("prefix subject"),
    help_text=_(
        "Whether to prefix the subject with \"{}\" or not."
    ).format(conf.SUBJECT_PREFIX))

К сожалению, на проектах, использующих это приложение, это вызывает django-admin makemigrations создавать миграции для него каждый раз, когда изменяется настройка. Или даже, когда они в первый раз устанавливают приложение для настроек, значение которых по умолчанию зависит от хост-системы.

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

За prefix_subject В приведенном выше примере я решил проблему с этим решением. Учитывая, что потеря help_text информация в миграциях была не очень эффективной.

Однако я не уверен, что это подходящее решение для всех / большинства случаев. Это?

Я думал о другом решении, которое, кажется, работает. Это решение состоит в том, чтобы вручную редактировать миграции и заменять оцененные параметры самой переменной.

Например, я бы заменил это:

migrations.CreateModel(
    name='MailStaticAttachment',
    fields=[
        ('id', ...),
        ('filename', ...)
        ('mime_type', ...)
        ('attachment', models.FilePathField(path='/home/antoine/Workspace/django-mailing/static/mailing/attachments', recursive=True, verbose_name='file')),
    ],
    options={...}
),

С:

from ..conf import ATTACHMENTS_DIR

migrations.CreateModel(
    name='MailStaticAttachment',
    fields=[
        ('id', ...),
        ('filename', ...)
        ('mime_type', ...)
        ('attachment', models.FilePathField(path=ATTACHMENTS_DIR, recursive=True, verbose_name='file')),
    ],
    options={...}
),

Это похоже на хорошее решение для вас?

Что вы советуете делать в таких случаях?

Я думаю, что оба Field.help_text, FilePathField.path а также FileField.upload_to атрибуты не используются для создания операторов SQL. Так что в этом случае не должно быть особых проблем из-за "игнорирования их при миграции". Но что, если я, гипотетически, хочу настраиваемый Field.default, Field.db_column или же CharField.max_length например? Вероятно, это очень плохая идея, которая не имеет практического интереса, но это единственная гипотетическая ситуация, которую я могу найти.:P I, думаю, в этом случае было бы лучше предоставить абстрактную базовую модель, предназначенную для расширения хост-проектом.

1 ответ

Решение

Во время проектирования django.db.migration было решено, что все атрибуты поля должны отслеживаться, даже если они не влияют на представление схемы.

Для upload_to В этом случае я предлагаю вам просто передать функцию, определенную на уровне модуля, как описано в документации.

import os

def upload_to(instance, filename):
    return os.path.join([conf.TEMPLATES_UPLOAD_DIR, filename])

Для path а также help_text Я предлагаю вам использовать подход, аналогичный тому, что я сделал с django-sundialобеспечить настраиваемые значения по умолчанию. Вам просто нужно убедиться, что вы передаете экземпляр класса с deconstruct() метод, возвращающий соответствующие параметры.

from django.utils.six import python_2_unicode_compatible


@python_2_unicode_compatible
class StringConfReference(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return getattr(conf, self.name)

    def deconstruct(self):
        return "%s.%s" % (__name__, self.__class__.__name__), (self.name,), {}


attachment = models.FilePathField(
    path=StringConfReference('ATTACHMENT_DIR'), recursive=True
)
Другие вопросы по тегам