说我想要一个项目,以及一对多的待办事项,并想要任意重新订购待办事项?
过去,我添加了一个带编号的订单字段,当有人想要更改订单时,必须使用新的订单号更新所有商品。这可能是最糟糕的方法,因为它不是原子和需要多次更新。
我注意到Django有一个多值的CommaSeparatedIntegerField,它可以通过将订购的密钥存储在项目表的一个字段中的待办事项表中的项目来包含订单。
我考虑过一个杜威十进制系统,如果我想把项目3放在1和2之间,我会把它的订单号改为1.5。
有些东西告诉我,虽然我有一个更容易的选择...
你如何命令一对多关系?
答案 0 :(得分:5)
我讨厌这个问题......我一直都遇到它。
对于我最近的Django网站,我们有一份包含N篇文章的时事通讯,当然,订单很重要。我将默认订单指定为升序Article.id,但如果以“正确”顺序以外的其他方式输入文章,则会失败。
在Newsletter change_form.html页面上,我使用Interface插件(http://interface.eyecon.ro/)添加了一些jQuery魔法。我显示相关文章的标题,用户可以随意拖动它们。有一个onChange处理程序可以重新计算article_order字段中的Article.id。
享受,
彼得
对于app = content,model = Newsletter,以下是 模板/管理/内容/ newslettter / change_form.html
{% extends 'admin/change_form.html' %}
{% block form_top %}{% endblock %}
{% block extrahead %}{{ block.super }}
<script type="text/javascript" src="/media/js/jquery.js"></script>
<script type="text/javascript" src="/media/js/interface.js"></script>
<script>
$(document).ready(
function () {
$('ol.articles').Sortable(
{
accept : 'sortableitem',
helperclass : 'sorthelper',
activeclass : 'sortableactive',
hoverclass : 'sortablehover',
opacity: 0.8,
fx: 200,
axis: 'vertically',
opacity: 0.4,
revert: true,
trim: 'art_',
onchange:
function(list){
var arts = list[0].o[list[0].id];
var vals = new Array();
var a;
for (a in arts) {
vals[a] = arts[a].replace(/article./, '');
}
$('#id_article_order').attr('value', vals.join(','));
}
});
}
);
</script>
{% endblock %}
{% block after_related_objects %}
{% if original.articles %}
<style>
.sortableitem {
cursor:move;
width: 300px;
list-style-type: none;
}
</style>
<h4>Associated Articles</h4>
<ol class="articles" id="article_list">
{% for art in original.articles %}
<li id="article.{{art.id}}" class="sortableitem">{{art.title}}</li>
{% endfor %}
</ol>
{% endif %}
{% endblock %}
答案 1 :(得分:2)
“添加了编号的订单字段” - 很好。
“使用新的订单号更新所有商品” - 可以避免。
使用带间隙的数字。
浮点。这样,有人可以在1和2之间插入“1.1”。我发现这很好用,因为大多数人都能理解测序的工作原理。而且你不必过多担心要留下多少空间 - 每个数字之间有很多很大的空间。
在初始加载时,将文章编号为100或1000或每个文章之间有空格。在这种情况下,您必须猜测要重新排序的数字。
以逗号分隔的位置。最初,它们都是(1,0),(2,0),(3,0)等等。但是当你想要重新排列东西时,你可能需要引入(2,1)和(2,2)在(2,0)之后但在之前(3.0)。
这看起来很复杂,但有些人喜欢这种复杂性。它基本上与浮点相同,除了单个数字被(整数,隐式分数)元组替换。这扩展到处理层次结构。
答案 2 :(得分:2)
我遇到过这个问题,我在最近的一段时间内完成了两个项目。对于我的示例解决方案,我有一个“表单”,其中分配了许多“变量”,表单上的变量顺序需要是可排序的。所以我实现了以下内容:
models.py
class Form(models.Model):
FormName = models.CharField(verbose_name="Form Name:", max_length=40)
VariableOrder = models.CommaSeparatedIntegerField(default="[]", editable=False)
def __unicode__(self):
return "%s" % (self.FormName)
class Variable(models.Model):
FormID = models.ForeignKey(Form, default=0, editable=False, related_name="Variable")
VarName = models.CharField(max_length=32, verbose_name="Name of variable in the database:")
def __unicode__(self):
return "%s" % self.VarName
上面的键是VariableOrder CommaSeparatedIntegerField是我们要在Form上存储Variables的顺序的地方,我们将把它用作python列表,这就是默认为[]的原因。 / p>
对于模板,我将我的变量渲染为一个我们将要拖放的排序(我实际使用的列表元素有更多与CSS相关的样式和有关变量的信息)。
<ul id="sortable">
{% for Variable in VarList %}
<li id="{{ Variable.id }}">{{ Variable }}</li>
{% endfor %}
</ul>
现在我们将拖放列表以便更改订单。 要实现这一点,您需要从头开始使用Django网站的AJAX CSRF代码段
$(function() {
$("#sortable" ).sortable({
placeholder: "ui-state-highlight",
update: function(event, ui){
$.ajax({
type:"POST",
url:"{% url builder.views.variableorder %}",
data: {Order: JSON.stringify($('#sortable').sortable('toArray')) },
success: function(data){
// Do stuff here - I don't do anything.
}
});
}
});
$( "#sortable" ).disableSelection();
});
上面的重要部分是“update”在每次发送任何变量的位置变化时调用该函数,这些变量发送AJAX。 toArray on sortable和JSON stringify让我们发送每个变量的从上到下的id,视图使用如下。 注意:我将活动的Form对象保留为会话变量,但在另一种情况下,您只需要调用您想要更改其顺序的Form对象。
def variableorder(request):
if request.is_ajax():
Order = request.POST['Order']
updateOrder = request.session['FormID']
updateOrder.VariableOrder = newOrder
updateOrder.save()
request.session['FormID'] = Form.objects.get(id=updateOrder.id)
return HttpResponse("Order changed.")
else:
pass
所有这一切的关键是您可以通过评估字符串将此CommaSeparatedIntegerField用作列表。例如:
添加变量:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
newVar = Variable(stuff in here)
newVar.save()
currentOrder.append(newVar.id)
aForm.VariableOrder = currentOrder
aForm.save()
删除变量:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
# Variable ID that we want to delete = 3
currentOrder.remove(3)
aForm.VariableOrder = currentOrder
aForm.save()
按顺序渲染变量:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
VarList = []
for i in currentOrder:
VarList.append(Variable.objects.get(id=i))
这是我将要使用的粗略初稿,但它对我来说效果很好。显而易见的第一个改进是对python列表的评估是类中的方法。例如。
def getVarOrder(self):
return eval(self.VariableOrder)
然后在想要操作列表时调用Form.getVarOrder()。无论如何,希望这会有所帮助。
JD
答案 3 :(得分:1)
我已经遇到过这么多次,我已经决定在BL或UI中动态管理这些,然后只要用户满意就将命令持久保存到专用列。 SQL只是专门设计的,不处理排序,它总是反击。
答案 4 :(得分:0)
这是问题的最新答案,但我只是想插入并指出B-Trees对于这类事情来说是一个很好的数据结构,特别是如果您的访问模式不需要您检索整个清单。