开发者

Django ModelMultipleChoiceField update queryset within constructor fails on POST

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'开发者_JS百科] = target_language_form
    return render_to_response(template_name, content_dict, 
                              context_instance=RequestContext(request))


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜