如何序列化有2个或更多外键的Django模型?

dm7nw8vv  于 2023-02-10  发布在  Go
关注(0)|答案(3)|浏览(123)

我在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__'

(* 这只是简单的序列化 *)
我的观点. 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'])

到目前为止,我得到的结果类似于{" purched_by ":5、"购买_课程":1}的JSON格式。
因此,问题是如何使用PurchasedCourseSerializer获取仅依赖于登录用户的所有Course对象(具有所有字段)?
比如:

[{
  "id": 1;
  "username": "testUsername";
      course_set
               [
                  {
                     "id": 2;
                     "name": "Computer Science";
                     "description": "Test description text...";
                  }
                  {
                     "id": 5;
                     "name": "History";
                     "description": "Test description text...";
                  }
               ]
}]
brgchamk

brgchamk1#

您也可以使用嵌套序列化器。这允许您显式定义外键模型应该如何序列化,并且它将逻辑保持在一个位置。
试试这个:

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

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = "__all__"

class PurchasedCourseSerializer(serializers.ModelSerializer):
    purchased_course = CourseSerializer()
    purchased_by = UserSerializer()

    class Meta:
        model = PurchasedCourse
        fields = "__all__"

现在,您可以在每个外键模型自己的序列化程序中定义其序列化,并保持逻辑的组织和可维护性。

gupuwyp2

gupuwyp22#

您可以重写序列化程序中的to_represention方法,以更改字段在阅读期间的行为,如下所示:

class PurchasedCourseSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source="purchased_by.username")

    def to_representation(self, obj):
       self.fields['purchased_course'] = CourseSerializer(obj.purchased_course )
       return super().to_representation(obj)
    class Meta:
        model = PurchasedCourse
        fields = '__all__'

仅供参考,PurchasedCourse与Course具有FK关系,因此一个PurchasedCourse将只有一个Course对象附加到它,因此您无法显示类似表示的列表。
但是,如果从UserSerializer进行序列化,则可以使用以下实现(通过SerializerMethodField):

class UserSerializer(...):
    courses = serializer.SerializerMethodField()

    def get_courses(self, obj):
      return CourseSerializer(Course.objects.filter(purchased_course__purchased_by=obj), many=True).data
js4nwp54

js4nwp543#

基本上有两种方法可以在序列化JSON中包含外键的所有属性。

    • 第一个解决方案**

PurchasedCourse串行化器中使用to_representation函数,它看起来如下所示:

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

    def to_representation(self, instance):
        rep = super().to_representation(instance)
        rep["purchased_course"] = CourseSerializer(instance.purchased_course).data
        rep["purchased_by"] = UserSerializer(instance.purchased_by).data

        return rep

这基本上使用外键的序列化程序来表示那些字段及其完整数据,或者在那些序列化程序中指定的任何字段。

    • 第二种解决方案**

使用嵌套的序列化程序基本上与第一种解决方案相同,只是方式更笨拙--至少对我来说是这样--

class PurchasedCourseSerializer(serializers.ModelSerializer):
    purchased_course = CourseSerializer()
    purchased_by = UserSerializer()

    class Meta:
        model = PurchasedCourse
        fields = '__all__'

因为第一种解决方案为您提供了一种更简单、更清晰的方法来管理您特别需要此序列化程序返回哪些字段。

相关问题