1

我正在整理一个 Django 网站,并且处于一个常规状态。

该站点具有许多用于添加和编辑数据的表单,这非常基本,但是当涉及外键关系时,我需要更多选择。假设我有一个已售出的“产品”类,对于数据库中的所有产品,我想添加一个对象“维护”、“年费”等等。

我可以简单地制作一个带有多选字段的表单,在其中选择我想要的产品,然后选择另一个字段用于输入维护对象的参数。这可以添加,但是如果我想编辑/删除/绘制关系/生成报告和类似的东西怎么办?

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

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

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

或者,还有 JQuery 的“可选”,但这对我来说似乎很抽象。

什么是解决这个问题的好方法?建议?示例代码?

4

2 回答 2

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 被解释而不是仅仅写为文本。

表格标签没有自动生成的原因是表格可能不是整个表格本身,所以表格只为表格生成行。

如果我们有多个提交按钮,则将“名称”属性放在表单中的提交按钮上是一种管理要执行的操作的好方法。可以想象对一张数据表执行任意数量的操作。

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

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' 命名的值并将它们放在一个列表中。在此之后,您可以通过查询主键轻松检索它们所代表的对象。

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

于 2012-09-27T11:50:17.850 回答
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 提供了完全按照您在此处复制的内容的表单集。

于 2012-09-27T12:06:17.957 回答