Formsets с флажками - PullRequest
       10

Formsets с флажками

4 голосов
/ 18 ноября 2010

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

Например, скажем, у меня есть экран выбора пользователя для модели:

class User(model):
   first = # char field
   last  = # char field
   birthdate = # date

Затем я хочу показать пользователям и позволить им выбрать одного из них:

Please select users:
[] John  Smith   Jan, 2001
[] Mike  Davis   Feb, 2002
[] John  Doe     Dec, 2000

[Continue]

Эта форма будет отправлена ​​и обработана.

Один из способов сделать это - ModelFormset. Проблема в том, что когда я пытаюсь использовать ModelFormsets для отображения пользователей, я не могу добавить флажок.

Другой способ, о котором я могу подумать, - это создать форму и вывести на нее целую кучу флажков с определенным идентификатором. Затем при отправке - переберите все выбранные флажки. Не уверен, как это будет работать с формами Джанго.

Любые предложения приветствуются. Спасибо.

РЕДАКТИРОВАТЬ: Хорошо получается, что, дав каждому флажку идентификатор (например, идентификатор пациента) в пределах одной и той же группы имен и просто просматривая словарь POST в представлении django, я получаю именно то, что мне нужно!

Ответы [ 2 ]

3 голосов
/ 22 ноября 2010

Я создал пользовательский виджет SelectMultiple для отображения сведений об объекте вместе с флажком для выбора, когда формы еще назывались newforms - он все еще работает:

from django.forms import CheckboxInput, SelectMultiple
from django.utils.encoding import force_unicode
from django.utils.html import escape
from django.utils.safestring import mark_safe

class TableSelectMultiple(SelectMultiple):
    """
    Provides selection of items via checkboxes, with a table row
    being rendered for each item, the first cell in which contains the
    checkbox.

    When providing choices for this field, give the item as the second
    item in all choice tuples. For example, where you might have
    previously used::

        field.choices = [(item.id, item.name) for item in item_list]

    ...you should use::

        field.choices = [(item.id, item) for item in item_list]
    """
    def __init__(self, item_attrs, *args, **kwargs):
        """
        item_attrs
            Defines the attributes of each item which will be displayed
            as a column in each table row, in the order given.

            Any callables in item_attrs will be called with the item to be
            displayed as the sole parameter.

            Any callable attribute names specified will be called and have
            their return value used for display.

            All attribute values will be escaped.
        """
        super(TableSelectMultiple, self).__init__(*args, **kwargs)
        self.item_attrs = item_attrs

    def render(self, name, value, attrs=None, choices=()):
        if value is None: value = []
        has_id = attrs and 'id' in attrs
        final_attrs = self.build_attrs(attrs, name=name)
        output = []
        str_values = set([force_unicode(v) for v in value]) # Normalize to strings.
        for i, (option_value, item) in enumerate(self.choices):
            # If an ID attribute was given, add a numeric index as a suffix,
            # so that the checkboxes don't all have the same ID attribute.
            if has_id:
                final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
            cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
            option_value = force_unicode(option_value)
            rendered_cb = cb.render(name, option_value)
            output.append(u'<tr><td>%s</td>' % rendered_cb)
            for attr in self.item_attrs:
                if callable(attr):
                    content = attr(item)
                elif callable(getattr(item, attr)):
                    content = getattr(item, attr)()
                else:
                    content = getattr(item, attr)
                output.append(u'<td>%s</td>' % escape(content))
            output.append(u'</tr>')
        return mark_safe(u'\n'.join(output))

Пример формы:

class JobSelectionForm(forms.Form):
    jobs = forms.MultipleChoiceField(widget=TableSelectMultiple(
               item_attrs=('formatted_number', 'name', 'client', 'get_status_display')))

    def __init__(self, accessible_jobs, *args, **kwargs):
        super(JobSelectionForm, self).__init__(*args, **kwargs)
        self.fields['jobs'].choices = [(j.id, j) \
                                       for j in accessible_jobs]

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

Шаблон:

{% if form.jobs.errors %}{{ form.jobs.errors }}{% endif %}
<table>
<thead>
  <tr>
    <th>&nbsp;</th>
    <th>Number</th>
    <th>Name</th>
    <th>Client</th>
    <th>Status</th>
  </tr>
</thead>
<tbody>
{{ form.jobs }}
</tbody>
</table>
1 голос
/ 18 ноября 2010

Вам не нужен набор форм, поскольку он предназначен для редактирования данных в наборе экземпляров модели. Вам нужна отдельная форма с ModelChoiceField или ModelMultipleChoiceField - вам может потребоваться изменить виджет на CheckboxSelectMultiple.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...