带额外条目的表单集拖放排序
我一直在寻找一种方法,让用户可以轻松地改变表单中条目的顺序。我发现了一个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 个回答
我在我的一个应用程序中使用可排序的表单集合。为了实现这个功能,我用的是一个jQuery的拖放插件:
http://www.isocra.com/2008/02/table-drag-and-drop-jquery-plugin/
我把这个插件的onDrop事件绑定到一个函数,这个函数会重置所有“顺序”字段的值。
另外,我还给表单集合传递了一些初始数据,这样即使在没有JavaScript的情况下,表单集合的额外“顺序”字段也总是有值。虽然用户无法重新排序行,但他们可以编辑并提交更改,而不会出现你提到的空值错误。
我找到了自己的解决办法。这个代码片段是为每一行设置顺序,只要那行的主键有值就会设置。但是那些额外的行主键是空的,我觉得它们必须保持空白,这样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新手,所以这样就可以了。如果有人有更好的主意,欢迎评论或者添加其他答案。