我正在尝试为Django编写应用程序。我希望我的用户能够收集某些类型的数据,例如样本,视频等......该应用程序称为收集器,对于每种类型的项目,都有一个类和一个与之相关的表单。
示例类:
class CreateTextView(CreateItemView):
form_class = TextForm
model = Text
def get_context_data(self, **kwargs):
context = super(CreateTextView, self).get_context_data(**kwargs)
context['item_type'] = 'text'
return context
示例表单:
class TextForm(forms.ModelForm):
class Meta:
model = Text
fields = COMMON_FIELDS + ('text',)
如您所见,实际视图继承自CreateItemView。我希望为CreateItemView定义尽可能多的功能,这样我就不必为所有项目类别单独执行。这在大多数情况下都是有效的,但是当我尝试使用数据处理表单时,它会变得有点棘手。
def post(self, request, *args, **kwargs):
form = TextForm(request.POST) # line 2
form = getattr(TextForm, '__init__')(data=request.POST) # line 3
if form.is_valid():
# Add owner information.
item = form.save(commit=False)
item.owner = request.user
item.save()
return HttpResponseRedirect(reverse('collector:index'))
return render(request, self.template_name, {'form': form})
在第2行中,如果只有一种类型的表单,您可以看到我将如何处理表单。第3行是我正在尝试做的事情。我希望能够使用context['item_type']
动态选择正确的表单并使用给定的数据对其进行实例化。
现在问题在于__init__
- 我从未在任何地方定义的方法。当我只将POST.request传递给__init__
时,它会抱怨没有自己。当我传递额外的self时,它会抱怨CreateTextView没有_meta属性等等。我只是找不到正确的论证组合来满足__init__
- 方法。我也无法查找它的定义,因为我没有定义它。然后我按照django框架中父类的定义,这导致我看到了几个看起来像工厂的复杂函数。这对我没有帮助......
现在我知道如何使用TextForm()
- 启动。有没有办法用getattr()
动态获取此方法?这样可以省去__init__
的麻烦。如果没有,我如何为__init__
提供正确的自我实例?
如下所述,我已经改变了我的课程。我不再使用上下文来存储item_type,而是使用类变量来轻松访问视图中的item_type。我的post方法在母类CreateItemView中定义,现在看起来像这样:
def post(self, request, *args, **kwargs):
try:
form_cls = ITEM_TYPE_MAP[self.item_type]
except KeyError:
# invalid item_type. raise a meaningful error here
raise Exception('Invalid item type.')
form = form_cls(request.POST)
if form.is_valid():
# Add owner information.
item = form.save(commit=False)
item.owner = request.user
item.save()
return HttpResponseRedirect(reverse('collector:index'))
return render(request, self.template_name, {'form': form})
答案 0 :(得分:0)
一个干净而且非常简单的解决方案是使用字典将item_type
值映射到实际的表单类:
ITEM_TYPE_MAP = {
"foo": TextForm,
"bar": SomeOtherForm,
}
你将这个字典放在某个全球的地方,并在控制器中使用它,如下所示:
item_type = context['item_type']
try:
form_cls = ITEM_TYPE_MAP[item_type]
except KeyError:
# invalid item_type. raise a meaningful error here
raise
form = form_cls(request.POST)
你通常不能直接调用__init__
,因为实现对象的不仅仅是那个。 Python也会在对象的类上调用__new__
,所以唯一可以确定的方法是通过调用该类型的实际构造函数。
这是上面发生的事情,首先将类型提取到form_cls
然后调用类型(即构造函数)。