使用Django ORM实现子查询的技术求助
用Django ORM实现子查询:结合你的评分表实例
嘿,我明白你卡在Django ORM子查询这儿的感觉了——一开始确实有点绕,不过结合你给出的评分表结构,咱们一步步拆解,用实际场景的例子来搞懂它!
首先,先把你的数据表转换成对应的Django Model(这是ORM操作的基础):
from django.db import models from django.contrib.auth.models import User class Rating(models.Model): id = models.AutoField(primary_key=True) rating = models.CharField(max_length=1, null=False) product = models.ForeignKey('Product', on_delete=models.CASCADE, db_column='product_id', related_name='ratings') user = models.ForeignKey(User, on_delete=models.SET_NULL, db_column='user_id', null=True, related_name='ratings') created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = '你的评分表表名' # 替换成你实际的表名
(假设你有对应的Product模型,基础版本如下)
class Product(models.Model): name = models.CharField(max_length=100) # 其他你需要的字段
接下来,咱们看几个最常用的子查询场景,每个场景都会对应SQL逻辑和Django ORM代码,帮你理解对应关系:
场景1:获取每个产品的最新评分
这是很常见的需求——你想知道每个产品最近一次被评分的记录。
对应的SQL逻辑大概是这样:
SELECT * FROM rating r WHERE r.created_at = ( SELECT MAX(created_at) FROM rating WHERE product_id = r.product_id );
用Django ORM实现的话,需要用到Subquery和OuterRef这两个工具:
from django.db.models import Subquery, OuterRef, Max # 第一步:定义子查询——获取每个产品的最新创建时间 latest_rating_time = Rating.objects.filter( product_id=OuterRef('product_id') # 用OuterRef引用外层查询的product_id ).values('product_id').annotate( latest_created=Max('created_at') ).values('latest_created') # 只取出最新时间这个值 # 第二步:用子查询作为条件,筛选出对应评分记录 latest_ratings = Rating.objects.filter( created_at=Subquery(latest_rating_time) )
这里的OuterRef就像是个“桥梁”,让内层的子查询能关联到外层查询的每条产品记录,Subquery则把内层查询的结果当作外层查询的筛选条件。
场景2:获取每个用户的最高评分
假设你的rating字段是按字符串排序的(比如'A'是最高,'E'是最低),想找出每个用户给出的最高评分记录。
对应的SQL:
SELECT * FROM rating r WHERE r.rating = ( SELECT MAX(rating) FROM rating WHERE user_id = r.user_id );
ORM实现:
from django.db.models import Subquery, OuterRef, Max # 子查询:获取每个用户的最高评分值 user_max_rating = Rating.objects.filter( user_id=OuterRef('user_id') ).values('user_id').annotate( max_rating=Max('rating') ).values('max_rating') # 筛选出每个用户对应最高评分的记录 user_top_ratings = Rating.objects.filter( rating=Subquery(user_max_rating) )
场景3:筛选出有评分的产品(存在性检查)
如果你想找出所有至少被评过分的产品,用Exists子查询会比传统的__exists更灵活(还能扩展额外条件)。
ORM代码:
from django.db.models import Exists, OuterRef # 筛选所有有评分的产品 rated_products = Product.objects.filter( Exists(Rating.objects.filter(product_id=OuterRef('id'))) ) # 扩展:筛选出被特定用户(比如id=1)评过分的产品 user_rated_products = Product.objects.filter( Exists(Rating.objects.filter(product_id=OuterRef('id'), user_id=1)) )
Exists会检查每条产品记录是否满足子查询的条件,它的执行效率通常比count()或者__in更高,因为只要找到匹配的记录就会停止查询。
核心知识点总结
Subquery:用来将一个查询的结果作为另一个查询的条件,通常返回单个值或一列值OuterRef:用来引用外层查询中的字段,实现内外层查询的关联Exists:专门用于存在性检查的子查询,高效且灵活
如果还有特定的子查询需求,比如更复杂的关联或者聚合,随时补充细节就行!
内容的提问来源于stack exchange,提问作者Why




