构造函数中的 Django ModelMultipleChoiceField 更新查询集在 POST 上失败

Posted

技术标签:

【中文标题】构造函数中的 Django ModelMultipleChoiceField 更新查询集在 POST 上失败【英文标题】:Django ModelMultipleChoiceField update queryset within constructor fails on POST 【发布时间】:2011-06-05 08:38:43 【问题描述】:

我一直在回答 *** 上的各种问题,试图弄清楚如何在表单中使用 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) 不是特殊“模板”的语言“ 语言。但是,当我尝试发布表单时,出现以下错误:

AttributeError: '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))

【问题讨论】:

【参考方案1】:

这一行是你的问题:

target_language_form = AddTargetLanguagesForm(request.POST)

这是从 POST 实例化表单的标准方法,但问题是您重写了 AddTargetLanguagesForm.__init__ 的方法签名:

def __init__(self, article=None, *args, **kwargs):

所以第一个位置参数(在自动self 之后)是article。您可以更改实例化,但我更喜欢这样做:

def __init__(self, *args, **kwargs):
    article = kwargs.pop('article', None)
    super(AddTargetLanguagesForm, self).__init__(*args, **kwargs)
    if article is not None:
        ...etc...

【讨论】:

感谢您的帮助。我决定更改以保留AddTargetLanguagesForm.__init__ 的签名并像这样传递article 值:target_language_form = AddTargetLanguagesForm(article, request.POST)。我曾尝试使用kwargs.pop,但由于这些更改,在呈现我的表单时出现错误。我最终没有进一步排除故障,而是更改了方法签名。

以上是关于构造函数中的 Django ModelMultipleChoiceField 更新查询集在 POST 上失败的主要内容,如果未能解决你的问题,请参考以下文章

Django中的信号

构造django形式的属性值

Django中的信号及其用法

django 信号

Django中的信号及其用法

Django中的信号及其用法