Django数据迁移后平均评分计算失效、choices参数未生效修复
Django迁移后商品平均评分计算失效修复方案
问题根因
该问题并非迁移未识别choices参数,实际是代码定义错误导致,核心问题有3个:
Review模型存在重复的rating字段定义:类中先声明了整数类型的rating = models.IntegerField(default=3),后续又重新声明了字符串类型的rating = models.CharField(max_length=7,choices= RATINGS),Python类属性以后定义的为准,执行AlterField迁移后,数据库中rating字段从整数类型被修改为字符串类型,和计算逻辑的数值预期冲突。RATINGS配置不符合Django choices规范:- choices标准格式为
( (数据库实际存储值, 页面展示值), ... ),当前代码把带尾部空格的字符串作为存储值、整数作为展示值,顺序完全写反。 - 存储值使用了带多余尾部空格的字符串(如
'1 '而非'1'),引入不必要的格式异常。
- choices标准格式为
- 平均评分计算逻辑无类型兼容处理:迁移后
rating字段存储的是字符串类型,直接执行reviews_total += review.rating会触发类型错误,无法完成数值累加,直接导致计算失效。
相关错误迁移片段截图:
修复步骤
- 修正
Review模型代码,删除重复字段定义,调整RATINGS配置和字段类型(评分用整数存储更合理),修正后代码如下:
class Review(models.Model): RATINGS = ( (1, '1星'), (2, '2星'), (3, '3星'), (4, '4星'), (5, '5星'), ) product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE) rating = models.IntegerField(choices=RATINGS, default=3) content = models.TextField() created_by = models.ForeignKey(User, related_name='reviews', on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return '%s - %s' % (self.product.name, self.created_by)
- 存量数据修正:如果执行错误迁移后已经存入了字符串格式的评分数据,先进入Django shell做数据转换,避免后续迁移报错:
执行shell命令:python manage.py shell
在shell中执行数据转换逻辑:
from products.models import Review for review in Review.objects.all(): try: # 去除字符串首尾空格后转为整数 review.rating = int(str(review.rating).strip()) review.save() except (TypeError, ValueError): # 转换失败的异常数据用默认3分填充 review.rating = 3 review.save()
- 生成并执行新的迁移:
执行命令生成迁移文件,此时Django会正确识别choices配置,生成将rating字段改回整数类型的迁移:python manage.py makemigrations
确认迁移文件内容无误后执行迁移:python manage.py migrate - (可选优化)为评分计算逻辑增加异常兼容,避免后续因脏数据导致计算失效,修改
Product类的get_rating方法:
def get_rating(self): reviews = self.reviews.all() review_count = reviews.count() if review_count == 0: return 0 reviews_total = 0 for review in reviews: try: reviews_total += int(review.rating) except (TypeError, ValueError): # 遇到异常评分直接跳过,也可根据业务需求按默认值计算 continue # 保留2位小数返回,和Product自身rating字段精度对齐 return round(reviews_total / review_count, 2)
内容的提问来源于stack exchange,提问作者tobias
相关产品推荐
相关产品推荐

