class ScholarshipForm(ModelForm): start_semester = StaffSemesterField() end_semester = StaffSemesterField() class Meta: model = Scholarship exclude = ('student', 'removed')
class PromiseForm(ModelForm): start_semester = StaffSemesterField() end_semester = StaffSemesterField() def clean_end_semester(self): en = self.cleaned_data.get('end_semester', None) st = self.cleaned_data.get('start_semester', None) if not en or not st: return None if st > en: raise forms.ValidationError("Promise cannot end before it begins") return en class Meta: model = Promise exclude = ('student', 'removed')
class GradStatusForm(ModelForm): start = StaffSemesterField( label="Effective Semester", help_text="Semester when this status is effective") def clean_end(self): en = self.cleaned_data.get('end', None) st = self.cleaned_data.get('start', None) if not en or not st: return None if st > en: raise forms.ValidationError("Status cannot end before it begins") return en class Meta: model = GradStatus exclude = ('student', 'created_by', 'hidden', 'end', 'start_date', 'config') hidden = ('id') widgets = { 'notes': forms.Textarea(attrs={ 'rows': 2, 'cols': 40 }), }
class GradProgramHistoryForm(ModelForm): start_semester = StaffSemesterField() class Meta: model = GradProgramHistory fields = ('program', 'start_semester', 'starting') widgets = { 'research_area': forms.Textarea(attrs={'rows': 3, 'cols': 40}), }
class SearchForm(forms.Form): first_name_contains = forms.CharField(required=False) last_name_contains = forms.CharField(required=False) start_semester_start = StaffSemesterField(required=False, label="Start semester after") start_semester_end = StaffSemesterField( required=False, help_text='Semester in which the student started their program', label="Start semester before") end_semester_start = StaffSemesterField(required=False, label="End semester after") end_semester_end = StaffSemesterField( required=False, label="End semester before", help_text='Semester in which the student completed/left their program') student_status = forms.MultipleChoiceField( gradmodels.STATUS_CHOICES + (('', 'None'), ), required=False, help_text="Student's current status" ) # choices updated in views/search.py status_asof = StaffSemesterField(label='Status as of', required=False, initial='') program = forms.ModelMultipleChoiceField(GradProgram.objects.all(), required=False) program_asof = StaffSemesterField(label='Program as of', required=False, initial='') grad_flags = forms.MultipleChoiceField(choices=[], label='Program Options', required=False) campus = forms.MultipleChoiceField(GRAD_CAMPUS_CHOICES, required=False) supervisor = forms.MultipleChoiceField([], required=False, label='Senior Supervisor') requirements = forms.MultipleChoiceField(choices=[], label='Completed requirements', required=False) requirements_st = forms.ChoiceField(( ('AND', mark_safe( u'Student must have completed <em>all</em> of these requirements') ), ('OR', mark_safe( u'Student must have completed <em>any</em> of these requirements') )), label='Requirements search type', required=False, initial='AND', widget=forms.RadioSelect) incomplete_requirements = forms.MultipleChoiceField( [], label='Incomplete requirements', required=False) is_canadian = NullBooleanSearchField(required=False) financial_support = forms.MultipleChoiceField( (('N', 'None'), ('S', 'Scholarship'), ('O', 'Other Funding'), ('P', 'Promise')), required=False) gpa_min = forms.DecimalField(max_value=4.33, min_value=0, decimal_places=2, required=False) gpa_max = forms.DecimalField(max_value=4.33, min_value=0, decimal_places=2, required=False) gender = forms.ChoiceField( (('', '---------'), ('M', 'Male'), ('F', 'Female'), ('U', 'Unknown')), required=False) visa = forms.MultipleChoiceField( VISA_STATUSES, required=False, ) scholarship_sem = forms.ModelMultipleChoiceField( Semester.objects.all(), label='Scholarship Semester Received', required=False) scholarshiptype = forms.ModelMultipleChoiceField( ScholarshipType.objects.all(), label='Received Scholarship', required=False) columns = forms.MultipleChoiceField( COLUMN_CHOICES, initial=( 'person.last_name', 'person.first_name', 'person.emplid', 'person.userid', 'program', 'current_status', ), help_text='Columns to display in the search results.') sort = forms.CharField(required=False, widget=forms.HiddenInput( )) # used to persist table sorting across "modify search" workflow semester_range_fields = [ 'start_semester_start', 'start_semester_end', 'end_semester_start', 'end_semester_end', ] personal_fields = [ 'first_name_contains', 'last_name_contains', 'is_canadian', 'gender', 'visa', 'gpa_min', 'gpa_max' ] program_fields = [ 'program', 'program_asof', 'grad_flags', 'campus', 'supervisor', ] requirement_fields = [ 'requirements', 'requirements_st', 'incomplete_requirements', ] status_fields = [ 'student_status', 'status_asof', ] financial_fields = [ 'financial_support', 'scholarship_sem', 'scholarshiptype', ] col_fields = ['columns', 'sort'] def clean_requirements_st(self): value = self.cleaned_data['requirements_st'] if not value and len(self.cleaned_data['requirements']) > 1: raise ValidationError, u"Specify a search type for requirements" return value def clean_financial_support(self): value = self.cleaned_data['financial_support'] if 'N' in value and len(value) > 1: raise ValidationError, u"If 'None' is selected, nothing else can be selected" return value def _make_query(self, query_string, query_param=None): query_value = self.cleaned_data.get(query_string, None) if _is_not_empty(query_value): if query_param is None: query_param = query_string if query_value is Unknown: query_value = None return Q(**{query_param: query_value}) return None def get_query(self): if not self.is_valid(): raise Exception, "The form needs to be valid to get the search query" auto_queries = [ ('first_name_contains', 'person__first_name__icontains'), ('last_name_contains', 'person__last_name__icontains'), ('application_status', 'application_status__in'), ('is_canadian', ), ('campus', 'campus__in'), ('scholarship_sem', 'scholarship__start_semester__in'), ('scholarshiptype', 'scholarship__scholarship_type__in'), ] manual_queries = [] if not self.cleaned_data.get('program_asof', None): # current program: is in table auto_queries.append(('program', 'program__in')) # else: selected semester so must calculate. Handled in secondary_filter if not self.cleaned_data.get('status_asof', None): # current status: is in table statuses = self.cleaned_data.get('student_status') if not statuses: pass elif '' in statuses: # we're allowing gs.student_status is None manual_queries.append( Q(current_status__in=statuses) | Q(current_status__isnull=True)) else: manual_queries.append(Q(current_status__in=statuses)) # else: selected semester so must calculate. Handled in secondary_filter if self.cleaned_data.get('start_semester_start', None) is not None: manual_queries.append( Q(start_semester__name__gte=self. cleaned_data['start_semester_start'].name)) if self.cleaned_data.get('start_semester_end', None) is not None: manual_queries.append( Q(start_semester__name__lte=self. cleaned_data['start_semester_end'].name)) if self.cleaned_data.get('end_semester_start', None) is not None: manual_queries.append( Q(end_semester__name__gte=self. cleaned_data['end_semester_start'].name)) if self.cleaned_data.get('end_semester_end', None) is not None: manual_queries.append( Q(end_semester__name__lte=self. cleaned_data['end_semester_end'].name)) if self.cleaned_data.get('supervisor', None): person_ids = self.cleaned_data['supervisor'] supervisors = Supervisor.objects.filter( supervisor__in=person_ids, supervisor_type__in=['SEN', 'COS'], removed=False) student_ids = [s.student_id for s in supervisors] manual_queries.append(Q(id__in=student_ids)) if self.cleaned_data.get('grad_flags', None): flag_ids = self.cleaned_data['grad_flags'] gradflagvalues = GradFlagValue.objects.filter( flag__id__in=flag_ids, value=True) student_ids = [gfv.student.id for gfv in gradflagvalues] manual_queries.append(Q(id__in=student_ids)) if self.cleaned_data.get('financial_support', None) is not None: if 'S' in self.cleaned_data['financial_support']: manual_queries.append(Q(scholarship__amount__gt=0)) if 'O' in self.cleaned_data['financial_support']: manual_queries.append(Q(otherfunding__amount__gt=0)) if 'P' in self.cleaned_data['financial_support']: manual_queries.append(Q(promise__amount__gt=0)) if 'N' in self.cleaned_data['financial_support']: manual_queries.append(~Q(pk__in=gradmodels.Scholarship.objects. all().values('student')) & ~Q(pk__in=gradmodels.OtherFunding. objects.all().values('student')) & ~Q(pk__in=gradmodels.Promise.objects. all().values('student'))) if self.cleaned_data.get('incomplete_requirements', False): # If a student has ANY of these requirements he will be included. inc_req = self.cleaned_data['incomplete_requirements'] completed_req = CompletedRequirement.objects.filter( requirement__series__in=inc_req) completed_req_students = set( cr['student_id'] for cr in completed_req.values('student_id')) manual_queries.append(~Q(pk__in=completed_req_students)) if self.cleaned_data.get('requirements', False): if self.cleaned_data['requirements_st'] == 'OR': # completed OR auto_queries.append( ('requirements', 'completedrequirement__requirement__series__in')) else: # completed AND for series in self.cleaned_data['requirements']: manual_queries.append( Q(pk__in=CompletedRequirement.objects.filter( requirement__series=series).values('student_id'))) # passes all of the tuples in auto_queries to _make_query as arguments # (which returns a single Q object) and then reduces the auto_queries # and manual_queries into one Q object using the & operator query = reduce( Q.__and__, chain( ifilter(lambda x: x is not None, (self._make_query(*qargs) for qargs in auto_queries)), manual_queries), Q()) #print self.cleaned_data return query #, exclude_query def _secondary_filter(self, gradstudent): return ( (gradstudent.person.gender() == self.cleaned_data['gender'] if _is_not_empty(self.cleaned_data.get('gender', None)) else True) and (gradstudent.person.gpa() >= self.cleaned_data['gpa_min'] if _is_not_empty(self.cleaned_data.get('gpa_min', None)) else True) and (gradstudent.person.gpa() <= self.cleaned_data['gpa_max'] if _is_not_empty(self.cleaned_data.get('gpa_max', None)) else True) # and # ((gradstudent.person.config['citizen'].lower() == 'canadian') == # self.cleaned_data['is_canadian'] # if _is_not_empty(self.cleaned_data.get('is_canadian', None)) # else True) and (gradstudent.person.visa() in self.cleaned_data['visa'] if _is_not_empty(self.cleaned_data.get('visa', None)) else True) and (not self.cleaned_data.get('program_asof', None) or not self.cleaned_data.get('program', None) or gradstudent.program_as_of( self.cleaned_data.get('program_asof', None)) in self.cleaned_data.get('program', None)) and (not self.cleaned_data.get('status_asof', None) or not self.cleaned_data.get('student_status', None) or gradstudent.status_as_of( self.cleaned_data.get('status_asof', None)) in self.cleaned_data.get('student_status', None))) def secondary_filter(self): # this returns a function in case it needs to use a closure # to cache some data used in the filter return self._secondary_filter def search_results(self, units): query = self.get_query() grads = GradStudent.objects.filter( program__unit__in=units).filter(query).select_related( 'person', 'program').distinct() return filter(self.secondary_filter(), grads)
class GradSemesterForm(forms.Form): start_semester = StaffSemesterField(required=False) end_semester = StaffSemesterField(required=False)
class FinancialCommentForm(ModelForm): semester = StaffSemesterField() class Meta: model = FinancialComment exclude = ('student', 'removed', 'created_at', 'created_by')
class OtherFundingForm(ModelForm): semester = StaffSemesterField() class Meta: model = OtherFunding exclude = ('student', 'removed')
class CompletedRequirementForm(ModelForm): semester = StaffSemesterField() class Meta: model = CompletedRequirement exclude = ('removed', 'student')