用于选择多行并在操作之间进行选择的表格

时间:2012-09-18 06:30:32

标签: django select row

我正在组建一个Django网站,我正处于一个车辙。

该网站提供了许多用于添加和编辑数据的表单,这是非常基本的,但是当它涉及到外键关系时,我需要更多选项。假设我有一个出售的“产品”类,对于数据库中的所有产品,我想添加一个对象“维护”,“年费”或者不是。

我可以简单地创建一个带有select-multiple字段的表单,在这里我选择我想要的产品,然后选择另一个字段来输入维护对象的参数。这样可以添加,但如果我想编辑/删除/绘制关系/生成报告和类似的内容会怎么样?

我在想的是,如果产品列在可滚动,可排序,可过滤的表格中(这些东西我可以轻松处理),那就太好了。这个表需要的是让我能够选择行(即:对象。)我想要操作,然后有多个提交按钮用于各种功能。

提交按钮,我可以处理,但我不知道如何使表行可选。一些javascript,我收集?

我在某处读到,如果每行都有一个隐藏的复选框绑定到对象主键,那么javascript可以处理行上的点击并选择/取消选中隐藏的复选框并适当地为行着色。

或者,有JQuery的'Selectable',但这对我来说似乎很抽象。

这会是一个好方法吗?建议?示例代码?

2 个答案:

答案 0 :(得分:3)

是的,这需要做很多工作,所以就这样了。

当我想创建一个使用tabledata而不是用户输入数据的表单时,我使用以下类:

class TableRowForm():
    '''
    This form is special, because usually, forms include a range of inputs
    to be filled out by the user. This form however, no inputs are filled in. The
    form is given a queryset of objects and a list of field names, and with those,
    a table is made. Each row in the table represents an object. clicking a row
    will select the object. Multiple submit buttons can be given with various
    functions. What these buttons have in common is that they all operate on the
    selected objects, e.g. selecting three objects and pressing delete will delete
    those three objects. The form is different in that it does not create new objects,
    it manipulates already existing objects.
    '''
    def __init__(self, queryset, fields):
        if not fields:
            raise Exception('A TableRowForm must be supplied both queryset and fields')
        self.queryset = queryset
        self.fields = fields

    def __unicode__(self):
        '''
        Builds the html table rows for the form.
        '''
        if not self.queryset: return '<tr><td>No data...<td></tr>'
        colcount = 0
        res = ""
        res += "<tr>"
        for f in self.fields:
            res += "<th>"+self.queryset[0]._meta.get_field_by_name(f)[0].verbose_name+"</th>"
        res += "</tr>\n"
        for obj in self.queryset:
            res += '<tr onclick="selectRow(this)">'
            res += '<td><input style="display:none;" type="checkbox" name="slct" id="%s" value="%s"/>'%(obj.pk,obj.pk)

            vals = [getattr(obj, x) for x in self.fields]
            colcount = len(vals)
            for x in vals:
                res += '%s</td><td>'%(str(x))
            res = res[:-4]
            res += '</tr>\n'
        res += '<tr><th colspan="%d"><span style="font-size:9pt;"><b>Selctable table:</b> Click a row to select it</span></th></tr>'%(colcount)

        # Add the javascript that implements functionality
        res += '''\
        <script>
        // Allows for selectable tablerows in forms
        function selectRow(row)
        {
            // Check/uncheck the checkbox
            var chk = row.getElementsByTagName('input')[0];
            chk.checked = !chk.checked;

            // Color the row in response to the checkbox's boolean value
            if (chk.checked) {
                row.style.backgroundColor = 'gray';
            } else {
                row.style.backgroundColor = 'white';
            }
        }
        </script>'''
        return res

这样做是需要显示数据的查询集和要显示的所需字段的列表,然后使用提供的数据构建表,并为每行隐藏复选框。

在构建表之后,会附加一个javascript来帮助选中复选框并相应地为表格着色。

创建这样的表单可能会是这样的:

trform = TableRowForm(queryset=Item.objects.all(),
                                 fields=('serial',
                                         'prod',
                                         'discount',
                                         'price',
                                         'account',
                                         'vat',))

在模板中使用此表单时,应该像这样完成

<form action="{% url bla.bla.bla %}" method="post">
<table>
{{ form|safe }}
</table>
<input type="submit" name="testform" value="Test" />
</form>

过滤器'| safe'确保解释HTML而不是仅仅写为文本。

表标记不是自动生成的原因是表单可能不是整个表本身,因此表单只为表创建行。

如果我们有多个提交按钮,则在表单中的提交按钮上放置'name'属性是管理要采取的操作的好方法。人们可以想象对数据表采取任意数量的行动。

最后,当点击提交按钮时,处理表单数据可以按如下方式完成:

if 'testform' in request.POST:
        # These two lines fetch all the selected objects from the tablerow form
        selections = request.POST.getlist('slct')
        its = Item.objects.filter(pk__in=selections)

此示例假定table-row-form上使用的对象类型为Item。 'slct'是自动赋予表单中复选框的名称。可以想象通过允许从request.POST实例创建表单来使这更聪明,让表单自动从POST数据中提取信息,但我还没有那么远;)

“request.POST.getlist('slct')”基本上获取以'slct'命名的所有值并将它们放入列表中。在此之后,您可以通过查询主键轻松检索它们所代表的对象。

我希望这对我以外的人有用。我为自己取得的成就感到自豪:)

答案 1 :(得分:0)

您不必创建自己的表单类 - 并在其中嵌入javascript。正确的方法是使用form media,或者只需按照以下方式执行:

{% for a in some_queryset %}
   <tr>
      <td><input type="checkbox" id="pk" name="pk" value={{ a.pk }} /></td>
      <td>{{ a.name }}</td>
   </tr>
{% endfor %}

# later on ...

<input 
    type="submit"
    name="action1"
    value="Do Action 1"
    id="action1_btn" class="btn btn-primary disabled" />
<input
    type="submit"
    name="action2"
    value="Do Action 2"
    id="action2_btn"
    class="btn btn-danger disabled" />

# and other buttons...

最后,这一点javascript:

<script type="text/javascript">
$('#pk').click(function() {
  if ($('input[name="pk"]:checked').length > 0)
  {
     // more than one check box is checked
     $("#action1_btn").removeClass('disabled');
     $("#action2_btn").removeClass('disabled');
     // other actions you want to do

  } else {

     // No check boxes are checked
     $("#action1_btn").addClass('disabled');
     $("#action2_btn").addClass('disabled');
  }
});
</script>

此脚本仅在检查行时启用按钮。

最后,django提供的formsets完全按照您在此处复制的内容进行操作。