from django.db import models # Create your models here. from django.db import models from django.db.models import Model, Max, Min import random from django.db.models import F class Student(models.Model): name = models.CharField(max_length=32) sid = models.CharField(max_length=20) credit = models.FloatField() class_name = models.CharField(max_length=32) probability = models.FloatField() max = models.FloatField() min = models.FloatField() def prob(self,class_name,credit): #由积分求概率 stu = Student.objects.filter(class_name=class_name) credits = [student.credit for student in stu] max_credit = max(credits) min_credit = max(credits) if max_credit == min_credit: return 1 else: return (credit - min_credit)/(max_credit - min_credit) def callstu(self,class_name,num,mode): #点名的函数,输入要点的人数,返回这些人的学号姓名,不重复,(基础模式) sts = Student.objects.filter(class_name=class_name) probabilities = [] if mode == 1 or mode == 2: #基础模式和得分加倍的筛选概率不变 probabilities = [student.probability for student in sts] elif mode == 3 : #三五成群 for s1 in sts: if (int(s1.credit) % 3 == 0 or int(s1.credit) % 5 == 0) and s1.credit != 0: probabilities.append(2*s1.probability) else: probabilities.append(s1.probability) else: #六六大顺 for s1 in sts: if int(s1.credit) % 6 == 0 and s1.credit != 0: probabilities.append(2*s1.probability) else: probabilities.append(s1.probability) if probabilities: max_probability = max(probabilities) min_probability = min(probabilities) else: max_probability = -1 min_probability = -1 if num > sts.count(): data = {'message':0} return data else: result = {} if mode == 1 or mode == 2: time = 0 #筛选出一个学生需要生成的随机数的次数 (刚开始比较稀疏,要避免一直不能完成抽取条件的情况)设置上限为10 while len(result) < num: #基础模式和得分加倍模式 if time == 10: #当为了筛选一个人而生成了10次随机数后,由于太浪费时间,直接筛选剩下的人 flag = 0 while flag == 0: s = sts.order_by('?').first() if s.sid not in result: result[s.name] = s.sid time = 0 flag += 1 else: random_probability = random.uniform(min_probability, max_probability) time += 1 s = sts.filter(probability__gte = random_probability).order_by('?').first() if s.sid not in result: result[s.name] = s.sid time = 0 #当筛选出一个的时候,为下一次的筛选置为0 elif mode == 3: #三五成群 time = 0 # 筛选出一个学生需要生成的随机数的次数 (刚开始比较稀疏,要避免一直不能完成抽取条件的情况)设置上限为10 while len(result) < num: #一个随机数就选出一个学生 if time == 10: flag = 0 while flag == 0: s = sts.order_by('?').first() if s.sid not in result: result[s.name] = s.sid time = 0 flag += 1 else: random_probability = random.uniform(min_probability, max_probability) # print(random_probability) ss1 = [student for student in sts if ( int(student.credit) % 5 == 0 or int(student.credit) % 3 == 0 )and student.probability > random_probability/2] ss2 =[student for student in sts if student.credit > random_probability] ss = list(set(ss1+ss2)) random_student = random.choice(ss) if random_student.id not in result: result[random_student.name] = random_student.sid time = 0 print(result) elif mode == 4: #六六大顺 time = 0 # 筛选出一个学生需要生成的随机数的次数 (刚开始比较稀疏,要避免一直不能完成抽取条件的情况)设置上限为10 while len(result) < num: #一个随机数就选出一个学生 if time == 10: flag = 0 while flag == 0: s = sts.order_by('?').first() if s.sid not in result: result[s.name] = s.sid time = 0 flag += 1 else: random_probability = random.uniform(min_probability, max_probability) ss1 = [student for student in sts if int(student.credit) % 6 == 0 and student.probability > random_probability/2] ss2 = [student for student in sts if student.credit > random_probability] ss = list(set(ss1+ss2)) random_student = random.choice(ss) if random_student.id not in result: result[random_student.name] = random_student.sid time = 0 data = {'message':1, 'result':result} return data def updateinfor (self,point,class_name,sid,style): #更新积分和概率 if style == 1 : point = point if style == 2 : point = point * 2 #先改变该学生的积分值 current_s = Student.objects.filter(class_name=class_name, sid=sid).first() current_credit = current_s.credit current_s.credit = current_credit + point current_s.save() #查找最新的最大或最小值,与原来写在表中的上次更新的最大值和最小值做对比 max_credit = Student.objects.filter(class_name=class_name).aggregate(max_credit=Max('credit'))['max_credit'] min_credit = Student.objects.filter(class_name=class_name).aggregate(min_credit=Min('credit'))['min_credit'] s = Student.objects.filter(class_name=class_name).first() #找未更新的值 max_credit0 = s.max min_credit0 = s.min fm = max_credit - min_credit #最新的分母 #如果不影响2个最值,仅改变单个学生的概率 if max_credit == max_credit0 and min_credit == min_credit0: if fm == 0: prob = 1.0 else: prob = 1 - (current_s.credit - min_credit)/fm current_s.probability = prob # 直接设置字段的值 current_s.save() # 调用 save 方法保存更改 #影响积分最大值和最小值其中的一个时,所有学生的概率都需要改变,先将最新的最大值和最小值写入数据库 else: #将最新的最大值和最小值写入数据库 sts = Student.objects.filter(class_name=class_name) sts.update(min = min_credit, max = max_credit) #更新所有学生的概率 if fm == 0 : sts.update(probability = 1.0) else: sts.update(probability = (1 - (F('credit') - min_credit)/fm)) #耗时最大,性能改进前的代码 # def updateinfor (self,point,class_name,sid,style): #更新积分和概率 # if style == 1 : # point = point # if style == 2 : # point = point * 2 # #先改变该学生的积分值 # current_s = Student.objects.filter(class_name=class_name, sid=sid).first() # current_credit = current_s.credit # current_s.credit = current_credit + point # current_s.save() # #查找最新的最大或最小值,与原来写在表中的上次更新的最大值和最小值做对比 # max_credit = Student.objects.filter(class_name=class_name).aggregate(max_credit=Max('credit'))['max_credit'] # min_credit = Student.objects.filter(class_name=class_name).aggregate(min_credit=Min('credit'))['min_credit'] # fm = max_credit - min_credit #最新的分母 # sts = Student.objects.filter(class_name=class_name) # sts.update(min=min_credit, max=max_credit) # # 更新所有学生的概率 # if fm == 0: # sts.update(probability=1.0) # else: # sts.update(probability=(1 - (F('credit') - min_credit) / fm))