爲何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")