我有一个代表Session
的模型(比如一小时一班的小孩),它有许多必须跟随订单的关联Task
s。更容易理解:
class Task(models.Model):
(...)
order = models.PositiveIntegerField('offset from the beginning of a Session')
session = models.ForeignKey(Session, related_name='tasks')
unique_together = ('session', 'order')
ordering = ('order', )
假设我想要更新单个会话order
(想象一下常见的拖放重新排序)。因此,通过更新一个任务的顺序,我需要重新排序其余的任务,以便唯一性不会制动。
图形示例(让我们说我希望pk=5014
的任务位于第二个位置(order=1
))
Initial state: Final state:
| pk | order | name | | pk | order | name |
|------|-------|------| |------|-------|------|
| 5011 | 0 | A | | 5011 | 0 | A |
| 5012 | 1 | B | ----> | 5014 | 1 | D |
| 5013 | 2 | C | | 5012 | 2 | B |
| 5014 | 3 | D | | 5013 | 3 | C |
我的问题是如何使用Django ORM更新它(如果可能的话)或者这是一种优雅的方式,因为我只能想到用新订单保存所需的任务(比如订单= 50),然后重新排列其余任务,最后将所需顺序重新分配给所需任务。
是否有类似bulk_update
的内容(经过长时间的研究后我没有发现任何相似内容),这样我就可以修改所有任务的order
字段,然后立即保存所有内容?或者我必须自己照顾这个unique_together吗?
答案 0 :(得分:2)
通常最好重用现有的解决方案:
https://github.com/bfirsh/django-ordered-model
虽然它仍然按顺序归结为2次保存:
https://github.com/bfirsh/django-ordered-model/blob/master/ordered_model/models.py#L122-L123
另见:
https://www.djangopackages.com/grids/g/model-ordering/
最好的办法是编写一个自定义SQL查询,类似于
将DB约束作为示例中的unique_together
也是个好主意。
答案 1 :(得分:0)
我会发布我开发的代码作为我的问题的解决方案;虽然我不是很开心(我认为必须以某种方式提供更好的解决方案),但万一它可以帮助某人。
我为模型Task
:
def update_order(self, new_order):
"""
Update the order of this task and reorder the rest of tasks
of the session accordingly
"""
current_order = self.order
tasks = Task.objects.filter(session=self.session)
current_highest_order = tasks.last().order
if new_order > current_highest_order or new_order < 0:
raise ValidationError(_('New order out of range'))
operation = -1 if new_order < current_order else +1
# set temporary order higher than any other to allow reordering the rest
self.order = current_highest_order + 1
self.save()
# reassign the rest of tasks' order accordingly
tasks = Task.objects.filter(session=self.session)
for i in range(current_order, new_order, operation):
task = tasks[i + operation] if operation == -1 else tasks[i]
task.order -= operation
task.save()
# Restore a proper order value (the desired new_order) to this task
self.order = new_order
self.save()
任何评论都会非常感激。