You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django返回JsonResponse时如何让QuerySet包含主键PK

Django中获取包含主键的评论QuerySet并解决AttributeError问题

问题回顾

你定义了如下的Comment模型:

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, to_field='username')
    video = models.ForeignKey(Video, on_delete=models.CASCADE)
    description = models.TextField(default="none")
    replyto = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
    uploaded = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    indent = models.IntegerField(default=0)

原本通过这个QuerySet查询评论并序列化返回:

Comment.objects.filter(video_id=Video.objects.get(identifier=request.GET['identifier'])).order_by('-uploaded')[:end]

但返回的结果里没有包含评论的主键(pk),于是你尝试用value_list来指定字段,却触发了错误:AttributeError: 'Manager' object has no attribute 'value_list'

你的序列化代码如下:

def obtain_comments(request, *args, **kwargs):
    begin = int(request.GET['begin'])
    end = int(request.GET['end'])
    n_comments = end - begin
    all_split = Comment.objects.filter(video_id=Video.objects.get(identifier=request.GET['identifier'])).order_by('-uploaded')[:end]
    data = {
        'comments': serializers.serialize('json',all_split),
    }
    return JsonResponse(data)

错误原因

这个错误的核心是拼写错误:Django QuerySet的方法是values_list(注意是复数values),而你写成了value_list(单数)。不过就算你改对了拼写,这里还有个问题:values_list返回的是元组的序列,而不是模型实例,后续用serializers.serialize处理会报错,因为序列化器需要的是Django模型实例对象。

解决方案

这里有两种符合你需求的思路,根据你的场景选择:

思路1:直接获取包含pk的字典序列(无需模型序列化)

如果你不需要保留模型实例的其他特性,只想拿到包含pk的纯数据字典,可以用values()方法(同样是复数),它会返回字典组成的QuerySet,每个字典包含你指定的字段,包括pk。注意要把方法放在filter、order_by等查询操作之后:

all_split = Comment.objects.filter(
    video_id=Video.objects.get(identifier=request.GET['identifier'])
).order_by('-uploaded')[:end].values(
    'pk', 'user', 'video', 'description', 'replyto', 'uploaded', 'updated', 'indent'
)

然后序列化的时候直接转成列表即可,不需要用Django的serializers.serialize:

data = {
    'comments': list(all_split),
}
return JsonResponse(data)

这样返回的每个评论对象里就会包含pk字段了。

思路2:保留模型序列化,把pk加入返回字段

如果你仍然想用Django的serializers.serialize(比如需要保留模型相关的元信息),那默认的序列化结果其实已经包含pk了,只是它不在fields里,而是作为单独的键存在。你可以在后端把pk合并到fields中,再返回给前端:

import json

def obtain_comments(request, *args, **kwargs):
    begin = int(request.GET['begin'])
    end = int(request.GET['end'])
    n_comments = end - begin
    all_split = Comment.objects.filter(video_id=Video.objects.get(identifier=request.GET['identifier'])).order_by('-uploaded')[:end]
    
    # 序列化并处理pk字段
    serialized_data = json.loads(serializers.serialize('json', all_split))
    processed_comments = []
    for item in serialized_data:
        # 把pk加入到fields字典中
        item['fields']['pk'] = item['pk']
        processed_comments.append(item['fields'])
    
    data = {
        'comments': processed_comments,
    }
    return JsonResponse(data)

这样处理后,返回的每个评论对象就和你之前的格式一致,同时多了pk字段。

额外小提示

另外,你代码里Video.objects.get(identifier=request.GET['identifier'])如果找不到对应的视频会抛出DoesNotExist异常,建议加上异常处理,避免请求直接崩溃~

内容的提问来源于stack exchange,提问作者BRHSM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:00:34