Задать вопрос

Тел: +7 965 3737 888





Getting dynamic model choices in newforms

<p>This is an excerpt from the form code used on this site; the tricky bit here is making the choices for the language field get filled in dynamically from Language.objects.all() on each form instantiation, so that new languages can be picked up automatically. It also adds a blank choice at the beginning so that users can't accidentally ignore the field and incorrectly end up with whatever Language was first in the list.
<p>If you use this, always remember that you have to call the superclass __init__ <em>before</em> you set your dynamic choices, and that you need to accept *args and **kwargs so you can pass them to it.
<p>In theory, ModelChoiceField will solve this, but it still seems to be a bit buggy.

Вопрос полезен? Да0/Нет0

Ответы (6):

Ответ полезен? Да0/Нет0

class MinorMessageForm( forms.Form):

#add choice by user

def __init__(self, *args, **kwargs):
    uid = kwargs.pop('uid')
    if uid: #remember to use exception handleing
        userdata = User.objects.get( id=uid)
        udata = userdata.minor_custodian
        l = []
        for u in udata:
             l.append(u.get('minor-name') +' - '+ u.get('custodian-email'))
    super(MinorMessageForm, self).__init__(*args, **kwargs)
    self.fields['for_user'].choices=  [('', '----------')]

its giving me key error at last line : for_user

Ответ полезен? Да0/Нет0

You can also use the 'queryset' field of ModelChoiceField:

class MyForm(forms.ModelForm):
    class Meta:
        model = my_models.MyModel

    def __init__(self, *args, **kwargs):
        dynarg = kwargs.pop('dynarg')
        self.base_fields['myfield'].empty_label = None
        self.base_fields['myfield'].queryset = my_models.MyField.objects.filter(myfilter=dynarg)
        super(MyForm, self).__init__(*args, **kwargs)

Ответ полезен? Да0/Нет0

Thank you for this helpful snippet ubernostrum.

If the form is bound and you want to filter the database query based on a value therein you can access it by: self.data.get('fieldname')

Ответ полезен? Да0/Нет0

Thank you for this snippet, one more question:


self.fields['language'].choices =

i put


, returning a list of choices and between '' because it is defined in another python file.

i got the following error at execution time:

need more than 1 value to unpack

What does it mean ???

Thank you very much


Ответ полезен? Да0/Нет0

Thank you!!!

I have spent several days trying to figure out how to filter a lookup table based on a value passed at run time. I was on the verge of deciding it could not be done, when I discovered this Snippet.

My only wish now is that I could understand >why< this works, when nothing else I tried did, but fortunately many things that I do not understand work anyway.

Ответ полезен? Да0/Нет0

It is also easy to create a builder function. You can use the same caching mechanism you do with other functions and even return different forms depending on the arguments.

def schedule_form(schedule, category):
    def _get_subjects():
        # some time consuming returns your choices
        # ...

    if category == CR:
        class CreditCourseSearchForm (forms.Form):
            subjects = forms.MultipleChoiceField(_get_subjects(), required=False)
            advising_codes = forms.ChoiceField(ADVISING_CODE_CHOICES, required=False)
            # ... 
        return CreditCourseSearchForm
        class NonCreditCourseSearchForm (forms.Form):
            subjects = forms.MultipleChoiceField(_get_subjects(), required=False)
            learning_community = forms.MultipleChoiceField(COMMUNITIES, required=False)
            # ... 
        return CreditCourseSearchForm