2016-06-10 37 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() 

任何評論都將非常感激。