Django turn ChoiceField into a submit button 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 %}
  &lt;form id="id_portfolio" method="post"&gt;
    {% csrf_token %}
    &lt;a style="visibility: hidden"&gt;{{ form.portfolios }}&lt;/a&gt;
    {% for portfolio in form.portfolios %}
      &lt;p&gt;
      {% if portfolio.data.selected %}
        &lt;button type="button"&gt;{{ portfolio.choice_label }}&lt;/button&gt;

      {% else %}
        &lt;button type="submit" value="{{ portfolio.data.value }}" 
          name="{{ portfolio.data.name }}"&gt;{{ portfolio.choice_label }}&lt;/button&gt;

      {% endif %}
      &lt;/p&gt;
    {% endfor %}
{% endblock content %}
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,
                    )