带额外条目的表单集拖放排序

3 投票
2 回答
3406 浏览
提问于 2025-04-15 17:34

我一直在寻找一种方法,让用户可以轻松地改变表单中条目的顺序。我发现了一个StackOverflow的问题,讨论了这个主题,里面的一个被接受的答案提到了一段Django代码片段,它使用了一个JQuery工具,允许通过拖放的方式来调整条目。这听起来很酷,但我遇到了一个关于“额外”条目的问题。如果我修改了一个“额外”条目,然后拖动它,提交时就会出现错误:

(1048, "Column 'order' cannot be null")

我认为Django会把“额外”条目分开处理,因为这些条目需要插入,而不是更新。所以重新排序可能会让事情变得复杂。有没有办法让这个功能正常工作,或者有没有其他建议来重新排序和/或添加新条目呢?

编辑:添加了一些相关的代码片段。我正在管理员界面中尝试这个,正如代码片段所示。不过,我最终想把它放到我自己的页面上。

models.py:

class Section(models.Model):
    section_id = models.AutoField(primary_key=True)
    section_name = models.CharField(max_length=135)
    score_order = models.IntegerField()
    def __unicode__(self):
      return self.section_name
    class Meta:
        db_table = u'section'
        ordering = [u"score_order"]

class Chair(models.Model):
    chair_id = models.AutoField(primary_key=True)
    member = models.ForeignKey(Member, null=True, blank=True,
      limit_choices_to={'current_member': True})
    section = models.ForeignKey(Section)
    description = models.CharField(max_length=135)
    order = models.IntegerField(blank=True, null=True)
    def __unicode__(self):
      return "%s - %s" % (self.description, self.member)
    class Meta:
        db_table = u'chair'
        ordering = (u'section', u'order')

admin.py

class SectionForm(forms.ModelForm):
    model = Section
    class Media:
        js = (
            '/scripts/jquery.js',
            '/scripts/ui.core.js',
            '/scripts/ui.sortable.js',
            '/scripts/section-sort.js',
        )

class ChairInline(admin.StackedInline):
    model = Chair

admin.site.register(Section,
                    inlines = [ChairInline],
                    form = SectionForm,
)

2 个回答

1

我在我的一个应用程序中使用可排序的表单集合。为了实现这个功能,我用的是一个jQuery的拖放插件:

http://www.isocra.com/2008/02/table-drag-and-drop-jquery-plugin/

我把这个插件的onDrop事件绑定到一个函数,这个函数会重置所有“顺序”字段的值。

另外,我还给表单集合传递了一些初始数据,这样即使在没有JavaScript的情况下,表单集合的额外“顺序”字段也总是有值。虽然用户无法重新排序行,但他们可以编辑并提交更改,而不会出现你提到的空值错误。

3

我找到了自己的解决办法。这个代码片段是为每一行设置顺序,只要那行的主键有值就会设置。但是那些额外的行主键是空的,我觉得它们必须保持空白,这样Django才能知道这些行是要插入的,而不是更新的。我修改了这个函数,让它检查其他字段是否也为空(幸运的是,我只有几个字段),还有主键:

jQuery(function($) {
    $('div.inline-group').sortable({
        items: 'div.inline-related',
        handle: 'h3:first',
        update: function() {
            $(this).find('div.inline-related').each(function(i) {
                if ($(this).find('input[id$=chair_id]').val() ||
                  $(this).find('select[id$=member]').val() ||
                      $(this).find('select[id$=description]').val()) {
                    $(this).find('input[id$=order]').val(i+1);
                }
            });
        }
    });
    $('div.inline-related h3').css('cursor', 'move');
    $('div.inline-related').find('input[id$=order]').parent('div').hide();
});

这样就解决了我的问题。我可能可以通过在表单中添加一个隐藏字段来进一步改进这个功能,这个字段会在任何行的字段被修改时设置。但是现在我还是个jQuery新手,所以这样就可以了。如果有人有更好的主意,欢迎评论或者添加其他答案。

撰写回答