views:

53

answers:

3

I've got some <selects> that I need to populate with some choices that depend on the currently logged in user. I don't think this is possible (or easy) to do from inside the form class, so can I just leave the choices blank and set them in the view instead? Or what approach should I take?

+3  A: 

Not sure if this is the best answer, but in the past I have set the choices of a choice field in the init of the form - you could potentially pass your choices to the constructor of your form...

Matthew J Morrison
Or just the user object, and the rest I could do from inside init. But how do you set the choices from inside init? Do you do `self.field = ...` like normal, or can you explicitly modify just the choices attribute? You have a small code snippet handy?
Mark
you can do something like self.fields['field_name'].choices = choice_tuple
Matthew J Morrison
+1  A: 

Considering that you have included the user as a parameter, I would solve this using a custom tag.

In your app/templatetags/custom_tags.py something like this:

@register.simple_tag
def combo(user, another_param):
    objects = get_objects(user, another_param)
    str = '<select name="example" id="id_example">'
    for object in objects:
        str += '<option value="%s">%s</option>' % (object.id, object.name)
    str += '</select>'
    return mark_safe(str)

Then in your template:

{% load custom_tags %}
{% special_select user another_param %}

More about custom tags http://docs.djangoproject.com/en/dev/howto/custom-template-tags/

juanefren
...what? Are you suggesting I add the extra fields from inside the *template*? That won't even validate, because they aren't apart of the valid `choices`. I think the template is the last place you want to be doing this... that's how I ran into this snag in the first place.
Mark
This would work, but I would personally avoid doing it for a few reasons. It isn't DRY - this tag redefines what the existing Select widget already does, it isn't reusable - this couples a specific process of gathering data with a specific presentation of that data, and finally it doesn't leverage the django forms, which I personally love for handling data entry. But still, a viable solution.
Matthew J Morrison
@Mark I forgot to say this solution is not based in django-forms, you should get the value from the POST manually.
juanefren
@juanefren: I'm afraid that's even worse. I need to access this field from inside the `clean` methods so that I can do some conditional validation w/ the other fields. Also, that makes this solution hackable and unvalidated... anyone can modify the HTML and insert their own options and then my app would just explode unless it's validated against the `choices` which Django does for you automatically.
Mark
+1  A: 

You could build your form dynamically in you view (well, actually i would rather keep the code outside the view in it's own function and just call it in the view but that's just details)

I did it like this in one project:

user_choices = [(1, 'something'), (2, 'something_else')]
fields['choice'] = forms.ChoiceField(
    choices=user_choices,
    widget=forms.RadioSelect,
)
MyForm = type('SelectableForm', (forms.BaseForm,), { 'base_fields': fields })
form = MyForm()

Obviously, you will want to create the user_choices depending on current user and add whatever field you need along with the choices, but this is a basic principle, I'll leave the rest as the reader exercise.

rebus