2016-04-08 74 views
0

TimeClass的每個「時間範圍」條目都相互依賴。django admin中的相關多對象驗證管理

它們不能重疊,並且start_time < end_time。

models.py

class Xyz(models.Model): 
    ... 

class TimeRangeClass(models.Model) 
    start_time = models.TimeField() 
    end_time = models.TimeField() 
    xyz = models.ForeignKey(Xyz) 
    # other fields here 

    def clean(self): 
     # Here I loop through TimeRangeClass.objects.all() and 
     # check for conflicts through my custom "my_validator_method". 
     # If there is a conflict I throw an error 
     #(I've since modified it to just be one single query as per Titusz advice)    
     for each in TimeRangeClass.objects.filter(xyz=self.xyz).exclude(id=self.id): 
      my_validator_method(start_time1=self.start_time, 
           end_time1=self.end_time, 
           start_time2=each.start_time, 
           end_time2=each.end_time) 

admin.py

from .models import TimeRangeClass, Xyz 
class TimeRangeClassInLine(admin.TabularInline): 
    model = TimeRangeClass 
    extra = 3 

@admin.register(Xyz) 
class Xyz(admin.ModelAdmin): 
    exclude = [] 
    inlines = [TimeRangeClassInLine] 

問題:我可以編輯/一次通過管理添加多個TimeRangeClass的。但鑑於models.Model清潔方法只評估1次更改,我無法驗證對彼此的多個編輯。

實施例:

  1. 保存一個條目1 & ENTRY2無衝突

  2. 變化ENTRY2以產生一個驗證錯誤

  3. 調整條目1(而不是#2),從而它們不重疊

  4. 這沒有註冊,因爲沒有寫入到第e分貝。

我正在尋找解決方法。

+0

你應該給出一個更具體的問題解釋。 你在哪裏/如何更改入口#2?從管理界面,從視圖或表單? – Titusz

回答

1

對這個問題的一些提示:

重疊行檢查時,不應遍歷全表。只是過濾有問題的行...是這樣的:

overlaps = TimeRangeClass.objects.filter(
    Q(start_time__gte=self.start_time, start_time__lt=self.end_time) | 
    Q(end_time__gt=self.start_time, end_time__lte=self.end_time) 
) 

overlaps現在是當你迭代它只有返回衝突的對象,評估一個查詢集。

如果您使用的是帶有postgres的Django,您應該查看https://docs.djangoproject.com/es/1.9/ref/contrib/postgres/fields/#datetimerangefield

一旦你有衝突的對象,你應該能夠改變它們在函數內的開始和結束時間並保存更改。 Model.save()不會自動調用model.clean()方法。但請注意,如果您從Django管理員保存一個對象,它將在保存之前調用model.clean()方法

所以這樣的事情:

def clean(): 
    overlaps = TimeRangeClass.overlaps.for_trc(self) 
    for trc_object in overlaps: 
     fixed_object = fix_start_end(trc_object, self) 
     fixed_object.save() 

如果你覺得勇敢,你也應該閱讀了關於交易,使多個對象的突變數據庫中的所有成功或全部失敗,沒有什麼介於兩者之間。

def clean(): 
    with transaction.atomic(): 
     # do your multi object magic here ... 

更新澄清的問題:

如果您想驗證或來自你有掛接到相應的ModelAdmin方法(一個或多個)管理的內嵌前/處理數據。有多種方法可以解決這個問題。我想最簡單的方法就是覆蓋ModelAdmin.save_fromset。在這裏你可以在保存之前訪問所有的內聯格式。

+0

感謝您使用Q()而不是遍歷查詢集的建議。我不知道爲什麼我決定在這種情況下循環,因爲我在其他情況下使用類似的查詢。 – Maxim

+0

我簡要地看了一下transaction.atomic()的文檔。這將允許我比較尚未保存的變量的清潔方法嗎? – Maxim

+0

你還沒有保存的變量是什麼意思?你的*還沒有保存的變量*從哪裏來?您正在比較新的最終未保存的TimeRangeClass實例與通過您的查詢集加載到內存中的現有實例。 – Titusz