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

4 months ago
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))