Django: Как я могу использовать get_model в моем сценарии использования, чтобы правильно импортировать класс и избежать конфликтов - PullRequest
1 голос
/ 16 марта 2012

У меня есть модель с методом get_form.

# models.py

from model_utils.managers import InheritanceManager
from breathingactivities.forms import ParentRecordForm, ChildRecordForm


class ParentRecord(models.Model):
    ....
    objects = InheritanceManager()

    def get_fields(self, exclude=('user')):
        fields = self._meta.fields
        return [(f.verbose_name, f.value_to_string(self)) for f in fields if not exclude.__contains__(f.name)]

    @classmethod
    def get_form(self, *args, **kwargs):
    return ParentRecordForm

class ChildRecord(ParentRecord):
    ....
    duration = DurationField(
    _('Duration'),
    help_text=_('placeholder'))

    @classmethod
    def get_form(self, *args, **kwargs):
        return ChildRecordForm

У меня есть представление, которое использует этот метод get_form для определения правильности формы для данного объекта.

# views.py

class ParentRecordUpdateView(UpdateView):
    model = ParentRecord
    form_class = ParentRecordForm
    template_name = 'parentrecords/create.html'

    def get_object(self, **kwargs):
        return ParentRecord.objects.get_subclass(slug=self.kwargs['slug'])

    def get_form_class(self, *args, **kwargs):
        form_class = self.model.objects.get_subclass(slug=self.kwargs['slug']).get_form()
        return form_class

    def get_form_kwargs(self):
        kwargs = super(ParentRecordUpdateView, self).get_form_kwargs()
        kwargs.update({'user': self.request.user})
        return kwargs

Я использую InheritanceManager из django-model-utils, поэтому я получаю чистый API для подклассов, когда я запрашиваю родительский класс - это вещь get_subclass (), и именно поэтому мое представление работает с ParentRecord.

Все это хорошо работает. Через консоль я вижу, что действительно form_class является классом формы, который я ожидаю, например ChildRecordForm, когда экземпляр имеет значение ChildRecord.

В моем forms.py я не могу просто импортировать models.ParentRecord и models.ChildRecord, так как я импортирую эти формы в мои models.py, и, таким образом, возникает ошибка, из-за которой Django не может импортировать эти модели. Я полагаю, из-за кругового импорта.

Итак, я пробую это вместо:

# forms.py

from django.db.models import get_model

class ParentRecordForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super (ParentRecordForm, self).__init__(*args, **kwargs)

    class Meta:
        model = get_model('model', 'ParentRecord')
        exclude = ('user')

class ChildRecordForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super (ChildRecordForm, self).__init__(*args, **kwargs)

    class Meta:
        model = get_model('model', 'ParentRecord')
        exclude = ('user')

Однако модель для этих форм всегда возвращает None.

Я иду и передаю ChildRecordForm совершенно не связанную модель, которую я могу импортировать из другого приложения в моем проекте, например:

# forms.py

from another_app import AnotherModel

class ChildRecordForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super (ChildRecordForm, self).__init__(*args, **kwargs)

    class Meta:
        model = AnotherModel
        exclude = ('user')

Тогда это работает, то есть форма возвращает поля AnotherModel.

Итак, я не могу понять, почему get_model () работает для меня в оболочке, а не в классе формы, когда я использую его для объявления значения для модели.

1 Ответ

2 голосов
/ 16 марта 2012

Мое предположение на get_model() состоит в том, что запуск его на уровне определения класса может дать неверные результаты, поскольку он будет оценен, поскольку Django заполняет все модели в своем AppCache.Мое быстрое чтение модуля django.db.models.loading, кажется, не показывает эту проблему, но одна вещь, которую нужно попробовать, это запустить get_model() в представлении и распечатать результаты, чтобы увидеть, является ли это то, что выдумаю, так и должно быть, поскольку к этому времени AppCache должен быть полностью загружен.

Но - в качестве обходного пути, чтобы обойти оригинальный круговой импорт (так что вам не нужно использовать get_model в любом случае) являетсяне импортируйте формы на уровне модуля - вместо этого вы можете вставить их в метод класса:

class ParentRecord(models.Model):
    @classmethod
    def get_form(self, *args, **kwargs):
        from yourapp.forms import BreathingActivityRecordForm
        return BreathingActivityRecordForm

Таким образом, импорт будет оцениваться только при фактическом вызове .get_form(), и там не должнобыть какие-либо циклические зависимости при загрузке модуля.

...