我如何在Django ModelForm中过滤ForeignKey的选择?

6 浏览
0 Comments

我如何在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,而且我不清楚是否可以在管理员界面之外使用。

谢谢。 (这似乎是一个非常基本的请求,但如果我应该重新设计某些内容,我也很乐意听取建议。)

admin 更改状态以发布 2023年5月20日
0
0 Comments

除了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博客的材料,其中有许多好的内容。

0
0 Comments

ForeignKey由django.forms.ModelChoiceField表示,它是一个选择字段,其选择是一个模型QuerySet。请参阅ModelChoiceField的参考文档。

因此,将QuerySet提供给字段的queryset属性。取决于您的表单是如何构建的。如果您构建一个显式表单,您将直接命名字段。

form.rate.queryset = Rate.objects.filter(company_id=the_company.id)

如果您采用默认的ModelForm对象,则form.fields["rate"].queryset = ...

这在视图中显式完成。不能进行任何修改。

0