构造函数中的 Django ModelMultipleChoiceField 更新查询集在 POST 上失败
我一直在研究 StackOverflow 上的各种问题,试图找出如何在表单中使用 ModelMultipleChoiceFields。我几乎有一个工作表单,允许用户选择将文章翻译成的语言。我创建了一个表单,它采用 SourceArticle
作为第一个构造函数参数,并使用它来指定表单的 languages
字段的查询集。
class AddTargetLanguagesForm(forms.Form):
def __init__(self, article=None, *args, **kwargs):
super(AddTargetLanguagesForm, self).__init__(*args, **kwargs)
self.fields['languages'].queryset = Language.objects.exclude(
Q(id = article.language.id) |
Q(id__in=[o.id for o in article.get_target_languages()]) |
Q(code="templates"))
languages = forms.ModelMultipleChoiceField(_("Languages"))
请注意,我的 AddTargetLanguagesForm
不是基于 ModelForm
,因为它不与我的任何模型对象直接相关。
当我第一次渲染表单时,它正确地为我提供了以下语言:(a) 不是源语言,(b) 尚未选择,(c) 不是特殊的“模板”语言。但是,当我尝试发布表单时,出现以下错误:
属性错误:“QueryDict”对象有 没有属性“语言”
我认为这与 Django 中表单的工作方式有关,但我还很新。我没有接受 SourceArticle 作为构造函数中的第一个参数,而是放置了 QueryDict。我假设这包含请求中的 POST 参数。我需要如何修改我的代码以允许其捕获所选语言?
这是我的观点的副本,如果它可以帮助您了解我如何使用该表格。
@login_required
def add_target_languages(request, aid, template_name="wt_articles/add_target_languages.html"):
"""
Adds one or more target language translations to a source article.
"""
content_dict = {}
# Fetch the article
no_match = False
sa_set = SourceArticle.objects.filter(id=aid)
if len(sa_set) < 1:
no_match = True
content_dict['no_match'] = no_match
else:
article = sa_set[0]
content_dict['article'] = article
if request.method == "POST":
target_language_form = AddTargetLanguagesForm(request.POST)
if target_language_form.is_valid():
languages = target_language_form.cleaned_data['languages']
article.add_target_languages(languages)
return HttpResponseRedirect('/articles/list')
else:
target_language_form = AddTargetLanguagesForm(article)
content_dict['target_language_form'] = target_language_form
return render_to_response(template_name, content_dict,
context_instance=RequestContext(request))
I've been pulling from various questions on StackOverflow to try to figure out how to work with ModelMultipleChoiceFields within a form. I almost have a working form that allows users to select languages to translate an article to. I created a form that takes a SourceArticle
as the first constructor argument and uses it to specify the queryset for the languages
field of my form.
class AddTargetLanguagesForm(forms.Form):
def __init__(self, article=None, *args, **kwargs):
super(AddTargetLanguagesForm, self).__init__(*args, **kwargs)
self.fields['languages'].queryset = Language.objects.exclude(
Q(id = article.language.id) |
Q(id__in=[o.id for o in article.get_target_languages()]) |
Q(code="templates"))
languages = forms.ModelMultipleChoiceField(_("Languages"))
Note that my AddTargetLanguagesForm
is not based on a ModelForm
, because it is not directly related to any of my model objects.
When I render the form for the first time, it correctly provides me with languages that (a) aren't the source language, (b) aren't already selected, and (c) aren't the special "templates" language. However, when I try to post my form, I get the following error:
AttributeError: 'QueryDict' object has
no attribute 'language'
I assume that this is related to how forms work in Django, but I'm pretty new. Rather than accepting a SourceArticle
as the first parameter in my constructor, a QueryDict
is placed instead. I assume that this contains the POST params from the request. How do I need to modify my code to allow it to capture the selected languages?
Here is a copy of my view, if it helps you see how I'm using the form.
@login_required
def add_target_languages(request, aid, template_name="wt_articles/add_target_languages.html"):
"""
Adds one or more target language translations to a source article.
"""
content_dict = {}
# Fetch the article
no_match = False
sa_set = SourceArticle.objects.filter(id=aid)
if len(sa_set) < 1:
no_match = True
content_dict['no_match'] = no_match
else:
article = sa_set[0]
content_dict['article'] = article
if request.method == "POST":
target_language_form = AddTargetLanguagesForm(request.POST)
if target_language_form.is_valid():
languages = target_language_form.cleaned_data['languages']
article.add_target_languages(languages)
return HttpResponseRedirect('/articles/list')
else:
target_language_form = AddTargetLanguagesForm(article)
content_dict['target_language_form'] = target_language_form
return render_to_response(template_name, content_dict,
context_instance=RequestContext(request))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这一行是你的问题:
这是从 POST 实例化表单的标准方法,但问题是你重写了
AddTargetLanguagesForm.__init__
: 的方法签名,以便第一个位置参数(在自动的
self
)是article
。您可以更改实例化,但我更喜欢这样做:This line is your problem:
That's the standard way of instantiating a form from a POST, but the trouble is that you've rewritten the method signature of
AddTargetLanguagesForm.__init__
:so that the first positional argument (after the automatic
self
), isarticle
. You could change the instantiation, but I prefer to do this: