Django模型Choice字段如何为选项配置对应分值实现选型计分
Django模型Choice字段绑定分值实现方案
方案一:兼容存量数据(推荐已上线项目使用)
不需要修改现有数据库结构,不需要迁移数据,仅通过新增映射关系和属性方法即可实现分值获取。
直接修改models.py对应模型代码:
class Survey_Answer(models.Model): # 原有选项配置完全保留,不影响已存的历史数据 CHOICES = [('Disagree Strongly', 'Disagree Strongly'), ('Disagree', 'Disagree'), ('Undecided', 'Undecided'), ('Agree', 'Agree'), ('Agree Strongly', 'Agree Strongly')] # 配置每个选项对应的分值,可根据业务需求自行调整 SCORE_MAP = { 'Disagree Strongly': 1, 'Disagree': 2, 'Undecided': 3, 'Agree': 4, 'Agree Strongly': 5 } question = models.ForeignKey(Survey_Question, on_delete=models.CASCADE) answer_text = models.CharField(max_length=20, choices=CHOICES, default='Undecided') date_published = models.DateTimeField('date published', auto_now_add=True) created_at = models.DateTimeField('created at', auto_now_add=True) # 新增分值属性,直接通过实例.score即可获取对应分值 @property def score(self): return self.SCORE_MAP.get(self.answer_text, 0) def __str__(self): return self.answer_text + ' - ' + self.question.question_text
使用方式
- 单条数据取值:
# 拿到回答实例后直接取分值 answer = Survey_Answer.objects.get(id=1) print(answer.answer_text) # 输出:Agree Strongly print(answer.score) # 输出:5
- 聚合统计(比如计算某道题的平均得分):
from django.db.models import Case, When, IntegerField, Avg # 统计id=1的问题所有回答的平均分 avg_result = Survey_Answer.objects.filter(question_id=1).aggregate( avg_score=Avg( Case( When(answer_text='Disagree Strongly', then=1), When(answer_text='Disagree', then=2), When(answer_text='Undecided', then=3), When(answer_text='Agree', then=4), When(answer_text='Agree Strongly', then=5), output_field=IntegerField() ) ) ) print(avg_result['avg_score'])
优势:改完代码重启服务即可生效,不需要执行数据库迁移,已有历史数据完全不受影响,后续调整分值只需要修改
SCORE_MAP配置即可。
方案二:直接存储分值(推荐未上线新项目使用)
如果项目还没正式上线、没有存量数据,可以直接调整Choice结构,把分值作为实际存储值存入数据库,查询和统计效率更高。
修改后的模型代码:
class Survey_Answer(models.Model): # 元组第一个值为数据库存储的分值,第二个值为前端展示的选项文本 CHOICES = [ (1, 'Disagree Strongly'), (2, 'Disagree'), (3, 'Undecided'), (4, 'Agree'), (5, 'Agree Strongly') ] question = models.ForeignKey(Survey_Question, on_delete=models.CASCADE) # 字段改为IntegerField类型,直接存储分值 answer = models.IntegerField(choices=CHOICES, default=3) date_published = models.DateTimeField('date published', auto_now_add=True) created_at = models.DateTimeField('created at', auto_now_add=True) @property def answer_text(self): # 兼容原有获取选项文本的调用习惯 return self.get_answer_display() @property def score(self): # 直接返回存储的分值即可 return self.answer def __str__(self): return self.get_answer_display() + ' - ' + self.question.question_text
注意:该方案需要执行
python manage.py makemigrations和python manage.py migrate完成数据库字段变更,如果已有存量数据需要提前做好数据转换,否则会出现数据不兼容问题。
内容的提问来源于stack exchange,提问作者Roronoa_Z
相关产品推荐
相关产品推荐

