如何根据Forms.py中的初始值验证字段?

时间:2019-07-07 16:09:07

标签: django django-forms

我在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)

1 个答案:

答案 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()