问题
I started writing my first reusable app about 3 weeks ago, and I'm having troubles to deal with migrations.
I want some points of my app to be customizable. Thus I have a conf submodule that defines custom settings and assign the reasonable defaults that will fit most cases.
This leads some of my model fields to look like this:
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))
Unfortunately, on projects using this app, this causes django-admin makemigrations
to create migrations for it every time a setting changes. Or even, the first time they install the app for settings which default value depends on the host system.
I'm more than doubtful about the legitimacy of a project creating its own migrations inside his copy of an app. But if I'm wrong, tell me.
For prefix_subject
in the above sample, I solved the issue with this solution. Considering that losing the help_text
information in migrations was not very effective.
However, I'm not sure this is a suitable solution for all/most cases. Is it?
I thought about another solution that seems to work. This solution is to manually edit migrations and replace evaluated settings by the variable itself.
For instance, I would replace this:
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={...}
),
With :
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={...}
),
Does it look like a good solution to you?
What do you advise to do in such cases?
I think both Field.help_text
, FilePathField.path
and FileField.upload_to
attributes are not used to create SQL statements. So in this case, there should not be specific issues due to "ignoring them in migrations". But what if I, hypothetically, want a customizable Field.default
, Field.db_column
or CharField.max_length
for instance? That's probably a very bad idea that have no practical interest, but that's the only hypothetical situation I can find. :P I guess in this case it would be better to provide an abstract base model, intended to be extended by the host project.
回答1:
During the design of django.db.migration
it was decided that all field attributes were to be tracked even if they didn't affect their schema representation.
For the upload_to
case I suggest you simply pass a function defined at a module level as documented.
import os
def upload_to(instance, filename):
return os.path.join([conf.TEMPLATES_UPLOAD_DIR, filename])
For the path
and help_text
I suggest you use an approach similar to what I did with 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
)
来源:https://stackoverflow.com/questions/35485498/django-migrations-and-customizable-reusable-apps