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

如何序列化含多外键的Django模型,获取用户关联课程详情

问题描述

我在Django的models.py中定义了两个模型:

from django.db import models
from django.contrib.auth.models import User

class Course(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    cost = models.IntegerField()
    course_image = models.ImageField()

    def __str__(self):
        return self.name

class PurchasedCourse(models.Model):
    purchased_by = models.ForeignKey(User, on_delete=models.CASCADE)
    purchased_course = models.ForeignKey(Course, on_delete=models.CASCADE)
    purchased_time = models.DateField(auto_now_add=True, blank=True)
    
    def __str__(self):
        return str(self.purchased_by) + ' => ' + str(self.purchased_course)

当前serializers.py内容如下:

from rest_framework import serializers
from .models import *

class CourseSerializer(serializers.ModelSerializer):
    class Meta:
        model = Course
        fields = '__all__'

class PurchasedCourseSerializer(serializers.ModelSerializer):
    class Meta:
        model = PurchasedCourse
        fields = '__all__'

(这只是简单序列化)

我的views.py内容如下:

from django.http import HttpResponse
from requests import Response
from .models import *
from .serializers import CourseSerializer, PurchasedCourseSerializer

from rest_framework import generics, viewsets
from rest_framework.authentication import BasicAuthentication, TokenAuthentication 
from rest_framework.permissions import IsAuthenticated

class CourseViewSet(viewsets.ModelViewSet):
    authentication_classes = [TokenAuthentication]
    permission_classes = (IsAuthenticated,)
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

class UserRelatedCourseViewSet(viewsets.ModelViewSet):
    queryset = PurchasedCourse.objects.all()
    serializer_class = PurchasedCourseSerializer

    def get_queryset(self):
        return PurchasedCourse.objects.filter(purchased_by__username=self.request.query_params['username'])

目前接口返回的JSON格式类似{"purchased_by":5, "purchased_course":1},但我需要获取仅属于登录用户的所有完整Course对象,期望返回的JSON结构如下:

[{
  "id": 1,
  "username": "testUsername",
  "course_set": [
    {
      "id": 2,
      "name": "Computer Science",
      "description": "Test description text..."
    },
    {
      "id": 5,
      "name": "History",
      "description": "Test description text..."
    }
  ]
}]
解决方案

要实现需求,需要调整序列化器和视图逻辑,直接基于登录用户关联的课程数据构建响应:

1. 调整序列化器结构

因为期望返回用户+其购买的课程列表,需要创建用户相关的序列化器,嵌套课程序列化器:

修改serializers.py:

from rest_framework import serializers
from django.contrib.auth.models import User
from .models import Course, PurchasedCourse

class CourseSerializer(serializers.ModelSerializer):
    class Meta:
        model = Course
        # 按需指定返回字段,不需要的字段可移除(比如course_image)
        fields = ['id', 'name', 'description']

class UserPurchasedCoursesSerializer(serializers.ModelSerializer):
    # 通过SerializerMethodField构建用户的课程列表字段
    course_set = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ['id', 'username', 'course_set']

    def get_course_set(self, obj):
        # 从用户的反向关联中取出所有购买记录,提取对应的Course对象
        purchased_records = obj.purchasedcourse_set.all()
        courses = [record.purchased_course for record in purchased_records]
        return CourseSerializer(courses, many=True).data

2. 修改视图逻辑

替换原有的UserRelatedCourseViewSet,直接创建获取当前登录用户购买课程的视图:

修改views.py:

from django.http import HttpResponse
from rest_framework.response import Response  # 注意:替换requests的Response为DRF的Response
from django.contrib.auth.models import User
from .serializers import UserPurchasedCoursesSerializer
from rest_framework import generics, viewsets
from rest_framework.authentication import BasicAuthentication, TokenAuthentication 
from rest_framework.permissions import IsAuthenticated

# 保留原有的CourseViewSet
class CourseViewSet(viewsets.ModelViewSet):
    authentication_classes = [TokenAuthentication]
    permission_classes = (IsAuthenticated,)
    queryset = Course.objects.all()
    serializer_class = CourseSerializer

# 新增获取当前用户购买课程的视图
class UserPurchasedCoursesView(generics.RetrieveAPIView):
    authentication_classes = [TokenAuthentication]
    permission_classes = (IsAuthenticated,)
    serializer_class = UserPurchasedCoursesSerializer

    def get_object(self):
        # 直接返回当前登录的用户对象,无需依赖URL参数
        return self.request.user

3. 路由配置示例

在urls.py中添加对应路由:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CourseViewSet, UserPurchasedCoursesView

router = DefaultRouter()
router.register(r'courses', CourseViewSet)

urlpatterns = [
    path('', include(router.urls)),
    # 访问该接口获取当前用户购买的课程
    path('my-courses/', UserPurchasedCoursesView.as_view(), name='my-purchased-courses'),
]

访问/my-courses/接口时,即可返回期望的JSON结构,且仅包含当前登录用户购买的完整课程数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:40:38