Django过滤ModelChoiceField的查询集 - 我做错了什么?

时间:2013-07-31 22:06:10

标签: django django-queryset

我知道关于同一主题存在很多问题,但我对一点感到困惑。 我的目的是在表单上显示两个ModelChoiceFields,但不直接将它们绑定到Game模型。

我有以下内容:

forms.py

class AddGame(forms.ModelForm):
    won_lag = forms.ChoiceField(choices=[('1','Home') , ('2', 'Away') ])
    home_team = forms.ModelChoiceField(queryset=Player.objects.all())
    away_team = forms.ModelChoiceField(queryset=Player.objects.all())

    class Meta:
        model = Game
        fields = ('match', 'match_sequence')

Views.py

def game_add(request, match_id):
    game = Game()
    try:
        match = Match.objects.get(id=match_id)
    except Match.DoesNotExist:
        # we have no object!  do something
        pass

    game.match = match

    # get form
    form = AddGame(request.POST or None, instance=game)
    form.fields['home_team'].queryset = Player.objects.filter(team=match.home_team )

    # handle post-back (new or existing; on success nav to game list)
    if request.method == 'POST':
        if form.is_valid():
            form.save()
            # redirect to list of games for the specified match
            return HttpResponseRedirect(reverse('nine.views.list_games'))

    ...

我感到困惑的是设置查询集过滤器。 首先我试过:

form.home_team.queryset = Player.objects.filter(team=match.home_team )

但是我收到了这个错误

AttributeError at /nine/games/new/1 
'AddGame' object has no attribute 'home_team'
...

所以我将其更改为以下内容:(阅读其他帖子后)

form.fields['home_team'].queryset = Player.objects.filter(team=match.home_team )

现在它运作正常。

所以我的问题是,两条线之间有什么区别?为什么第二个工作而不是第一个?我确信这是一个新手(我是一个)的问题,但我很困惑。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:3)

Django表格是metaclasses

>>> type(AddGame)
<class 'django.forms.forms.DeclarativeFieldsMetaclass'>

他们基本上根据其定义中给出的信息创建表单实例。这意味着,在定义AddGame表单时,您将无法获得所看到的内容。实例化它时,metaclass将返回包含所提供字段的正确实例:

>>> type(AddGame())
<class 'your_app.forms.AddGame'>

因此,通过实例,您只需执行form.field即可访问这些字段。事实上,它比这复杂一点。您可以访问两种类型的字段。使用form['field'],您将访问BoundField。用于输出和raw_input。

通过form.fields['fields'],您将访问field that python can understand。这是因为如果from已经获得了任何输入,那么就会发生验证和数据转换(事实上,这些是用于此的字段,the general process of validation有点复杂)。

我希望这可能会为你解决一些问题,但正如你所看到的,整个form's API真的很复杂。对于最终用户来说非常简单,但幕后有很多编程:)

阅读链接提供将有助于消除您的疑虑,并将提高您对这个非常有用的主题和Django的了解。

祝你好运!

更新:顺便说一下,如果您想了解有关该主题的Python的元类,this is a hell of an answer的更多信息。

答案 1 :(得分:0)

在你views.py中,你有这一行:

form = AddGame(request.POST or None, instance=game)

所以form是类AddGame的Form对象(旁注:您应该将名称更改为AddGameForm以避免混淆)。

由于home_teamAddGame类中的字段,因此它不是form对象中的属性。这就是您无法通过form.home_team访问它的原因。

但是,Django Form API为任何表单对象提供fields属性,这是一个包含所有表单字段的dict。这就是您可以访问form.fields['home_team']的原因。

最后,由于home_teamModelChoiceField,因此它可以包含queryset属性,这就是您可以访问form.fields['home_team'].queryset

的原因