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")
相關文章
相關標籤/搜索