drf序列化器serializers.SerializerMethodField()的用法

 

为何DRF中有时候返回的json中图片是带域名的,有时候是不带域名的呢?前端

解析:数据库

带域名的结果是在view中对模型类序列化的,DRF在序列化图片的时候 会检查上下文有没有request,若是有,就给图片加上域名,django

好比说咱们视图用的是apiview():json

咱们须要序列化数据的时候,加  context={"request":request}api

TestSerilaizer(instance=instance, context={"request":request})

而后这样序列化器就取到了request对象,而后你再测试下图片url便可iview

 

还有一种状况,在序列化器里调用序列化器的时候,也会碰到这种状况,固然也必需要这样解决,函数

goods_json = GoodsSerializer(good_ins, many=False, context={'request': self.context['request']}).data    #注意具体语法

 

 

我再说几种传参的方法,这几种方法在开发过程当中也会常常的遇到,post

在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:request、format、view,这三个数据对象能够在定义序列化器时使用。测试

serializer = AccountSerializer(account, context={'request': request})

解析,若是是apiview,你视图函数里就写第一行格式,确保序列化器里能够取到requsts对象,固然若是视图函数继承的非apiview,那么能够忽略,加密

咱们能够在序列化器里取不少参数方便咱们使用,如

def validate(self, attrs):#在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:
        # request、format、view,这三个数据对象能够在定义序列化器时使用
        mobile = self.context['view'].kwargs['mobile']

这样就能够取到url里的mobile参数,来咱们接着看,

 

在视图里这样取也能够,好比当咱们重写视图的get方法时:咱们这样取pk得值

from rest_framework.generics import ListAPIView class NewGoodsView(ListAPIView): serializer_class = GoodeInfoSerializer queryset = GoodInfo.objects.all() def get(self,request,*args,**kwargs): goods = GoodInfo.objects.filter(type_id=kwargs['pk']).order_by('-id')[:2] ser = self.get_serializer(goods,many=True) return Response(ser.data)

而后看看下面这张截图,当访问商品详情时 点击量+1,

 

而后再继续看看,只要是咱们请求后台时前端请求header头中携带token认证,而后咱们在后台就能够用request 取到当前的用户对象,如

class MyCartInfoView(ListAPIView): ''' 个人购物车页面 ''' serializer_class = CartInfoSerializer queryset = Cart.objects.all() def get_queryset(self): return self.queryset.filter(user = self.request.user,selected=True)

下面,我再介绍四种咱们常常会用到的方法

get_objects() :

接着看下面,咱们在URL中并无携带参数,这样的话视图找不到PK会抛出异常,当咱们重写get_objects() 方法后,

class UserDetalView(RetrieveAPIView): ''' 我的中心信息展现 ''' serializer_class = UserDetailSerializer permission_classes = (IsAuthenticated,) # 重写get_object方法,返回用户指定信息
    def get_object(self): return self.request.user

 

解析:get_objects() 

     返回详情视图所需的模型类数据对象,默认使用lookup_field参数来过滤queryset。 在视图中能够调用该方法获取详情信息的模型类对象。

若详情访问的模型类对象不存在,会返回404。

 

get_queryset():

返回视图使用的查询集,是列表视图与详情视图获取数据的基础,默认返回queryset属性,能够重写,例如:

 

get_serializer(self, args, *kwargs)
返回序列化器对象,被其余视图或扩展类使用,若是咱们在视图中想要获取序列化器对象,能够直接调用此方法。

class CartCountView(GenericAPIView): ''' detail页面购物车数量渲染 ''' serializer_class = CartCountSerializer queryset = Cart.objects.all() def get(self,request): ser = self.get_serializer(self.get_queryset().filter(user=request.user),many=True) count = len(ser.data) return Response({'data':count})

get_serializer_class(self)

返回序列化器类,默认返回serializer_class,能够重写,例如:三级联动的实现,

先看看序列化器,

class AreaSerializer(serializers.ModelSerializer): ''' 行政区信息序列化器 '''
    class Meta: model = Area fields = ('id', 'name') class SubAreaSerializer(serializers.ModelSerializer): ''' 子集行政区信息序列化器 ''' subs = AreaSerializer(read_only=True,many=True) class Meta: model = Area fields = ('id', 'name', 'subs')

来看看视图,

class AreaViewSet(CacheResponseMixin,ReadOnlyModelViewSet): # 关闭分页,由于高级视图集默认是有分页操做的,而咱们这里前端页面选择省市县,是不须要分页的
    pagination_class = None # queryset = Area.objects.all()
    # serializer_class = AreaSerializer

    ''' list:返回全部的省份信息 retrieve:返回特定省或市下的下属城市 '''
    def get_queryset(self): ''' 返回视图使用的查询集, 是列表视图与详情视图获取数据的基础, 默认返回queryset属性 '''
        if self.action == 'list': return Area.objects.filter(parent=None) else: return Area.objects.all() def get_serializer_class(self): if self.action == 'list': return AreaSerializer else: return SubAreaSerializer

来看看url

from django.conf.urls import url from . import views from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register('areas',views.AreaViewSet,base_name='area') urlpatterns = [ ] urlpatterns += router.urls

 

drf模型序列化器默认仅返回数据库中已存在字段,若是想新增输出字段,改如何操做?

例如:输出用户角色时,顺便输出当前角色总共有多少用户.

先举个例子:

class Role(models.Model): """角色表,一的一方""" name = models.CharField(max_length=30, unique=True, verbose_name='角色名称')  # 媒体运营,广告运营,活动运营,财务,技术,惟一,必填
    desc = models.CharField(max_length=100, null=True, blank=True, verbose_name='角色描述')  # 非必填
 
    class Meta: db_table = 'tb_role' verbose_name = '角色' verbose_name_plural = verbose_name def __str__(self): """控制对象输出内容"""
        return self.name class User(BaseModel): """用户表,多的一方""" account = models.CharField(max_length=30, unique=True, verbose_name='登陆帐户')  # 必填,惟一
    password = models.CharField(max_length=100, null=True, blank=True, default='888888', verbose_name='登陆密码')  # 非必填,默认888888,长度100是为了之后加密扩展
    username = models.CharField(max_length=30, null=True, blank=True, verbose_name='用户名称')  # 非必填
    role = models.ForeignKey(Role, on_delete=models.CASCADE, related_name='user', verbose_name='角色') class Meta: db_table = 'tb_user' verbose_name = '用户' verbose_name_plural = verbose_name def __str__(self): """控制对象输出内容"""
        return self.account

接着看序列化器,

class RoleModelSerializer(serializers.ModelSerializer): """角色模型序列化器""" user_count = serializers.SerializerMethodField(label='用户数量')  # 新增数据库不存在字段用户数量
 
    class Meta: model = Role fields = ['id', 'name', 'desc', 'user_count'] def get_user_count(self, obj): """ 返回当前角色用户数量 固定写法,obj表明Role实例对象,模型类配置了反向引用user表明当前角色用户 """ number = obj.user.count() return number

注意: 

user_count 字段在数据库中不能存在,下面写方法的时候前面加 get_  就能够,这样就获得咱们须要的数据了。
在此方法里须要调用序列化器,咱们直接调用便可,举例:
ad_goods = serializers.SerializerMethodField()  #位于中间部分goods商品的img大图片显示

    def get_ad_goods(self, obj): goods_json = {} ad_goods = IndexAd.objects.filter(category_id=obj.id,)  #过滤goods在广告表中的数据
        if ad_goods: good_ins = ad_goods[0].goods  #取一条
            goods_json = IndexGoodsSerializer(good_ins, many=False, context={'request': self.context['request']}).data return goods_json
HiddenField()

HiddenField的值不依靠输入,而须要设置默认的值,不须要用户本身post数据过来,也不会显式返回给用户,最经常使用的就是user!!

咱们在登陆状况下,进行一些操做,假设一个用户去收藏了某一门课,那么后台应该自动识别这个用户,而后用户只须要将课程的id post过来,那么这样的功能,咱们配合CurrentUserDefault()实现。

 

下面是一个用户留言功能的实现:

class LeavingMessageSerializer(serializers.ModelSerializer): ''' 用户留言 '''
    # 获取当前登陆的用户
    user = serializers.HiddenField( default=serializers.CurrentUserDefault() ) #read_only:只返回,post时候能够不用提交,format:格式化输出
    add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M') class Meta: model = UserLeavingMessage fields = ("user", "message_type", "subject", "message", "file", "id" ,"add_time")
相关文章
相关标签/搜索