我有一个ModelForm
,并且我想使用我的Model方法进行表单验证过程,我尝试了form.save(commit=False)
,但是它返回了一个None
对象。
期间模型具有两个属性,分别是开始时间字段和结束时间字段。
models.py
class Booking(models.Model):
CATEGORY_CHOICES = (
('Web', 'Web Application'),
('Emb', 'Embedded Application')
)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bookings')
room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='bookings')
category = models.CharField(max_length=50, choices=CATEGORY_CHOICES, default='Web')
date = models.DateField('Booking Date', db_index=True)
start = models.ForeignKey(Period, on_delete=models.SET_NULL, related_name='start_at', null=True)
end = models.ForeignKey(Period, on_delete=models.SET_NULL, related_name='end_at', null=True)
used = models.BooleanField(default=False)
objects = BookingManager()
class Meta:
ordering = ['-date']
def get_start_time(self):
return datetime.datetime.combine(self.date, self.start.start,
tzinfo=timezone.get_current_timezone())
def get_end_time(self):
return datetime.datetime.combine(self.date, self.end.end,
tzinfo=timezone.get_current_timezone())
def is_occurring(self):
now = timezone.localtime(timezone.now())
return (now >= self.get_start_time()) and (now <= self.get_end_time())
def extend_booking_time(self):
next_end = self.end.next_period()
if next_end is None:
raise ValidationError("Invalid extending period")
if not next_end.is_available(self.date, next_end):
raise ValidationError("Overlapped extension")
else:
self.end = next_end
self.save()
def check_in(self):
# Create record
'''
Log.objects.create(user=self.user.username,
room=self.room, booking= self.id)
'''
self.used = True
self.save()
def check_out(self, time):
# Record Log
#log = Log.objects.get(booking=self.id)
#log.check_out = time
#log.save()
self.delete()
def check_periods(self):
return self.start.start < self.end.end
def check_time(self):
now = timezone.localtime(timezone.now())
if now >= self.get_end_time():
return False
else:
return True
def check_overlap(self):
start = self.get_start_time()
end = self.get_end_time()
bookings = Booking.objects.filter(room=self.room, date=self.date)
for booking in bookings:
if (start < booking.get_end_time()) and (end > booking.get_start_time()):
return False
return True
def clean(self):
if not self.check_periods():
raise ValidationError('Period error!')
if not self.check_time():
raise ValidationError('Time error!')
if not self.check_overlap():
raise ValidationError('Overlap error!')
forms.py
class BookingForm(forms.ModelForm):
class Meta:
model = Booking
fields= ['room', 'date', 'start', 'end']
def __init__(self, *args, **kwargs):
initial_args = kwargs.get('initial', None)
if initial_args:
super(BookingForm, self).__init__(*args, **kwargs)
self.fields['start'].widget = forms.TextInput()
self.fields['date'].widget.attrs['readonly'] = True
self.fields['start'].widget.attrs['readonly'] = True
self.fields['room'].queryset = Room.objects.filter(
id=initial_args['room'].id
)
self.fields['end'].queryset = Period.objects.get_available_periods(
initial_args['room'],
initial_args['date'],
initial_args['start']
)
def clean_date(self):
now = timezone.localtime(timezone.now()).date()
date = self.cleaned_data['date']
if date < now:
raise ValidationError('Ngay dang ky khong hop le')
return date
def clean(self):
pass
views.py
class BookingCreateView(LoginRequiredMixin, CreateView):
login_url = 'login'
form_class = BookingForm
template_name = 'booking_add.html'
success_url = reverse_lazy('booking_list')
def get(self, request, *args, **kwargs):
room = self.request.GET.get('room', None)
date = self.request.GET.get('date', None)
start = self.request.GET.get('start', None)
if room is None or date is None or start is None:
return redirect('select')
else:
room_object = get_object_or_404(Room, id=room)
period = get_object_or_404(Period, number=start)
date = datetime.datetime.strptime(
date, '%d-%m-%Y'
).replace(tzinfo=timezone.get_current_timezone())
if period.is_expired(date) or not period.is_available(room, date):
return redirect(room_object.get_absolute_url())
return super(BookingCreateView, self).get(request, *args, **kwargs)
def get_initial(self):
initial = super(BookingCreateView, self).get_initial()
initial['date'] = datetime.datetime.strptime(
self.request.GET.get('date'), '%d-%m-%Y'
)
initial['room'] = get_object_or_404(
Room, id=self.request.GET.get('room')
)
initial['start'] = get_object_or_404(
Period, number=self.request.GET.get('start')
)
return initial
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
模板。
<main>
<div class="reg-form">
<form class="form" method="post" action="">
{% csrf_token %}
<label for="room">Phòng</label>
{{ form.room }}
<label for="date">Ngày</label>
{{ form.date }}
<label for="start">Ca bắt đầu</label>
{{ form.start }}
<label for="end">Ca kết thúc</label>
{{ form.end }}
<button type="submit">Đăng ký</button>
<p>{{ form.errors }}</p>
</form>
</div>
</main>
我想在check_overlap
验证过程中使用方法BookingForm
,什么是最好的方法?
答案 0 :(得分:0)
最佳方法是非常主观的,但是这里的 a 方法并不太复杂。
在模型中,调用clean
中的方法。在验证过程中(完成保存之前),ModelForm将调用模型的clean方法。
以下是相关的来源部分:
https://github.com/django/django/blob/master/django/forms/models.py#L381 https://github.com/django/django/blob/master/django/forms/models.py#L381
这是模型验证文档:https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects
在表单上覆盖clean
会破坏方法的解析顺序,因此不会以编写代码的方式调用模型的原始代码。
希望这会有所帮助!