[python] Django ChoiceField

I'm trying to solve following issue:

I have a web page that can see only moderators. Fields displayed on this page (after user have registered):
Username, First name+Last name, Email, Status, Relevance, etc.

I need to display table with information of all users stored in db with this fields, but two of fields have choices, so I want to make option that moderators can choose another option and after clicking on "Update" button this fields will be updated for selected user.

I can to display all choices of "status" and "relevance" fields, and after I choose new options from dropdown db is updated.
I want to display dropdowns and option stored in db should be selected. I've tried a lot of options, I googled a lot of my time, and searched for answer or for right direction in StackOverFlow too, but didn't find anything.

Sorry for my bad english and thank you in advance for help!

Below is part of my code:

models.py:

class Profile(models.Model):
    user = models.OneToOneField(User)

    status = models.IntegerField(choices=((1, _("Not relevant")),
                                        (2, _("Review")),
                                        (3, _("Maybe relevant")),
                                        (4, _("Relevant")),
                                        (5, _("Leading candidate"))),
                                default=1)

    relevance = models.IntegerField(choices=((1, _("Unread")),
                                        (2, _("Read"))),
                                default=1)

forms.py:

class CViewerForm(forms.Form):

    status = forms.ChoiceField(label="",
                                initial='',
                                widget=forms.Select(),
                                required=True)

    relevance = forms.ChoiceField(widget=forms.Select(),
                              required=True)

views.py:

@group_required('Managers')
@render_to('reader/view.html')
def admins_view(request):
    users_list = Profile.objects.select_related('user').all()
    users_dict = dict()

    if request.method and request.method == 'POST':
        form = CViewerForm(request.POST)

    if form.is_valid():
        d = form.cleaned_data
        # get all selected choices
        status_list = request.POST.getlist('status')
        relevance_list = request.POST.getlist('relevance')
        # get all usernames viewed on page
        users_list = request.POST.getlist('username')

        # create dict from all those lists
        users_dict = zip([user for user in users_list], [status for status in status_list], [rel for rel in relevance_list])
        # run through dict and do bulk update
        for user_dict in users_dict:
            Profile.objects.filter(user__username=user_dict[0]).update(status=user_dict[1], relevance=user_dict[2])

        return HttpResponseRedirect(reverse('reader:admins_view'))

else:
    form = CViewerForm()

return {'users_list': users_list,
        'user': request.user,
        'form': form}

template:

<form class="form-horizontal" action="" method="post" name="update-form" class="well form-inline" id="view_form">
            {% csrf_token %}
            {{ form.non_field_errors }}
            {% for hidden in form.hidden_fields %}
               {{ hidden }}
            {% endfor %}

            {% if user.is_staff %}
                    <div>
                        <table class="table table-striped table-condensed">
                            <thead>
                                <tr>
                                    <th>{% trans 'Username' %} </th>
                                    <th>{% trans 'E-mail' %} </th>
                                    <th>{% trans 'Status' %} </th>
                                    <th>{% trans 'Relevance' %} </th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for user in users_list %}
                                <tr>
                                    <td><input type="text" READONLY name="username" value="{{ user.user.username }}"></td>
                                    <td>{{ user.user.first_name }}</td>
                                    <td>{{ user.user.last_name }}</td>
                                    <td>{{ user.user.email }}</td>
                                    <td>{{ user.get_status_display }}</td>
                                    <td>{{ user.get_relevance_display }}</td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                {% endif %}
                <br>
            {% endif %}
            <div class="form-actions">
                <input type="hidden" name="_cmd_personal">
                <input type="submit" class="btn btn-info" value="{% trans 'Update' %}" name="update" class="default">
            </div>
        </form>

Below is a solution:

forms.py (as @Liarez wrote).

template:

<form class="form-horizontal" action="" method="post" name="update-form" class="well form-inline" id="view_form">
{% csrf_token %}
{% if user.is_staff %}
    {% if users_list %}
        <div>
            <table class="table table-striped table-condensed">
                <thead>
                    <tr>
                        <th>{% trans 'Username' %} </th>
                        <th>{% trans 'First name' %} </th>
                        <th>{% trans 'Last name' %} </th>
                        <th>{% trans 'E-mail' %} </th>
                        <th>{% trans 'CV Status' %} </th>
                        <th>{% trans 'CV Relevance' %} </th>
                    </tr>
                </thead>
                <tbody>
                    {% for user in users_list %}
                    <tr>
                        <td><input type="text" READONLY name="username" value="{{ user.user.username }}"></td>
                        <td>{{ user.user.first_name }}</td>
                        <td>{{ user.user.last_name }}</td>
                        <td>{{ user.user.email }}</td>
                        <td>
                            <select name="cv_status">
                                {% for key, status in status_choices %}
                                    {% ifequal user.get_cv_status_display status %}
                                        <option value="{{ user.cv_status }}" selected>{{ user.get_cv_status_display }}</option>
                                    {% else %}
                                        <option value="{{ key }}">{{ status }}</option>
                                    {% endifequal %}
                                {% endfor %}
                            </select>
                        </td>
                        <td>
                             <select name="cv_signal">
                                {% for key, signal in signal_choices %}
                                    {% ifequal user.get_cv_signal_display signal %}
                                        <option value="{{ user.cv_signal }}" selected>{{ user.get_cv_signal_display }}</option>
                                    {% else %}
                                        <option value="{{ key }}">{{ signal }}</option>
                                    {% endifequal %}
                                {% endfor %}
                            </select>
                        </td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    {% endif %}
    <br>
{% endif %}
<div class="form-actions">
    <input type="submit" class="btn btn-info" value="{% trans 'Update' %}" name="update" class="default">
</div>

This question is related to python django choicefield

The answer is


Better Way to Provide Choice inside a django Model :

from django.db import models

class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    GRADUATE = 'GR'
    YEAR_IN_SCHOOL_CHOICES = [
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
        (GRADUATE, 'Graduate'),
    ]
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )

New method in Django 3

you can use Field.choices Enumeration Types new update in django3 like this :

from django.db import models

class Status(models.TextChoices):
    UNPUBLISHED = 'UN', 'Unpublished'
    PUBLISHED = 'PB', 'Published'


class Book(models.Model):
    status = models.CharField(
        max_length=2,
        choices=Status.choices,
        default=Status.UNPUBLISHED,
    )

django docs


If your choices are not pre-decided or they are coming from some other source, you can generate them in your view and pass it to the form .

Example:

views.py:

def my_view(request, interview_pk):
    interview = Interview.objects.get(pk=interview_pk)
    all_rounds = interview.round_set.order_by('created_at')
    all_round_names = [rnd.name for rnd in all_rounds]
    form = forms.AddRatingForRound(all_round_names)
    return render(request, 'add_rating.html', {'form': form, 'interview': interview, 'rounds': all_rounds})

forms.py

class AddRatingForRound(forms.ModelForm):

    def __init__(self, round_list, *args, **kwargs):
        super(AddRatingForRound, self).__init__(*args, **kwargs)
        self.fields['name'] = forms.ChoiceField(choices=tuple([(name, name) for name in round_list]))

    class Meta:
        model = models.RatingSheet
        fields = ('name', )

template:

<form method="post">
    {% csrf_token %}
    {% if interview %}
         {{ interview }}
    {% endif %}
    {% if rounds %}
    <hr>
        {{ form.as_p }}
        <input type="submit" value="Submit" />
    {% else %}
        <h3>No rounds found</h3>
    {% endif %}

</form>