2016-06-10 72 views
1

我有一个模型,代表Session(说一个孩子一个小时的课程),有一定数量的关联Task s必须遵循订单。更易于理解:Django - 重新排序(更新)对象与unique_together =(ForeignKey,IntegerField)

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更新(如果可能),或者这将是一个优雅的方式来做到这一点,因为我只能想到用新的顺序(例如order = 50)保存所需的任务,然后重新排列其余的任务,最后重新分配所需的任务顺序到所需的任务。

是否有类似于bulk_update(经过长时间研究后我没有找到类似的东西),它允许我为所有任务修改order字段,然后一次保存所有任务?还是我必须自己照顾这个unique_together?

+1

它通常是最好的重用现有的解决方案 https://github.com/bfirsh/django-ordered-model 虽然它仍然归结为2序列节省: http://dba.stackexchange.com/questions/131118/how-can-i-swap-two-values-from-particular-column-in-a-table-in-postgres 另请参阅:https://www.djangopackages.com/grids/g/model-订购/ 最好的办法是编写一个自定义的SQL查询,沿着 http://dba.stackexchange的行。com/questions/131118/how-can-i-swap-two-values-from-particular-column-in-a-table-in-postgres 将数据库限制作为你的'unique_together' – seeg

+0

谢谢你真的很多,这正是我所期待的。我会看看,并考虑到所有的想法! – vabada

+0

@seeg如果您不介意发表您的评论作为答案我会将其标记为已接受,因为它解决了我的问题 – vabada

回答

1

它通常是最好的重用现有的解决方案:

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/

最佳的选择将是沿着

https://dba.stackexchange.com/questions/131118/how-can-i-swap-two-values-from-particular-column-in-a-table-in-postgres

线条它也有DB约束在您的示例unique_together好主意编写自定义的SQL查询,一些东西。

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() 

任何评论都将非常感激。