views:

32

answers:

1

Hey,

I have got a choiceField in my form, where I display filtered data. To filter the data I need two arguments. The first one is not a problem, because I can take it directly from an object, but the second one is dynamically generated. Here is some code:

class GroupAdd(forms.Form):
    def __init__(self, *args, **kwargs):
        self.pid = kwargs.pop('parent_id', None)

        super(GroupAdd, self).__init__(*args, **kwargs)

    parent_id = forms.IntegerField(widget=forms.HiddenInput)
    choices = forms.ChoiceField(
        choices = [
            [group.node_id, group.name] for group in Objtree.objects.filter(
                 type_id = ObjtreeTypes.objects.values_list('type_id').filter(name = 'group'), 
                 parent_id = 50
            ).distinct()] + [[0, 'Add a new one']
        ], 
        widget = forms.Select(
            attrs = {
                'id': 'group_select'
            }
        )
     )

I would like to change the parent_id that is passed into the Objtree.objects.filter. As you can see I tried in the init function, as well with kwargs['initial']['parent_id'] and then calling it with self, but that doesnt work, since its out of scope... it was pretty much my last effort. I need to acccess it either trough the initial parameter or directly trough parent_id field, since it already holds its value (passed trough initial).

Any help is appreciated, as I am running out of ideas.

+2  A: 

OK a couple of minor points here before I answer your question.

Firstly, your field should probably be a ModelChoiceField - this takes a queryset parameter, rather than a list of choices, which avoids the need for the list comprehension to get id and value.

Secondly, your query to get the Objtree objects is much better written using the double-underscore notation to traverse relations:

Objtree.objects.filter(type__name='group', parent_id=50)

Now, the actual question. As you note, you can't access local or instance variables within the field declarations. These are class-level attributes, which are processed (via the metaclass) when the class is defined, not when it is instantiated. So you need to do the whole thing in __init__.

Like this:

class GroupAdd(forms.Form):
    parent_id = forms.IntegerField(widget=forms.HiddenInput)
    choices = forms.ModelChoiceField(queryset=None)

    def __init__(self, *args, **kwargs):
        pid = kwargs.pop('parent_id', None)
        super(GroupAdd, self).__init__(*args, **kwargs)
        self.fields['choices'].queryset = Objtree.objects.filter(
                                              type__name='group', parent_id=pid
                                          )
Daniel Roseman
Thanks, this worked like a charm, but I cant use `type__name='group'` as there is no relation between `Objtree` and `ObjtreeTypes`. I could add a foreing key, but that is not neccessary for now. +1
realshadow