
喜欢你就关注我





01
序列化器(高级)
动态字段(dynamic fields)
根据请求参数动态返回不同字段(如 ?fields=id,title 只返回 id 和 title)
classArticleSerializer(serializers.ModelSerializer):classMeta: model = Article fields = ['id', 'title', 'content', 'created_time']def__init__(self, *args, **kwargs): super().__init__(*args, **kwargs)# 从请求参数获取需要返回的字段 fields = self.context['request'].query_params.get('fields')if fields: fields = fields.split(',')# 过滤掉不存在的字段 valid_fields = [f for f in fields if f in self.fields]# 保留需要的字段for field_name in list(self.fields):if field_name notin valid_fields: self.fields.pop(field_name)只读与只写字段:
【read_only=True】:字段仅用于序列化(返回给前端),反序列化时忽略(如 id、created_time)
【write_only=True】:字段仅用于反序列化(接收前端输入),序列化时不返回(如 password)
classUserSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) # 密码只输入,不返回classMeta: model = User fields = ['id', 'username', 'password']嵌套序列化器的深度控制:
通过 depth 参数控制嵌套关联的深度(仅 ModelSerializer 支持),避免过度嵌套导致数据冗余
classArticleSerializer(serializers.ModelSerializer):classMeta: model = Article fields = ['id', 'title', 'author'] depth = 1# 嵌套1层:author字段显示User模型的基本字段(如id, username)02
实际案例
案例一 序列化器(APIView)
urls.py
from django.contrib import adminfrom django.urls import pathfrom sers import Viewsurlpatterns = [# 路由 path("sers/book/", views.BookView.as_view()), # 增加、查所有# (!无名分组) path("sers/book/(\d+)", views.BookDetailView.as_view()) #查单一、改、删]models.py
from django.db import modelsclassBook(models.Model): title = models.CharField(max_length=32, verbose_name="数据名称") price = models.IntegerField(verbose_name="价格") pub_date = models.DateField(verbose_name="出版日期")book_serializers.py
from rest_framework import serializersclassBookSerializers(serializers.Serializer):# 序列化 主键 id = serializers.PrimarilyKey() title = serializers.CharField(max_length=32) price = serializers.IntegerField()# 可以自定义 序列化器类 中的字段名,使用source参数指定原字段名 date = serializers.DateField(source="pub_date")defcreate(self, validated_data):# 如果调用 序列化器save方法,必须重写# create方法 或 update方法# 将数据插入到 数据库中return Book.objects.create(**self.validated_data)defupdate(self, instance, validated_data): Book.objects.filter(pk=instance.id).update(**validated_data) updated_book = Book.objects.get(pk=id)return updated_bookviews.py
from django.shortcuts import renderfrom .models import Book # 模型类(实体类)from rest_framework.views import APIViewfrom rest_framework.response import Response # 优化Json响应体from .book_serializers.py import BookSerializersclassBookView(APIView):defget(self, request):# 获取所有书籍信息 book_list = Book.objects.all() # 返回 queryset[book1, book2, ... ]# 构建 序列化器对象:BookSerializers(instance=, data=)# instance参数: 序列化参数# data参数: 反序列化参数 serializer = BookSerializers(instance=book_list, many=True) return Response(serializer.data)defpost(self, request): serializer = BookSerializers(data=request.data)# !注意:前端传过来的Json数据(data=request.data),必须要做校验# is_valid() 校验函数(校验序列化器中的字段)# 将校验成功的字段,放到:serializer.validated_data 中# 将校验失败的字段,放到:serializer.errors 中# 只要有一个字段校验失败,is_valid()就返回: Falseif serializer.is_valid(): serializer.save() # 序列化器save方法return Response(serializer.data) # 针对self.instance属性做序列化else:# 返回错误信息return Response(serializer.errors)classBookDetailView(APIView):defget(self, request, id): book = Book.objects.get(pk=id)# 序列化传instance,反序列化传data serializer = BookSerializers(instance=book, many=False)return Response(serializer.data)defput(self, request, id):# 获取提交的更新数据 update_book = Book.objects.get(pk=id)# 构建序列化器,如果是修改操作的的话,instance和data参数都需要传! serializer = BookSerializers(instance=update_book, data=request.data)# 校验if serializer.is_valid(): serializer.save() # 序列化器save方法return Response(serializer.data)else:# 返回错误信息return Response(serializer.errors)defdelete(self, request, id): Book.objects.get(pk=id).delete()return Response()案例二 自动创建序列化器类
【ModelSerializer类】支持:一对一、一对多、多对多
urls.py
from django.contrib import adminfrom django.urls import pathfrom sers import Viewsurlpatterns = [# 路由 path("sers/book/", views.BookView.as_view()), # 增加、查所有# (!无名分组) path("sers/book/(\d+)", views.BookDetailView.as_view()) #查单一、改、删]models.py
from django.db import modelsclassBook(models.Model): title = models.CharField(max_length=32, verbose_name="数据名称") price = models.IntegerField(verbose_name="价格") pub_date = models.DateField(verbose_name="出版日期")book_serializers.py
from rest_framework import serializersclassBookSerializers(serializers.ModelSerializer): data = serializer.DateField(source="pub_date") # 自定义序列化字段名classMeta: model = Book# fields = "__all__" 表示:对所有字段做序列化# fields = ["title", "price"] 表示:只对这两个字段做序列化# exclude = ["pub_date"] 表示:排除指定字段views.py
from django.shortcuts import renderfrom .models import Book # 模型类(实体类)from rest_framework.views import APIViewfrom rest_framework.response import Response # 优化Json响应体from .book_serializers.py import BookSerializersclassBookView(APIView):defget(self, request):# 获取所有书籍信息 book_list = Book.objects.all() # 返回 queryset[book1, book2, ... ]# 构建 序列化器对象:BookSerializers(instance=, data=)# instance参数: 序列化参数# data参数: 反序列化参数 serializer = BookSerializers(instance=book_list, many=True) return Response(serializer.data)defpost(self, request): serializer = BookSerializers(data=request.data)# !注意:前端传过来的Json数据(data=request.data),必须要做校验# is_valid() 校验函数(校验序列化器中的字段)# 将校验成功的字段,放到:serializer.validated_data 中# 将校验失败的字段,放到:serializer.errors 中# 只要有一个字段校验失败,is_valid()就返回: Falseif serializer.is_valid(): serializer.save() # 序列化器save方法return Response(serializer.data) # 针对self.instance属性做序列化else:# 返回错误信息return Response(serializer.errors)classBookDetailView(APIView):defget(self, request, id): book = Book.objects.get(pk=id)# 序列化传instance,反序列化传data serializer = BookSerializers(instance=book, many=False)return Response(serializer.data)defput(self, request, id):# 获取提交的更新数据 update_book = Book.objects.get(pk=id)# 构建序列化器,如果是修改操作的的话,instance和data参数都需要传! serializer = BookSerializers(instance=update_book, data=request.data)# 校验if serializer.is_valid(): serializer.save() # 序列化器save方法return Response(serializer.data)else:# 返回错误信息return Response(serializer.errors)defdelete(self, request, id): Book.objects.get(pk=id).delete()return Response()03
SerializerMethodField 详解
基本概念
SerializerMethodField 是一个只读字段,它的值是通过调用序列化器类中的一个方法来获取
基本语法
field_name = serializers.SerializerMethodField(method_name=None)如果不指定 method_name,默认调用 get_<field_name> 方法
如果指定 method_name,则调用指定的方法
基本用法
classUserSerializer(serializers.ModelSerializer):# 1. 不指定method_name,默认调用 get_full_name full_name = serializers.SerializerMethodField()# 2. 指定method_name,调用 get_display_status status_display = serializers.SerializerMethodField(method_name='get_display_status')classMeta: model = User fields = ['id', 'username', 'full_name', 'status_display']defget_full_name(self, obj):"""计算全名"""returnf"{obj.first_name}{obj.last_name}"defget_display_status(self, obj):"""返回状态显示文本""" status_map = {'A': '活跃','I': '非活跃', 'S': '暂停' }return status_map.get(obj.status, '未知')基于请求上下文的计算:
classProductSerializer(serializers.ModelSerializer): is_favorited = serializers.SerializerMethodField() current_price = serializers.SerializerMethodField()classMeta: model = Product fields = ['id', 'name', 'price', 'is_favorited', 'current_price']defget_is_favorited(self, obj):"""检查当前用户是否收藏了该商品""" request = self.context.get('request')if request and request.user.is_authenticated:return obj.favorites.filter(user=request.user).exists()returnFalsedefget_current_price(self, obj):"""计算当前价格(考虑折扣、用户等级等)""" request = self.context.get('request') user = request.user if request elseNone base_price = obj.price# 用户等级折扣if user and user.membership_level == 'VIP': base_price *= 0.9# 季节性折扣if self.is_seasonal_sale(): base_price *= 0.8return round(base_price, 2)基于关联数据计算:
classOrderSerializer(serializers.ModelSerializer): item_count = serializers.SerializerMethodField() can_cancel = serializers.SerializerMethodField()classMeta: model = Order fields = ['id', 'status', 'created_at', 'item_count', 'can_cancel']defget_item_count(self, obj):"""计算订单中的商品种类数量"""return obj.order_items.count()defget_can_cancel(self, obj):"""判断订单是否可以取消""" cancellable_statuses = ['pending', 'confirmed']return obj.status in cancellable_statuses高级语法
带参数的方法字段:
classProductSerializer(serializers.ModelSerializer): price_with_currency = serializers.SerializerMethodField()classMeta: model = Product fields = ['id', 'name', 'price', 'price_with_currency']defget_price_with_currency(self, obj):"""根据请求返回带货币符号的价格""" request = self.context.get('request') currency = request.GET.get('currency', 'USD') if request else'USD' currency_symbols = {'USD': '$','EUR': '€','CNY': '¥' } symbol = currency_symbols.get(currency, '$')returnf"{symbol}{obj.price}"性能优化考虑:
❌ 可能引起 N+1查询
classOrderListSerializer(serializers.ModelSerializer): customer_name = serializers.SerializerMethodField()classMeta: model = Order fields = ['id', 'total', 'customer_name']defget_customer_name(self, obj):# 每次都会查询数据库!return obj.customer.name✅ 优化版本
classOptimizedOrderListSerializer(serializers.ModelSerializer): customer_name = serializers.SerializerMethodField()classMeta: model = Order fields = ['id', 'total', 'customer_name']defget_customer_name(self, obj):# 使用预加载的数据return obj.customer.name在视图中预加载数据
classOrderListView(generics.ListAPIView): serializer_class = OptimizedOrderListSerializerdefget_queryset(self):return Order.objects.select_related('customer')SerializerMethodField的优缺点
优点:
灵活性:可以计算任何复杂的字段值
只读性:自动成为只读字段,无需额外配置
上下文感知:可以访问请求上下文
业务逻辑隔离:将计算逻辑封装在序列化器中
缺点:
性能风险:可能引起N+1查询问题
测试复杂性:需要为每个方法字段编写测试
不可用于写入:不能用于反序列化

篇幅太长,下期再见!
