Question
Say I have the following in my 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)
I.e. there are multiple Companies
, each having a range of Rates
and
Clients
. Each Client
should have a base Rate
that is chosen from its
parent Company's Rates
, not another Company's Rates
.
When creating a form for adding a Client
, I would like to remove the
Company
choices (as that has already been selected via an "Add Client"
button on the Company
page) and limit the Rate
choices to that Company
as well.
How do I go about this in Django 1.0?
My current forms.py
file is just boilerplate at the moment:
from models import *
from django.forms import ModelForm
class ClientForm(ModelForm):
class Meta:
model = Client
And the views.py
is also basic:
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})
In Django 0.96 I was able to hack this in by doing something like the following before rendering the template:
manipulator.fields[0].choices = [(r.id,r.name) for r in Rate.objects.filter(company_id=the_company.id)]
ForeignKey.limit_choices_to
seems promising but I don't know how to pass in the_company.id
and I'm not
clear if that will work outside the Admin interface anyway.
Thanks. (This seems like a pretty basic request but if I should redesign something I'm open to suggestions.)
Answer
ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet. See the reference for ModelChoiceField.
So, provide a QuerySet to the field's queryset
attribute. Depends on how
your form is built. If you build an explicit form, you'll have fields named
directly.
form.rate.queryset = Rate.objects.filter(company_id=the_company.id)
If you take the default ModelForm object, form.fields["rate"].queryset = ...
This is done explicitly in the view. No hacking around.