Hey, all! I hit an interesting design choice on my Twitch stream this evening related to Class Based Views, and I wanted to check if anyone has alternative patterns to the solution I arrived at.
I have a CreateView that creates records for a Course model. The form class that I’m using needs a QuerySet that is dynamically set when the form is created. Here’s the whole form for context:
class CourseForm(DaysOfWeekModelForm):
class Meta:
model = Course
fields = ["name", "grade_levels"] + DaysOfWeekModelForm.days_of_week_fields
grade_levels = forms.ModelMultipleChoiceField(queryset=GradeLevel.objects.none())
def __init__(self, school_year, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["grade_levels"].queryset = GradeLevel.objects.filter(
school_year=school_year
)
In my view, I need to provide an appropriate school_year record, which I do in get_form_kwargs.
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["school_year"] = SchoolYear.get_current_year_for(self.request.user)
return kwargs
My challenge is this: SchoolYear.get_current_year_for may return None. When the value is None, I don’t want the page to 404. Ideally, it would redirect to a page where a user can create a school year.
The problem is that, to my knowledge, there isn’t a great way to trigger a redirect from the get_form_kwargs method.
This is an exceptional case for my app so I’ve considered using an exception. I’ve considered raising a new exception like NoSchoolYearError in get_form_kwargs and handling that exception in dispatch to do the redirect.
Generalized, I think my question is this: is there an appropriate hook in CBVs to use to check on form data preconditions before a form is instantiated?
If you’ve got other ideas or I’m missing something obvious about CBVs, I’d love to read your thoughts. Thanks.