Django ChoiceField

Я пытаюсь решить следующую проблему:

У меня есть веб-страница, которую могут видеть только модераторы. Поля, отображаемые на этой странице (после регистрации пользователя):
Имя пользователя, Имя+Фамилия, Электронная почта, Статус, Релевантность и т. д.

Мне нужно отобразить таблицу с информацией обо всех пользователях, хранящихся в БД, с этими полями, но в двух полях есть варианты, поэтому я хочу сделать так, чтобы модераторы могли выбрать другой вариант, и после нажатия кнопки «Обновить» эти поля будут обновлены для выбранного пользователя .

Я могу отображать все варианты полей статуса и релевантности, и после того, как я выбираю новые параметры из раскрывающегося списка, база данных обновляется.
Я хочу отображать раскрывающиеся списки, и следует выбрать параметр, хранящийся в базе данных. Я пробовал много вариантов, много времени гуглил, искал ответ или правильное направление и в StackOverFlow, но ничего не нашел.

Извините за мой плохой английский и заранее спасибо за помощь!

Ниже приведена часть моего кода:

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}

шаблон:

<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>

Ниже приведено решение:

form.py (как написал @Liarez).

шаблон:

<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>

person Denis    schedule 25.06.2014    source источник


Ответы (4)


Сначала я рекомендую вам, поскольку @ChrisHuang-Leaver предложил определить новый файл со всеми вариантами, которые вам нужны, например choices.py:

STATUS_CHOICES = (
    (1, _("Not relevant")),
    (2, _("Review")),
    (3, _("Maybe relevant")),
    (4, _("Relevant")),
    (5, _("Leading candidate"))
)
RELEVANCE_CHOICES = (
    (1, _("Unread")),
    (2, _("Read"))
)

Теперь вам нужно импортировать их в модели, чтобы код был понятен следующим образом (models.py):

from myApp.choices import * 

class Profile(models.Model):
    user = models.OneToOneField(User)    
    status = models.IntegerField(choices=STATUS_CHOICES, default=1)   
    relevance = models.IntegerField(choices=RELEVANCE_CHOICES, default=1)

И вам необходимо импортировать варианты в forms.py:

формы.py:

from myApp.choices import * 

class CViewerForm(forms.Form):

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

В любом случае у вас есть проблема с вашим шаблоном, потому что вы не используете никаких {{form.field}}, вы создаете таблицу, но в ней нет входных данных, только скрытые_поля.

Когда пользователь является штатным, вы должны создать столько полей ввода, сколько пользователей вы можете контролировать. Я думаю, что форма django - не лучшее решение для вашей ситуации.

Я думаю, вам будет лучше использовать html-форму, чтобы вы могли генерировать как можно больше входных данных с помощью букле: {% for user in users_list %}, и вы генерируете ввод с идентификатором, связанным с пользователем, и вы можете управлять всеми ими в представлении.

person AlvaroAV    schedule 25.06.2014
comment
Большое тебе спасибо! Это правильное направление для меня, и я сделал это, как требовалось! - person Denis; 25.06.2014
comment
Приятно быть полезным! - person AlvaroAV; 25.06.2014
comment
Наличие вариантов в отдельном, но небольшом файле Python и его включение было бы лучше, чем дублирование. Когда-нибудь в будущем все изменится... - person Chris Huang-Leaver; 20.05.2015
comment
@ChrisHuang-Leaver, вы правы, я обновил вопрос - person AlvaroAV; 20.05.2015

Лучший способ предоставить выбор внутри модели django:

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,
    )
person santhosh_dj    schedule 26.12.2019

Если ваш выбор не определен заранее или исходит из какого-то другого источника, вы можете сгенерировать его в своем представлении и передать в форму.

Пример:

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', )

шаблон:

<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>
person Arindam Roychowdhury    schedule 03.10.2018

Новый метод в Django 3

вы можете использовать новое обновление Field.choices Enumeration Types в django3 следующим образом:

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

person hassanzadeh.sd    schedule 22.11.2020