Django 迁移和可定制的可重用应用程序

Django migrations and customizable reusable apps

大约 3 周前我开始编写我的第一个可重用应用程序,但我在处理迁移方面遇到了麻烦。

我希望我的应用程序的某些点可以自定义。因此,我有一个 conf submodule 定义自定义设置并分配适合大多数情况的合理默认值。

这导致我的一些模型字段看起来像这样:

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,我用 this solution 解决了这个问题。考虑到在迁移中丢失 help_text 信息不是很有效。

但是,我不确定这是否适合 all/most 个案例。是吗?

我想到了另一个似乎有效的解决方案。此解决方案是手动编辑迁移并用变量本身替换评估设置。

例如,我将替换为:

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_textFilePathField.pathFileField.upload_to 属性都不用于创建 SQL 语句。所以在这种情况下,应该不会因为"ignoring them in migrations"而出现具体问题。但是,假设我想要一个可自定义的 Field.defaultField.db_columnCharField.max_length 怎么办?这可能是一个没有实际意义的非常糟糕的想法,但这是我能找到的唯一假设情况。 :P 我想在这种情况下最好提供一个抽象的基础模型,以供宿主项目扩展。

django.db.migration 的设计过程中,决定跟踪所有字段属性,即使它们不影响其模式表示。

对于 upload_to 的情况,我建议您只传递一个定义在模块级别的函数 as documented

import os

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

对于 pathhelp_text,我建议您使用类似于我对 django-sundial to provide configurable defaults. You'll just have to make sure you pass an instance of a class with a deconstruct() method returning the appropriate parameters 所做的方法。

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
)