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

发布于 2024-10-11 01:42:55 字数 2272 浏览 3 评论 0原文

我一直在研究 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

无人问我粥可暖 2024-10-18 01:42:55

这一行是你的问题:

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...

This line is your problem:

target_language_form = AddTargetLanguagesForm(request.POST)

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__:

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

so that the first positional argument (after the automatic self), is article. You could change the instantiation, but I prefer to do this:

def __init__(self, *args, **kwargs):
    article = kwargs.pop('article', None)
    super(AddTargetLanguagesForm, self).__init__(*args, **kwargs)
    if article is not None:
        ...etc...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文