Question

So, I am having this form where I display a list of all my app models in a drop-down list and expect from the user to choose one so as to display its fields. Below is my form and the models() method, which creates the list of models to be passed as argument to my ChoiceField.

*forms.py*
class dbForm(forms.Form):
    model_classes_field = forms.ChoiceField(choices=models(), required=True,)

def models():
apps = get_app('Directories')
m_id = 0
for model in get_models(apps):
    m_id += 1
    model_classes.append({
        'model_name': model._meta.verbose_name,
        'model_id': m_id,
        'model_table': model._meta.db_table,
        'model_object': model.objects.all()  
    })
return model_classes

In my views.py I tried handling the POST data but unfortunately for some reason the form was not valid and I couldn't manipulate any data. Furthermore form.errors does not display anything at all.

*views.py*
def index(request): 
if request.method == 'POST': # If the form has been submitted...
    form = dbForm(request.POST) # A form bound to the POST data
    if form.is_valid(): # All validation rules pass
            model_classes_field = form.cleaned_data['model_classes_field']
            return HttpResponseRedirect('/list/') # Redirect after POST
    else:
            print "form: ", form.errors
else:
    form = dbForm() # An unbound form
    print "form: ", form.errors
    print "not valid form"

return render(request, 'Directories/index.html', {
            'form': form,
    })

Furthermore, in the template whenever i try to submit the form it returns an error message "too many values to unpack" and does not redirect me to the next template (list.html).

*index.html*
{% block content%} 
<div id="content" align="center">                
    <h2> Welcome! this is Directories app! </h2> 
    <form action="" method="post">{% csrf_token %}
{{ form.model_classes_field.errors }}
<label for="id_model_classes_field">Choose from one of the existing tables:</label> 
<select id="id_model_classes_field" name="model_classes_field">         
{% for choice in form.fields.model_classes_field.choices %}
        <option name="m_id" value="{{ choice.model_table }}">{{choice.model_id}}: {{choice.model_name}}</option> 
{% endfor %} 
</select> <br /> 
<input type="submit" value="Change" name="_change" />
</form>
</div>
<div id="bottom">

</div>
{% endblock %}

The only workaround i found on this is to fill the form action with the template to be redirected at (i.e. action = "list") instead of doing it in the views with return HttpResponseRedirect('/list/') . However, I believe that this does not solve the issue since still the form is not valid and i cannot process data with form.cleaned_data. It's peculiar though that the post data is sent even though the form is not valid.

*

EDIT: Solution

I changed my models() method as such:

def models():
    apps = get_app('Directories')
    for model in get_models(apps):
        model_classes.append( (model._meta.verbose_name, model._meta.db_table), )
    return model_classes

so I included a tuple as instructed by @Rohan and after making a slight alteration to my index.html:

...
{% for choice in form.fields.model_classes_field.choices %}
        <option name="m_id" value="{{choice.0}}">{{choice.0}}</option> 
{% endfor %} 
...

form is valid and can now process my data.

*

Was it helpful?

Solution

Value of choices should be list/tuple containing items with exactly 2 elements. But you are creating list of dicts which might be causing the issue.

for model in get_models(apps):
    m_id += 1
    model_classes.append({
        'model_name': model._meta.verbose_name,
        'model_id': m_id,
        'model_table': model._meta.db_table,
        'model_object': model.objects.all()  
    })

So you may want to update models() method to return appropriate list/tuple.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top