如何将Django表单类变量传递给嵌套类Meta?
你好!我现在遇到了一点小麻烦。下面的代码运行得很好,完全符合预期。简单来说,这是一种模型表单,它会根据从网址中收到的字符串,或者根据提供的实例的类,动态地确定它的模型。
我想问的是,是否可以把这个功能抽象到另一个模块,也就是 forms.py,通过传递 model_name 变量来实现。我可以顺利地把 model_name 传递给表单类,但我不知道怎么把它传递给 Meta。有没有简单的方法可以做到这一点?如果没有也没关系,不过这样做会让我的视图代码看起来整洁很多。
@user_passes_test(lambda u: u.is_staff, login_url="%slogin/" % NINJA_ADMIN_URL_PREFIX)
def content_form(request, model_name=None, edit=False, call_name=''):
if edit:
content = Content.objects.get(call_name=call_name)
model_name = content.fields.__class__.__name__
class ContentForm(forms.ModelForm):
parent = ModelTextField(queryset=Content.objects.all(), widget=JQueryAutocomplete(
source_url='%sjson/call_names.json' % NINJA_ADMIN_URL_PREFIX, jquery_opts = {'minLength': 2},
override_label='item.fields.call_name', override_value='item.fields.call_name'),
required=False)
class Meta():
model = get_ninja_type(model_name)
widgets = {
'ninja_type': forms.widgets.HiddenInput(),
}
def clean_parent(self):
call_name = self.cleaned_data['parent']
if call_name:
try:
parent = Content.objects.get(call_name=call_name)
except Content.DoesNotExist:
raise forms.ValidationError("The call name '%s' doesn't exist. Choose another parent." % call_name)
return parent
else:
return None
if request.method == 'POST':
if edit:
form = ContentForm(request.POST, instance=content.fields)
else:
form = ContentForm(request.POST)
if form.is_valid():
content = form.save()
messages.success(request, "Your new content has been saved.")
return HttpResponseRedirect('%scontent/' % NINJA_ADMIN_URL_PREFIX)
else:
if edit:
form = ContentForm(instance=content.fields)
else:
form = ContentForm(initial={'ninja_type': model_name.lower(),
'author': request.user})
if edit:
page_title = 'Edit %s' % model_name
else:
page_title = 'Create New %s' % model_name
return render(request, 'ninja/admin/content_form.html', {
'form': form,
'ninja_type': model_name,
'page_title': page_title,
'edit': edit,
'meta_field_names': NINJA_META_FIELD_NAMES,
})
1 个回答
1
当我仔细想想,这个答案其实很明显。一个函数返回一个类是完全没问题的。这就是在views.py开头的内容。我觉得这可能是实现这个功能的最佳方式,或者至少是最简洁的方式。
@user_passes_test(lambda u: u.is_staff, login_url="%slogin/" % NINJA_ADMIN_URL_PREFIX)
def content_form(request, model_name=None, edit=False, call_name=''):
if edit:
content = Content.objects.get(call_name=call_name)
model_name = content.fields.__class__.__name__
ContentForm = get_content_form(model_name)
if request.method == 'POST':
if edit:
form = ContentForm(request.POST, instance=content.fields)
else:
这是forms.py中的内容。
def get_content_form(model_name):
class DynamicContentForm(forms.ModelForm):
parent = ModelTextField(queryset=Content.objects.all(), widget=JQueryAutocomplete(
source_url='%sjson/call_names.json' % NINJA_ADMIN_URL_PREFIX, jquery_opts = {'minLength': 2},
override_label='item.fields.call_name', override_value='item.fields.call_name'),
required=False)
class Meta():
model = get_ninja_type(model_name)
widgets = {
'ninja_type': forms.widgets.HiddenInput(),
}
def clean_parent(self):
call_name = self.cleaned_data['parent']
if call_name:
try:
parent = Content.objects.get(call_name=call_name)
except Content.DoesNotExist:
raise forms.ValidationError("The call name '%s' doesn't exist. Choose another parent." % call_name)
return parent
else:
return None
return DynamicContentForm