You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
9.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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))