Django:如何在我的用例中使用get_model来正确导入类并避免冲突

时间:2012-03-16 09:38:15

标签: django django-models django-forms django-views

我有一个带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

我正在使用来自django-model-utils的InheritanceManager,所以当我查询父类时,我得到一个干净的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()在shell中适用于我,但在我使用它来为模型声明值时不能在表单类中使用。

1 个答案:

答案 0 :(得分:2)

我对get_model()的猜测是,在类定义级别运行它会产生不正确的结果,因为当Django填充其AppCache中的所有模型时,它会得到评估。我对django.db.models.loading模块的快速阅读似乎没有显示该问题,但要尝试的一件事是在视图中运行get_model()并打印出结果以查看如果它是您认为的那样,那么AppCache应该完全加载。

但是 - 作为解决原始循环导入的一种解决方法(所以你不必使用get_model)就是不要在模块级别进行表单导入 - 你可以将它们粘贴在classmethod中:

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

这样,只有在实际调用.get_form()时才会导致导入,并且模块加载时不应存在任何循环依赖关系。