如何在Django表单中校验字段大小关系?自定义校验函数未生效
The reason your compare_mon method isn’t running at all is because Django’s form system doesn’t automatically execute custom methods with arbitrary names during validation. You need to hook into Django’s built-in validation lifecycle methods to make your time comparison checks actually run.
Here’s how to fix it:
Option 1: Use the general clean() method (best for cross-field validation)
The clean() method is called after all individual field clean methods, making it perfect for comparing multiple fields like start and end times. If you have multiple days (mon, tues, wed, etc.), you can loop through them to avoid repeating code:
class TimeOpeningHoursForm(forms.ModelForm): class Meta: model = BusinessOpeningHours fields = ('mon_st', 'mon_end', 'tue_st', 'tue_end', ...) widgets = { 'mon_st': Select(attrs={'class': 'form-control'}), 'mon_end': Select(attrs={'class': 'form-control'}), 'tue_st': Select(attrs={'class': 'form-control'}), 'tue_end': Select(attrs={'class': 'form-control'}), ... } def clean(self): cleaned_data = super().clean() # Define pairs of start/end fields for each day day_field_pairs = [ ('mon_st', 'mon_end'), ('tue_st', 'tue_end'), # Add wed_st/wed_end, thu_st/thu_end, etc. here ] for start_field, end_field in day_field_pairs: start_time = cleaned_data.get(start_field) end_time = cleaned_data.get(end_field) # Only validate if both fields have valid data (avoids errors from required fields failing first) if start_time and end_time: if start_time > end_time: # Attach the error to the end field for better user feedback day_name = start_field.split('_')[0].capitalize() self.add_error(end_field, f"{day_name} start time must be before end time.") return cleaned_data
Option 2: Call your custom method from clean()
If you want to keep your compare_mon logic separate, you can call it directly from the clean() method (which Django does recognize):
class TimeOpeningHoursForm(forms.ModelForm): # ... your Meta and widgets code remains the same ... def clean(self): cleaned_data = super().clean() self.compare_mon(cleaned_data) # Add calls to compare_tue(), compare_wed(), etc. if needed return cleaned_data def compare_mon(self, cleaned_data): st = cleaned_data.get('mon_st') end = cleaned_data.get('mon_end') if st and end and st > end: self.add_error('mon_end', "Monday start time must be less than end time.")
Key Tips:
- Always call
super().clean()first to get the validated cleaned data from parent methods. - Use
cleaned_data.get()instead of direct indexing to avoidKeyErrorif a field failed earlier validation (like a required field left empty). - Use
self.add_error()to attach errors to specific fields—this makes error messages show up next to the relevant input, improving user experience.
Content of the question originates from Stack Exchange, asked by Maddie Graham

