我希望我的用户能够将对象添加到数据库(在我的情况下是一个文件),并且该对象自动转到最后的“位置”,之后该用户可以使用某种类型的用于将该对象更改为“高于”或“重新排序”表格的UI。
显然,表没有订单,它是数据表基础的一部分。 看完一些帖子后,我看到我有两个选择:
对我来说,我会从DB中读取比写入更多的内容,所以我选择了第一个。 我的问题是如何实现添加新文件,删除旧文件和更改订单。
目前,正如我每次对DB进行任何更改时所看到的那样,我必须调用ORDER_BY整数字段然后:
唯一的问题是我觉得make和order_by调用非常昂贵,并且每次稍微更改都会更改这么多数据库行。还有其他方法吗?我确定这是一个非常普遍的问题。
答案 0 :(得分:3)
我会做什么(以及我做了什么)是存储'订单'字段。当您按顺序选择并取回记录时,您可以通过此列进行订购。
至于如何插入和重新排序,这取决于数据量。对于一个简单的“Todo”类型的应用程序,你有< 100个项目(我从空中抓取了这个数字),加载那么多Model
个对象,更新它们的数量并保存它们没有错。
如果您有已排序的模型列表,则可以使用以下命令更新订单:
for i, model in enumerate(models):
model.sort_order = i
model.save()
在优化方面:
您的号码不必连续。如果删除记录,则不必修改任何其他记录,它们仍然是有序的。这就是一次操作。
如果您想经常插入,那么您可以进行一项优化是留下空白(例如model.sort_order = i * 10
),然后您可以在两个记录之间插入空格。如果你的空间不足,那么你可以采取两种策略中的一种,具体取决于你的用例:
如果频繁插入,则可以重新编号,如上所述(留出较大的空格)。重新编号很昂贵,但你不得不经常这样做
如果不进行频繁插入,可以将数字向下移动(即插入元素后增加数字)。在最糟糕的情况下,这与完整的重新编号一样昂贵,但在一般情况下,价格只有一半。
如果要交换两个项目,只需交换排序顺序即可。这只需要两次更新。
因此,您需要更新超过2条记录的唯一情况是您的空间不足或者您想要完全更改所有记录的顺序。
对于更大的列表,您可以编写一些自定义SQL来重新排列数字,但只有在您开始注意到问题后才应该这样做。
答案 1 :(得分:1)
您可以使用单个ORM调用更新数据库中整个系列行的订单字段,该调用转换为单个数据库匹配:
MyModel.objects.filter(sort_order__gt=300).update(val=F('sort_order')+1)
这会将大于300的所有对象的sort_order
字段加1,允许您在那里插入新对象。
答案 2 :(得分:1)
我刚刚提出了如何重新排序大组行而不必更改“全部”记录的想法,所以我从未测试过它。您仍然需要“订单”列,但它将是float
而不是int
。
假设你在数据库中有这个:
(A,1), (B,2), (C,3), (D,4), (E,5), (F,6), (G,7)
(其中第二个值是“订单”字段) 你想在D之前移动F,即:
(A,1), (B,2), (C,3), (F,6), (D,4), (E,5), (G,7)
更新“订单”字段的算法是:
现在你的表现在看起来像这样:
(A,1), (B,2), (C,3), (F,4), (D,4.5), (E,5), (G,7)
另一个例子,现在让我们在D之前移动A,即:
(B,2), (C,3), (F,4), (A,1), (D,4.5), (E,5), (G,7)
我们再次使用相同的algorythm更新订单字段。首先,我们将A的顺序设置为D的顺序,D的顺序设置为旧的值和下一个的一半:
(B,2), (C,3), (F,4), (A,4.5), (D,4.75), (E,5), (G,7)
有了这个算法,你只需要做两个只涉及每行1行的UPDATES。也许你的桌子上也需要一个“下一个”字段...如果有一天订单变得混乱,你可以随时将它们重置为整数值
我刚刚提出这个想法,也许还有更有效的方法:P
希望这有帮助