2016-02-18 4 views
4

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

Я хочу, чтобы некоторые пункты моего приложения настраивались. Таким образом, у меня есть 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 в миграциях была не очень эффективной.

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

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

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

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={...} 
), 

ли это выглядеть как хорошее решение для вас?

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

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

ответ

2

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

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

import os 

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

Для path и help_text я предлагаю вам использовать подход, аналогичный тому, что я сделал с django-sundial для обеспечения конфигурируемых по умолчанию. Вам просто нужно убедиться, что вы передаете экземпляр класса с 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 
) 
+0

спасибо. Я не ожидал лучшего решения. Вот исправление, которое я применил: https://github.com/Aladom/django-mailing/commit/78ffcb81eea5e01d6e5ff112d8548fed9d1063f3. Полученная миграция выглядит хорошо. :) –

+0

Да, использование 'deconstructible' еще лучше. Причина, по которой я предложил использовать 'python_2_unicode_compatible', заключается в том, что если один из ваших настроек, на которые ссылаются, содержит символы не-ascii, он будет сбой на Python 2. –

+0

Да. Однако я решил не беспокоиться о совместимости с Python 2. Я думаю, Python 3 широко принят достаточно. Даже django потеряет поддержку python 2 в обозримом будущем. –