Форма Django с неизвестным количеством полей флажка и несколькими действиями

Мне нужна помощь с формой, которая выглядит как входящая почта Gmail и имеет несколько действий. Существует список элементов, и я хочу обернуть его формой, так как каждый элемент имеет флажок перед линией. Поэтому, когда пользователь выбирает несколько элементов, он может щелкнуть по двум кнопкам с различными действиями, например, удалить и пометить прочитанные.

<form action="">
    {% for item in object_list %}
    <input type="checkbox" id="item.id">
    {{ item.name }}
    {% endfor %}
    <button type="submit" name="delete">Delete</button>
    <button type="submit" name="mark_read">Mark read</button>
</form>

Я могу найти кнопку отправки, которую пользователь нажимает, если используется if 'delete' in request.POST, но я не могу обратиться к любой форме, потому что форма Django не может быть определена с неизвестным количеством полей, как я думаю. Итак, как я могу обрабатывать выбранные элементы в поле зрения?

if request.method == 'POST':
    form = UnknownForm(request.POST):
    if 'delete' in request.POST:
        'delete selected items'
    if 'mark_read' in erquest.POST:
        'mark selected items as read'
    return HttpResponseRedirect('')

Ответ 1

Несколько флажков с одинаковым именем - все те же поля.

<input type="checkbox" value="{{item.id}}" name="choices">
<input type="checkbox" value="{{item.id}}" name="choices">
<input type="checkbox" value="{{item.id}}" name="choices">

вы можете собирать и группировать их с помощью одного поля формы django.

class UnknownForm(forms.Form):
    choices = forms.MultipleChoiceField(
        choices = LIST_OF_VALID_CHOICES, # this is optional
        widget  = forms.CheckboxSelectMultiple,
    )

В частности, вы можете использовать ModelMultipleChoiceField.

class UnknownForm(forms.Form):
    choices = forms.ModelMultipleChoiceField(
        queryset = queryset_of_valid_choices, # not optional, use .all() if unsure
        widget  = forms.CheckboxSelectMultiple,
    )

if request.method == 'POST':
    form = UnknownForm(request.POST):
    if 'delete' in request.POST:
        for item in form.cleaned_data['choices']:
            item.delete()
    if 'mark_read' in request.POST:
        for item in form.cleaned_data['choices']:
            item.read = True; item.save()

Ответ 2

Я не могу прокомментировать решение Thomas, поэтому я делаю это здесь.

Для ModelMultipleChoiceField имя аргумента не является выбором, кроме набора запросов.

Итак, чтобы взять последний пример:

class UnknownForm(forms.Form):
choices = forms.ModelMultipleChoiceField(
    choices = queryset_of_valid_choices, # not optional, use .all() if unsure
    widget  = forms.CheckboxSelectMultiple,
)

Ответ 3

У меня была эта же проблема, используя базовое представление класса и повторяя список неизвестного размера в HTML-шаблоне Django.

Это решение использует "пост" и работает для меня. Я делаю это здесь, потому что вышеупомянутые решения были полезны, но не решили проблему с циклом для меня.

Шаблон HTML:

<form action="" method="post">
    {% for item in object_list %}
        <input type="checkbox" value="{{item.id}}" name="my_object">
        {{ item.name }}
    {% endfor %}
    <button type="submit" name="delete">Delete</button>
    <button type="submit" name="mark_read">Mark read</button>
</form>

Форма:

class MyForm(forms.Form):
    my_object = forms.MultipleChoiceField(
        widget=forms.CheckboxSelectMultiple,
    )

В представлении, основанном на классе, обращайтесь к данным POST с помощью функции post. Это позволит получить доступ к списку ваших отмеченных элементов, вашего контекста и других данных формы.

Вид:

Class MyView(FormView):
    template_name = "myawesometemplate.html"
    form_class = MyForm
...
# add your code here 

    def post(self, request, *args, **kwargs):
        ...
        context = self.get_context_data()
        ...
        if 'delete' in request.POST:
            for item in form.POST.getlist('my_object'):
                # Delete
        if 'mark_read' in request.POST:
            for item in form.POST.getlist('my_object'):
                # Mark as read

Ответ 4

Я нашел, что это очень полезно при добавлении групп или разрешений пользователю.

Убедитесь, что у вас есть стандартные группы django и разрешения, включенные в ваше представление для страницы.

from django.contrib.auth.models import Permission, Group

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

    groups = forms.ModelMultipleChoiceField(label='Groups', required=False, queryset=Group.objects.all(), widget=forms.CheckboxSelectMultiple)
user_permissions = forms.ModelMultipleChoiceField(label='Permissions', required=False, queryset=Permission.objects.all(), widget=forms.CheckboxSelectMultiple)

Затем в почтовом разделе метода просмотра для этой страницы вы можете получить выбранные варианты, возвращенные как список объектов выбора, и добавить их к объекту пользователя с циклом for.

u.save()  # required to save twice, so this saves the other form fields.
        user.groups.clear()
        u.user_permissions.clear()
        # print('Group name:', form.cleaned_data['groups'])
        for group in form.cleaned_data['groups']:
            print(group)  # Prints to your console for debugging
            user.groups.add(group)
        for permission in form.cleaned_data['user_permissions']:
            print(permission)  # Prints to your console for debugging
            user.user_permissions.add(permission)
        u.save()  #This saves the groups and permissions

Это может по-прежнему нуждаться в некоторой логике, если группы не выбраны, но должно быть достаточно для начала.