django admin 中的依赖多对象验证
dependent multi object validation in django admin
TimeClass 的每个 "time range" 条目相互依赖。
它们不能重叠并且 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]
问题:我可以通过管理员一次 edit/add 多个 TimeRangeClass。但是考虑到 models.Model clean 方法一次只评估 1 个更改,我无法相互验证多个编辑。
示例:
保存 Entry1 和 Entry2 不冲突
更改 Entry2 以产生验证错误
调整 Entry1(而不是 #2),使它们不重叠
这没有注册,因为两个更改都没有写入数据库。
我正在寻找解决方法。
问题的一些提示:
检查重叠行时,不应遍历整个 table。只需过滤有问题的行...类似于:
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
现在是一个查询集,它会在您迭代它时进行评估,并且仅 returns 冲突的对象。
如果您将 Django 与 postgres 一起使用,您应该查看 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 ...
关于澄清问题的更新:
如果您想要验证或 pre/process 来自管理员内联的数据,您必须连接到相应的 ModelAdmin
方法。有多种方法可以解决这个问题。我想最简单的方法是覆盖 ModelAdmin.save_fromset。在保存之前,您可以在此处访问所有内联表单。
TimeClass 的每个 "time range" 条目相互依赖。
它们不能重叠并且 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]
问题:我可以通过管理员一次 edit/add 多个 TimeRangeClass。但是考虑到 models.Model clean 方法一次只评估 1 个更改,我无法相互验证多个编辑。
示例:
保存 Entry1 和 Entry2 不冲突
更改 Entry2 以产生验证错误
调整 Entry1(而不是 #2),使它们不重叠
这没有注册,因为两个更改都没有写入数据库。
我正在寻找解决方法。
问题的一些提示:
检查重叠行时,不应遍历整个 table。只需过滤有问题的行...类似于:
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
现在是一个查询集,它会在您迭代它时进行评估,并且仅 returns 冲突的对象。
如果您将 Django 与 postgres 一起使用,您应该查看 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 ...
关于澄清问题的更新:
如果您想要验证或 pre/process 来自管理员内联的数据,您必须连接到相应的 ModelAdmin
方法。有多种方法可以解决这个问题。我想最简单的方法是覆盖 ModelAdmin.save_fromset。在保存之前,您可以在此处访问所有内联表单。