我在forms.py中有一个自定义的self.clean方法,该方法包含检查POST日期值是否与现有记录重叠的方法。如果用户编辑其记录但不更改日期,则此验证将停止记录更新。如何使用If语句更改验证,或者如何取决于用户是否修改了start_date或end_date字段?
我尝试查看诸如self.get_initial()和self.has_changed()之类的东西,这些东西似乎仅适用于视图函数?我宁愿在forms.py中验证。
如果我可以从“重叠”验证中滤除当前正在编辑的记录,那可能是最整洁的解决方案。
forms.py:
class EditBookingForm(ModelForm):
class Meta:
model = Bookings
#user not included as that is handled in views
fields = ['start_date', 'end_date', 'type', 'approved', 'members', 'guests']
...
def clean(self):
form_data = self.cleaned_data
#check if dates overlap by more than one day (ie. can start/end on the same day)
overlap_in = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['end_date']).count()
overlap_st = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['start_date']).count()
overlap_end = Bookings.objects.filter(start_date__lt=form_data['end_date'], end_date__gt=form_data['end_date']).count()
overlap_same = Bookings.objects.filter(start_date=form_data['start_date'], end_date=form_data['end_date']).count()
overlap_over = Bookings.objects.filter(end_date__gt=form_data['start_date'], start_date__lt=form_data['end_date']).count()
overlap = overlap_end + overlap_in + overlap_same + overlap_st + overlap_over
if overlap > 0:
self._errors["start_date"] = ["Your dates overlap with an existing booking"]
del form_data["start_date"]
return form_data
views.py:
booking = get_object_or_404(Bookings, pk=booking_id)
if request.method == "POST":
form = EditBookingForm(request.POST)
if form.is_valid():
#some code
#if not POST request
else:
form = EditBookingForm(instance=booking)
context = {
'form': form,
}
return render(request, 'bookings/edit_booking_page.html', context)
答案 0 :(得分:0)
正在编辑现有实例的ModelForm将在初始化时传递正在编辑的实例。您应该可以使用此预编辑实例,并将其从查询集中排除为pk
bookings = Bookings.objects.all()
if self.instance.pk:
bookings = bookings.exclude(pk=self.instance.pk)
overlap_in = bookings.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['end_date']).count()
# etc
您可以将5个查询集简化为最多3个,只要您确认end_date大于start_date。可以将它们减少到1 ...
# So long as end_date is greater than start_date then this should be covered by overlap_st
# overlap_in = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['end_date']).count()
overlap_st = Bookings.objects.filter(start_date__lt=form_data['start_date'], end_date__gt=form_data['start_date']).count()
# So long as end_date is greater than start_date then this should be covered by overlap_over
# overlap_end = Bookings.objects.filter(start_date__lt=form_data['end_date'], end_date__gt=form_data['end_date']).count()
overlap_same = Bookings.objects.filter(start_date=form_data['start_date'], end_date=form_data['end_date']).count()
overlap_over = Bookings.objects.filter(end_date__gt=form_data['start_date'], start_date__lt=form_data['end_date']).count()