2016-04-08 52 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