Overrding queryset on a field in form generated with ModelForm

96 views
Skip to first unread message

Tony Chu

unread,
Dec 10, 2008, 3:18:36 AM12/10/08
to Django users
Hi All,

I was using the ModelForm to generate my first form in Django.
ModelForm is great. However, I had wanted to dynamically limit the
selection of Foreign keys to a subset I generate.

The only way I found after a lot of trial and error was the following:

form['foreignkey'].field.queryset = desiredQuerySetFromForeignKey

Is this a good way to do it? Or is there some reason why this isn't
mentioned in the documentations?

More importantly, is there a better, more idiomatic 'Django' way to do
this?

Thanks for your time.

Tony

Malcolm Tredinnick

unread,
Dec 10, 2008, 8:38:13 PM12/10/08
to django...@googlegroups.com

On Wed, 2008-12-10 at 00:18 -0800, Tony Chu wrote:
> Hi All,
>
> I was using the ModelForm to generate my first form in Django.
> ModelForm is great. However, I had wanted to dynamically limit the
> selection of Foreign keys to a subset I generate.
>
> The only way I found after a lot of trial and error was the following:
>
> form['foreignkey'].field.queryset = desiredQuerySetFromForeignKey
>
> Is this a good way to do it?

There's a lot of text below, but my short answer is "looks fine to me."
That might, of course, be why nobody trusts my opinion, so be
responsible for your own actions.

> Or is there some reason why this isn't
> mentioned in the documentations?

Not every single possibility for setting parameters is mentioned in the
documentation. Sometimes because nobody's provided documentation for it
yet. Sometimes because those possibilities are sufficiently edge-case
that documenting them would obscure the necessary pieces (which means
documenting them really has to go into a separate section and still be
findable). At some level, looking at the __init__ methods for field
classes isn't that hard to do (it's pretty normal Python practice, too).

Basically, documentation on various levels, given that we're catering
for everybody from experienced Django users to people just learning
Python and all stages in between, is an ongoing process.

If you want to take a swing at writing more comprehensive documentation
in this area, please do! We welcome genuine documentation improvements.
As I note above, the hard bit is working out a structure so that all the
necessary reference material is available (since you're really after a
piece of reference documentation), without making the existing "howto"
stuff less comprehensible. That's another ongoing problem we wrestle
with and something that is very much ongoing work (it's easier to fix
now that the docs have been restructured prior to 1.0, but it's by no
means finished work).

> More importantly, is there a better, more idiomatic 'Django' way to do
> this?

Without wanting to stamp anything as "more idiomatic", I'll say this
(it's in two parts, so bear with me whilst the first bit looks like a
non-solution): the reasonably standard approach if you want to change
the field used by default in a ModelForm is to override that field.
ForeignKeys in models are represented by ModelChoiceFields (that's
documented in topcs/forms/models) which accept a queryset parameter. So
you can override the field and specify whatever queryset you like.

However, since you want to do this dynamically, you need to work out how
to effect the same behaviour at form build time (i.e. in __init__). So
the solution you've come up with is essentially the most logical: at
instance creation, get the field object you're interested in and change
the affected parameter. I can't see that there's anything wrong with
that approach. As much as possible classes tend to be designed (not just
in Django, but as a trend in Python) so that parameters can be set up by
writing to attributes or calling particular methods -- that is, modified
at runtime, not just at definition.

Regards,
Malcolm

Tony Chu

unread,
Dec 27, 2008, 2:13:17 AM12/27/08
to Django users
Thank you very much Malcolm. The methods I listed above has worked for
me so far - so your response is reassuring.

I was just surprised that no one had encountered a similar need
already. The concept here is parallel to getting a list of
territories in a country, dynamically fetched based on the country
specified. That would appeared to me to be a fairly common pattern.

Yours,
Tony

On Dec 10, 5:38 pm, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:

Malcolm Tredinnick

unread,
Jan 2, 2009, 9:40:41 PM1/2/09
to django...@googlegroups.com
On Fri, 2008-12-26 at 23:13 -0800, Tony Chu wrote:
> Thank you very much Malcolm. The methods I listed above has worked for
> me so far - so your response is reassuring.
>
> I was just surprised that no one had encountered a similar need
> already. The concept here is parallel to getting a list of
> territories in a country, dynamically fetched based on the country
> specified. That would appeared to me to be a fairly common pattern.

It's quite possible people have encountered the need previously and just
implemented it. It doesn't require any huge announcement if they did.

"It appears to me to be a common pattern" is neither here nor there.
Even if 100 people wanted to do something, that would be less than 1% of
people subscribed to this list (which is, itself, only a subset of
Django users), for example.

None of that invalidates what I said: some things just aren't documented
yet. It's usually pretty easy to work out how to do something, though,
since it's only Python code, after all.

Regards,
malcolm

mrsource

unread,
Feb 5, 2009, 4:11:09 AM2/5/09
to Django users
Maybe I missing some step:
I trying to set up the the automatic admin page form to edit a
category tree builded with treebeard extension:
#Model:
class Categoria(AL_Node,Componente):
immagine = fields.ImageWithThumbnailsField
(upload_to=Componente.image_path + 'categorie/',
thumbnail={'size':
(100, 60),'options': ['crop', 'upscale'],},
help_text =
Componente.image_help_text,

blank=True,default=Componente.noimage_logo)
parent = models.ForeignKey('self',
related_name='children_set',
null=True,
db_index=True)
node_order_by = ['data_creazione']
class Meta:
verbose_name = 'Categoria'
verbose_name_plural = 'Categorie'

but the I would exclude some elements from the foreign key choice
widget as itself object id and its descendants:
First I tried this to exclude the element that I editing:

#admin.py
class CategoriaForm(forms.ModelForm):
class Meta:
model = Categoria
def __init__(self, *args, **kwargs):
super(CategoriaForm,self).__init__(self, *args, **kwargs);
self.fields['parent'].queryset = Categoria.objects.filter
('id'<>kwargs['instance'].id)

but I get this error in the Categoria admin editing page:

Exception Type: TypeError
Exception Value: 'bool' object is not iterable
Exception Location: D:\codice\workspace\django\django\db\models\sql
\query.py in add_filter, line 1101

mrsource

unread,
Feb 7, 2009, 9:20:22 AM2/7/09
to Django users
Solved, I corrected the __init__ method with this:

def __init__(self, *args, **kwargs):
super(CategoriaForm,self).__init__(*args,**kwargs);
if kwargs.has_key('instance'):
self.fields['parent'].queryset = Categoria.objects.exclude
(parent=kwargs['instance'].id).exclude(id=kwargs['instance'].id)
Reply all
Reply to author
Forward
0 new messages