2
\$\begingroup\$

I have made a ChoiceField into a select and submit button and wondered if this is the correct approach.

forms.py

class PortfolioForm(forms.Form):
 def __init__(self, *args, **kwargs):
 super(PortfolioForm, self).__init__(*args, **kwargs)
 portfolios = [('pf 1', 'pf 1'), ('pf 2', 'pf 2'), ('pf 3', 'pf 3')]
 self.fields['portfolios'] = forms.ChoiceField(
 widget=forms.Select(),
 choices=portfolios,
 required=False,
 )

views.py

class PortfolioView(View):
 form_class = PortfolioForm
 template_name = 'portfolio.html'
 def get(self, request):
 form = self.form_class()
 return render(request, self.template_name, {'form': form})
 def post(self, request):
 form = self.form_class(self.request.POST)
 if form.is_valid():
 selected_portfolio = form.cleaned_data.get('portfolios')
 print(selected_portfolio) 
 form = self.form_class(initial={'portfolios': selected_portfolio})
 else:
 form = self.form_class(initial={'portfolio_name': ''})
 return render(self.request, self.template_name, {'form': form})

and most of the trickery in the template. I use elements of form.portfolios to make the buttons, but it seems I have to include form.portfolios in the template to make it all work. In order not to show I put this in a hidden tag.

{% block content %}
 <form id="id_portfolio" method="post">
 {% csrf_token %}
 <a style="visibility: hidden">{{ form.portfolios }}</a>
 {% for portfolio in form.portfolios %}
 <p>
 {% if portfolio.data.selected %}
 <button type="button">{{ portfolio.choice_label }}</button>
 {% else %}
 <button type="submit" value="{{ portfolio.data.value }}" 
 name="{{ portfolio.data.name }}">{{ portfolio.choice_label }}</button>
 {% endif %}
 </p>
 {% endfor %}
{% endblock content %}
asked Sep 9, 2019 at 13:20
\$\endgroup\$
4
  • \$\begingroup\$ I haven't tried replicating this on my own machine, but what goes terribly wrong if you just use Django's built-in form rendering using {{ form }}? \$\endgroup\$ Commented Sep 10, 2019 at 15:20
  • \$\begingroup\$ Just rendering the built-in form {{ form.portfolios }} gives me a dropdown list. I want the buttons to be visible at all time. \$\endgroup\$ Commented Sep 11, 2019 at 3:41
  • \$\begingroup\$ Do you want there to be a button for each portfolio choice on the page? It may be better to override the Select widget and replace the select.html template with a template that renders buttons instead of a dropdown select \$\endgroup\$ Commented Sep 11, 2019 at 8:35
  • \$\begingroup\$ @mikeyl, yes correct I do not want the dropdown but still want to use the choicefied. Can you point me to how to replace the select.html with one that renders buttons. \$\endgroup\$ Commented Sep 11, 2019 at 9:21

1 Answer 1

2
\$\begingroup\$

If you want the options to appear on the page, I would recommend using the RadioSelect widget instead. You will still need to click a separate button to submit however.

class PortfolioForm(forms.Form):
 def __init__(self, *args, **kwargs):
 super(PortfolioForm, self).__init__(*args, **kwargs)
 portfolios = [('pf 1', 'pf 1'), ('pf 2', 'pf 2'), ('pf 3', 'pf 3')]
 self.fields['portfolios'] = forms.ChoiceField(
 widget=forms.RadioSelect(),
 choices=portfolios,
 required=False,
 )

If you would like your own custom widget instead, you can inherit one of the existing widgets and apply your own template.

# widgets.py
class ButtonSelect(ChoiceWidget):
 template_name = 'widgets/button_select.html'
 option_template_name = 'widgets/button_select_option.html'
# templates/widgets/button_select.html
{% include "django/forms/widgets/multiple_input.html" %}
# templates/widgets/button_select_option.html
""""
Will need custom widget option code here.
Take a look at https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/input_option.html
"""

Then you can use it in your PortfolioForm

from widgets import ButtonSelect
class PortfolioForm(forms.Form):
 def __init__(self, *args, **kwargs):
 super(PortfolioForm, self).__init__(*args, **kwargs)
 portfolios = [('pf 1', 'pf 1'), ('pf 2', 'pf 2'), ('pf 3', 'pf 3')]
 self.fields['portfolios'] = forms.ChoiceField(
 widget=ButtonSelect(),
 choices=portfolios,
 required=False,
 )
answered Sep 11, 2019 at 13:39
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.