Django按预约开始日计算用户年龄筛选ReservationFrame出现TypeError
错误原因
你代码中的比较逻辑(ExtractMonth('start_at'), ExtractDay('start_at')) < (person_birthday.month, person_birthday.day)是在Python运行时直接执行的,左侧是Django ORM的查询表达式对象,右侧是整数类型,二者不支持直接在Python层做比较,需要将比较逻辑转换为数据库可识别的ORM查询条件。
解决方案
将生日未过的判断逻辑拆分为两个可在数据库层执行的条件:
- 预约开始月份 < 用户生日月份
- 预约开始月份等于用户生日月份,且预约开始日期 < 用户生日日期
满足任一条件时年龄计算额外减1即可。
另外需要注意JSON字段的数值比较问题:如果使用PostgreSQL作为数据库,JSON字段内的数值默认以字符串类型返回,比较时需要添加__int后缀强制转为整数再比较;如果使用MySQL作为数据库,直接使用原字段名比较即可。
完整可运行代码
from django.db.models import F, Case, When, IntegerField, Q from django.db.models.functions import ExtractYear # 提前取出用户生日的年月日三个字段,避免重复访问属性 person_birthday = request.user.person.birthday birth_year = person_birthday.year birth_month = person_birthday.month birth_day = person_birthday.day reservation_frames = reservation_frames.annotate( age=ExtractYear('start_at') - birth_year - Case( When( Q(start_at__month__lt=birth_month) | Q(start_at__month=birth_month, start_at__day__lt=birth_day), then=1 ), default=0, output_field=IntegerField() ) ) # 过滤下限:无下限 或 年龄≥下限 reservation_frames = reservation_frames.filter( Q(information__has_key='lower_age_limit') == False | Q(information__lower_age_limit__int__lte=F('age')) ) # 过滤上限:无上限 或 年龄≤上限 reservation_frames = reservation_frames.filter( Q(information__has_key='upper_age_limit') == False | Q(information__upper_age_limit__int__gte=F('age')) )
补充说明
你代码中定义的frames_without_age_limit变量未被使用,如果需要单独获取无年龄限制的记录可以单独使用这个变量,否则可以删除该行。如果不需要保留年龄计算字段用于后续逻辑,也可以提前将年龄判断逻辑直接写在过滤条件中,无需annotate即可直接过滤,查询性能更高。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

