def distribute_personal(distribution_proposals, students_done=[]): """ Distribute all students with a private proposal to the private proposal. :param distribution_proposals: List of distributions :param students_done: list of distributed students :return: """ stds = get_all_students().filter( personal_proposal__isnull=False, personal_proposal__TimeSlot=get_timeslot()).distinct( ).prefetch_related('personal_proposal') for s in stds: try: p = s.personal_proposal.filter(TimeSlot=get_timeslot()).get() except MultipleObjectsReturned: raise Exception( "User {} has multiple private proposals ({}). Please resolve this!" .format( s, print_list( s.personal_proposal.filter( TimeSlot=get_timeslot()).all()))) if p.TimeSlot != get_timeslot(): raise Exception( "User {} of this timeslot has private proposal {} of other timeslot {}" .format(s, p, p.TimeSlot)) distribution_proposals.append(DistributionProposal(s.id, p.id, 0)) students_done.append(s) return [distribution_proposals, students_done]
def get_valid_students(): """ All students with applications, without personal, in this timeslot. :return: list of user objects. """ # TODO personal_proposal should be filtered by timeslot return get_all_students().filter( personal_proposal__isnull=True, applications__isnull=False).filter( applications__Proposal__TimeSlot=get_timeslot()).distinct()
def planning_public(): """ Check if presentations planning is public visible """ if get_timephase_number() < 5: # no distributions yet in phase 5. return False ts = get_timeslot() try: options = ts.presentationoptions except PresentationOptions.DoesNotExist: return False if get_timephase_number() == 7 or options.Public: return True return False
def calculate_2_from_project(distribute_random, automotive_preference): """ Type 2, calculated new way. Loop over proposals and find a student for it. :return: """ projects = list(get_valid_proposals().select_related()) shuffle(projects) students_done = [] # list of student objects projects_done = [] # list of proposal objects distribution_proposals = [] # list of DistributionProposal objects distribution_proposals, students_done = distribute_personal( distribution_proposals, students_done) # iterate for all preferences twice # once to first handle all automotive # second time the leftovers plus ele if automotive_preference: track_automotive = Track.objects.get(Name='Automotive') for n in range(1, settings.MAX_NUM_APPLICATIONS + 1): # iterate all projects for proj in projects: # skip non AU if proj.Track != track_automotive: continue # select all applicants of current selected cohort and preference, sort it for cohort > ects > random apps = list(proj.applications.filter(Priority=n, Proposal__TimeSlot=get_timeslot()).distinct().select_related() \ .order_by('-Student__usermeta__Cohort', '-Student__usermeta__ECTS', '?')) assigned = count_distributions(proj.id, distribution_proposals) # while project is not yet full while assigned != proj.NumStudentsMax: # take first from list and check if not yet distributed # if list of applications is empty move on if len(apps) == 0: break app = apps.pop(0) # check if student is automotive if (not app.Student.usermeta.Study) or ( 'Automotive' not in app.Student.usermeta.Study): continue # not automotive. # check if there is not an ele project at higher preference for this student, than wait for next round students_appls = app.Student.applications.filter( Priority__lt=app.Priority, Proposal__TimeSlot=get_timeslot()).distinct() students_appls = [ True if a.Proposal.Track != track_automotive else False for a in students_appls ] if True in students_appls: continue if app.Student not in students_done: # put it in the distribute list to this proposal distribution_proposals.append( DistributionProposal(app.Student_id, proj.id, n)) students_done.append(app.Student) assigned += 1 if assigned == proj.NumStudentsMax: projects_done.append(proj) # all students not only au for n in range(1, settings.MAX_NUM_APPLICATIONS + 1): # iterate all projects for proj in projects: # select all applicatants of current selected cohort and preference, sort it for cohort > ects > random apps = list(proj.applications.filter(Priority=n, Proposal__TimeSlot=get_timeslot()).distinct().select_related() \ .order_by('-Student__usermeta__Cohort', '-Student__usermeta__ECTS', '?')) assigned = count_distributions(proj.id, distribution_proposals) # while project is not yet full while assigned != proj.NumStudentsMax: # take first from list and check if not yet distributed # if list of applications is empty move on if len(apps) == 0: break app = apps.pop(0) if app.Student not in students_done: # put it in the distribute list to this proposal distribution_proposals.append( DistributionProposal(app.Student_id, proj.id, n)) students_done.append(app.Student) assigned += 1 if assigned == proj.NumStudentsMax: projects_done.append(proj) # distribute leftover students random if distribute_random: distribution_proposals, students_done = distribute_remaining_random( distribution_proposals, students_done) return distribution_proposals
def calculate_1_from_student(distribute_random, automotive_preference): """ option1, calculated old way. Look for proposals for each student. :return: """ # valid students: stds = get_valid_students() # list of students processed but not in distributionproposal students_done = [] # list of student objects projects_done = [] distribution_proposals = [] # list of DistributionProposal objects # personal proposals: distribution_proposals, students_done = distribute_personal( distribution_proposals, students_done) # get all cohorts cohorts = get_cohorts() # loop over all cohorts, take the youngest students first if automotive_preference: # for AU students in AU applications track_automotive = Track.objects.get(Name='Automotive') for c in cohorts: # get students in this cohort with applications, ordered by ECTS stds_c = list( stds.filter( Q(usermeta__Cohort=c) & Q(usermeta__Study__contains='Automotive')).distinct(). order_by('-usermeta__ECTS')) # filter on students without distributionproposal # Higher application have priority over ECTS for n in range(1, settings.MAX_NUM_APPLICATIONS + 1): # all students in this cohort, ordered by most ECTS first, with application number a stds_c = list(set(stds_c) - set(students_done)) for s in stds_c: # loop over applications. Lower choices have priority over ects/cohort if s not in students_done: try: application = s.applications.filter( Proposal__TimeSlot=get_timeslot()).get( Priority=n) except Application.DoesNotExist: # user does not have a'th application continue if application.Proposal.Track != track_automotive: break # apply to proposal: proposal = application.Proposal if proposal.TimeSlot != get_timeslot(): # application is to an invalid proposal continue num_dist = count_distributions(proposal.id, distribution_proposals) max_dist = proposal.NumStudentsMax if num_dist < max_dist: # proposal can handle more students distribution_proposals.append( DistributionProposal(s.id, proposal.id, n)) # remove this student from queryset because it is now distributed students_done.append(s) #else: this might be a tie between students, check and if yes log. # loop over all cohorts, take the youngest students first # for all students for c in cohorts: # get students in this cohort with applications, ordered by ECTS stds_c = list( stds.filter( Q(usermeta__Cohort=c)).distinct().order_by('-usermeta__ECTS')) # filter on students without distributionproposal # Higher application have priority over ECTS for n in range(1, settings.MAX_NUM_APPLICATIONS + 1): # all students in this cohort, ordered by most ECTS first, with application number a stds_c = list(set(stds_c) - set(students_done)) for s in stds_c: # loop over applications. Lower choices have priority over ects/cohort if s not in students_done: try: application = s.applications.filter( Proposal__TimeSlot=get_timeslot()).get(Priority=n) except Application.DoesNotExist: # user does not have a'th application continue # apply to proposal: proposal = application.Proposal if proposal.TimeSlot != get_timeslot(): # application is to an invalid proposal continue num_dist = count_distributions(proposal.id, distribution_proposals) max_dist = proposal.NumStudentsMax if num_dist < max_dist: # proposal can handle more students distribution_proposals.append( DistributionProposal(s.id, proposal.id, n)) # remove this student from queryset because it is now distributed students_done.append(s) #else: this might be a tie between students, check and if yes log. if distribute_random: distribution_proposals, students_done = distribute_remaining_random( distribution_proposals, students_done) # return the list of distributed students return distribution_proposals
def get_valid_students(): """ All students with applications, with personal, in this timeslot. Personal proposals are distributed as first, so personal prop students will not get to the other distribution. :return: list of user objects. """ return get_all_students().filter(applications__isnull=False).filter(applications__Proposal__TimeSlot=get_timeslot()).distinct()