大约 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我想在这种情况下,最好提供一个抽象的基本模型,旨在由主机项目扩展。
在设计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
)