【问题标题】:Django: How can I use get_model in my use case to correctly import a class and avoid conflictsDjango:如何在我的用例中使用 get_model 来正确导入类并避免冲突
【发布时间】:2012-03-16 09:38:14
【问题描述】:

我有一个带有 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 是我期望的表单类,例如当实例是 ChildRecord 时的 ChildRecordForm。

在我的 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() 为模型声明值时,我无法弄清楚为什么 get_model() 在 shell 中对我有用,但在表单类中却不行。

【问题讨论】:

  • 就风格而言,classmethod 的第一个参数通常命名为 cls,而不是 self
  • 好吧,我不知道。

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


【解决方案1】:

我对@9​​87654322@ 的猜测是,在类定义级别运行它会产生不正确的结果,因为它会在 Django 填充其 AppCache 中的所有模型时被评估。我对django.db.models.loading 模块的快速阅读似乎没有显示出这个问题,但要尝试的一件事是在 view 中运行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() 时才会评估导入,并且在模块加载时间不应该有任何循环依赖。

【讨论】:

  • 我认为这是正确的。我一直在非常广泛地使用 get_model 并且一直被它返回 None 所困扰,因为我在加载应用程序缓存之前解释了一个模块。
  • 当你在一个方法或函数中导入你的模块时,每次调用该函数时都会被评估。不是很浪费时间吗?
  • import 语句必须被评估,但模块本身一旦在sys.modules 中就不会重新加载。开销可以忽略不计,对我来说只有几分之一毫秒。 gist.github.com/3193380
  • Spooky,这完全是我的问题,甚至使用 InheritanceManager!
猜你喜欢
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 2016-07-19
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
相关资源
最近更新 更多