我如何在Django ModelForm中过滤ForeignKey的选择?
我如何在Django ModelForm中过滤ForeignKey的选择?
假设我在我的models.py
中有以下内容:
class Company(models.Model): name = ... class Rate(models.Model): company = models.ForeignKey(Company) name = ... class Client(models.Model): name = ... company = models.ForeignKey(Company) base_rate = models.ForeignKey(Rate)
即有多个公司
,每个公司都有一系列的费率
和客户
。每个客户
应该有一个基础费率
,该费率从其父级公司的费率
中选择,而不是另一个公司的费率
。
在创建用于添加客户
的表单时,我想删除公司
选项(因为通过“添加客户”按钮在公司
页面中已经选择了该选项),并将费率
的选择限制在该公司
中。
我该如何在Django 1.0中进行操作?
我的当前forms.py
文件目前只是样板:
from models import * from django.forms import ModelForm class ClientForm(ModelForm): class Meta: model = Client
views.py
也很基础:
from django.shortcuts import render_to_response, get_object_or_404 from models import * from forms import * def addclient(request, company_id): the_company = get_object_or_404(Company, id=company_id) if request.POST: form = ClientForm(request.POST) if form.is_valid(): form.save() return HttpResponseRedirect(the_company.get_clients_url()) else: form = ClientForm() return render_to_response('addclient.html', {'form': form, 'the_company':the_company})
在Django 0.96中,我可以通过在渲染模板之前执行以下操作之类的方式来进行调整:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
似乎是有前途的,但我不知道如何传递the_company.id
,而且我不清楚是否可以在管理员界面之外使用。
谢谢。 (这似乎是一个非常基本的请求,但如果我应该重新设计某些内容,我也很乐意听取建议。)
除了S.Lott的答案外,正如becomingGuru在评论中提到的,通过覆盖ModelForm.__init__
函数,可以添加查询集过滤器。(这同样适用于常规表单)它可以帮助重用并保持视图函数的整洁。
class ClientForm(forms.ModelForm): def __init__(self,company,*args,**kwargs): super (ClientForm,self ).__init__(*args,**kwargs) # populates the post self.fields['rate'].queryset = Rate.objects.filter(company=company) self.fields['client'].queryset = Client.objects.filter(company=company) class Meta: model = Client def addclient(request, company_id): the_company = get_object_or_404(Company, id=company_id) if request.POST: form = ClientForm(the_company,request.POST) #<-- Note the extra arg if form.is_valid(): form.save() return HttpResponseRedirect(the_company.get_clients_url()) else: form = ClientForm(the_company) return render_to_response('addclient.html', {'form': form, 'the_company':the_company})
如果您有许多模型需要常用过滤器,这可能非常有用(通常我会声明一个抽象表单类)比如:
class UberClientForm(ClientForm): class Meta: model = UberClient def view(request): ... form = UberClientForm(company) ... #or even extend the existing custom init class PITAClient(ClientForm): def __init__(company, *args, **args): super (PITAClient,self ).__init__(company,*args,**kwargs) self.fields['support_staff'].queryset = User.objects.exclude(user='michael')
除此之外,我只是重申了Django博客的材料,其中有许多好的内容。
ForeignKey由django.forms.ModelChoiceField表示,它是一个选择字段,其选择是一个模型QuerySet。请参阅ModelChoiceField的参考文档。
因此,将QuerySet提供给字段的queryset
属性。取决于您的表单是如何构建的。如果您构建一个显式表单,您将直接命名字段。
form.rate.queryset = Rate.objects.filter(company_id=the_company.id)
如果您采用默认的ModelForm对象,则form.fields["rate"].queryset = ...
这在视图中显式完成。不能进行任何修改。