rest_framework 之序列化、表的增刪改查


restful協議

     ----  一切皆是資源,操作只是請求方式
     
     ----book表增刪改查
         /books/                 books
         /books/add/             addbook
         /books/(\d+)/change/    changebook
         /books/(\d+)/delete/    delbook
         
    ----book表增刪改查
         /books/     -----get            books      -----  返回當前所有數據
         /books/     -----post           books      -----  返回提交數據 
         
         /books/(\d+)-----get            bookdetail -----  返回當前查看的單條數據 
         /books/(\d+)-----put            bookdetail -----  返回更新數據 
         /books/(\d+)-----delete         bookdetail -----  返回空
         
              
         class  Books(View):
              def get(self,request):
                  pass  # 查看所有書籍
                  
              def post(self,request):
                  pass  # 添加書籍
                  
                  
         class  BooksDetail(View):
              def get(self,request,id):
                  pass  # 查看具體書籍
         
              def put(self,request,id):
                  pass  # 更新某本書籍
                  
              def delete(self,request,id):
                  pass  # 刪除某本書籍    
         
                       
restframework(Django)  

    ----針對數據:json
    
    
    (1)Django的原生request:(django默認的request中沒有對json數據進行解析)

          瀏覽器   -------------  服務器
          
          "GET url?a=1&b=2 http/1.1\r\user_agent:Google\r\ncontentType:urlencoded\r\n\r\n"
          "POST url http/1.1\r\user_agent:Google\r\ncontentType:urlencoded\r\n\r\na=1&b=2"

          request.body: a=1&b=2
          request.POST:
                       if contentType:urlencoded:
                             a=1&b=2----->{"a":1,"b":2}
    
    (2)restframework 下的APIView:        
    
    (3)
    class PublishSerializers(serializers.Serializer):
            name=serializers.CharField()
            email=serializers.CharField()
            
            
        PublishSerializers(queryset,many=true)
        PublishSerializers(model_obj)
        
        
    總結:
        1 reuqest類----源碼
        
        2 restframework 下的APIView--源碼
        
          url(r'^books/$', views.BookView.as_view(),name="books")#  View下的view

          books/一旦被訪問: view(request) ------APIView: dispatch()
        
        3 def dispatch():
        
              構建request對象
              self.request=Request(request)
              self.request._request
              self.request.GET  # get
              self.request.data # POST  PUT
          
              分發----if get請求:
                    if request.method.lower() in self.http_method_names:
                        handler = getattr(self, request.method.lower(),
                                         self.http_method_not_allowed)
                    else:
                        handler = self.http_method_not_allowed   

                    response = handler(request, *args, **kwargs) # self.get(request, *args, **kwargs)
                    
                    return response                
            
        4 序列化類
            # from django.core import serializers
            # ret=serializers.serialize("json",publish_list)
        
            restframework下的序列類  BookModelSerializers
                將queryset或者model對象序列成一json數據
                    bs=BookModelSerializers(book_list,many=True,context={'request': request})
                    bs=BookModelSerializers(book,context={'request': request})
           
                還可以做校驗數據,json-------》queryset/model-->記錄
                
                    bs=BookModelSerializers(data=request.data)
                    if bs.is_valid():
                        print(bs.validated_data)
                        bs.save() # 重寫create方法
        5 操作數據:
        
            以Book表為例
                class BookView(APIView):
                    # 查看所有書籍
                    def get(self,request):
                        book_list=Book.objects.all()
                        bs=BookModelSerializers(book_list,many=True,context={'request': request})
                        return Response(bs.data)
                        
                    # 添加一本書籍    
                    def post(self,request):
                        # post請求的數據
                        bs=BookModelSerializers(data=request.data)
                        if bs.is_valid():
                            print(bs.validated_data)
                            bs.save()# create方法
                            return Response(bs.data)
                        else:
                            return Response(bs.errors)

                class BookDetailView(APIView):
                    # 查看一本書籍
                    def get(self,request,id):

                        book=Book.objects.filter(pk=id).first()
                        bs=BookModelSerializers(book,context={'request': request})
                        return Response(bs.data)
                    # 更新一本書籍
                    def put(self,request,id):
                        book=Book.objects.filter(pk=id).first()
                        bs=BookModelSerializers(book,data=request.data)
                        if bs.is_valid():
                            bs.save()
                            return Response(bs.data)
                        else:
                            return Response(bs.errors)
                    # 刪除某一本書籍
                    def delete(self,request,id):
                        Book.objects.filter(pk=id).delete()

                        return Response()

    
    
                        
    
        
本文概況 

參考

參考2

serializers進階

快速實例:Quickstart

使用restframework先下載:cmd->pip3 install djangorestframework

使用rest_framework前先在settings中進行app的注冊

View源碼解析

一、APIView源碼解析 

from rest_framework.views import APIView
class PublishView(APIView):
    def get(self,request):
     pass
def post(self,request):      pass 

urls.py 

url(r'^publishes/$', views.PublishView.as_view(),name="publish"),

當用戶訪問publishes時執行as_view()方法,但PublishView類下面沒有as_view()方法,去找父類APIView

#rest_framework\views.py

class APIView(View): #繼承View
#        ……
    @classmethod
    def as_view(cls, **initkwargs):
#        ……
        view = super(APIView, cls).as_view(**initkwargs)  #執行其父類View中的as_view()方法拿到返回結果(view)
        view.cls = cls
        view.initkwargs = initkwargs
        return csrf_exempt(view)   #返回函數名view,其實拿到的是父類View中as_view()方法返回的view
        #一旦用戶訪問publishes時就執行父類View中的view方法,父類View中view()執行結束之后返回了一個dispatch方法
        #return self.dispatch(request, *args, **kwargs)
        #dispatch()調用的先后順序:應該最開始self是PublishView,但其下沒有dispatch方法,然后找其父類APIView
       # 發現下面定義了dispatch方法,此次就不執行APIView父類View中的dispatch方法
       #經過以上分析用戶訪問publishes最終執行的是dispatch方法(首先要搞清楚是哪個類下的dispatch方法)

#       ……
    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)
        return Request(
            request,  #舊的request
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
#       ……
    def dispatch(self, request, *args, **kwargs):  #resr_framework所有的接口都封裝在dispatch方法中#構建一個新的request
        request = self.initialize_request(request, *args, **kwargs) self.request = request  #這句話之后下面所用的request都是新構建的request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:  #做分發
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            # handler方法的執行其實就是get/post等方法的執行,傳進去的request是新的request
            #也就是說視圖get(self,request)中的request是新的request
            response = handler(request, *args, **kwargs)
#   ……

#request.py
class Request(object):
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
#   ……
        self._request = request   #self是當前Request對象,其實就是新的request對象
        #新的request對象下面有個實例變量_request,self._request的結果就是舊的request
#   ……

    @property
    def data(self): #先記住一點:request.data拿到的是所有請求過來的數據
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data   #_full_data默認為空

    def _load_data_and_files(self):
        if not _hasattr(self, '_data'):
            self._data, self._files = self._parse()
            if self._files:
                self._full_data = self._data.copy()   #如果是_files,對_full_data進行賦值
                self._full_data.update(self._files)
            else:
                self._full_data = self._data

#       ……
    def _parse(self): #解析器 不同的數據用不同的解析器解析
#       ……
        try:
            return (parsed.data, parsed.files)  #最終返回的值是解析之后的源數據
        except AttributeError:
            empty_files = MultiValueDict()
            return (parsed, empty_files)

分析源碼之后我們需要知道三點:

a、request是新的request,通過 self._request = request可以調用舊的request

b、request.data可以拿到POST、PUT等請求(不包括GET請求)過來的數據

c、request.GET可以拿到GET請求過來的數據

d、APIView是在CBV基礎上做的,基於View又擴展了一些功能

二、序列化

創建一個序列化類

1、簡單使用

開發我們的Web API的第一件事是為我們的Web API提供一種將代碼片段實例序列化和反序列化為諸如json之類的表示形式的方式。我們可以通過聲明與Django forms非常相似的序列化器(serializers)來實現。

model_to_dict把model 對象轉換為一個字典

 

>>> from app01 import models
>>> obj=models.Publish.objects.filter(pk=1).first()
>>> obj
<Publish: 蘋果出版社>
>>> from django.forms.models import model_to_dict
>>> model_to_dict(obj)
{'id': 1, 'name': '蘋果出版社', 'email': '123@qq.com'}

models部分:

from django.db import models

class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish")
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name

views部分:

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=32)
    price = serializers.IntegerField()
    pub_date = serializers.DateField()
    publish = serializers.CharField(source="publish.name")  # 一對多
    authors = serializers.SerializerMethodField()  # 多對多
    def get_authors(self, obj):
        temp = []
        for author in obj.authors.all():
            temp.append(author.name)
        return temp

"""
序列化BookSerializer(book_list,many=True)
    temp=[]
    for obj in book_list:
        temp.append({
            "title":obj.title,
            "price":obj.price,
            "pub_date":obj.pub_date,
            #"publish":str(obj.publish),
            obj.publish.name
            # "authors":obj.authors.all, 
            "authors":get_authors(obj),        

        })
"""
class BookViewSet(APIView):   #這里是序列化的方式示例:真正的get請求在下面 def get(self,request,*args,**kwargs):
        book_list = Book.objects.all()
        # 序列化方式1:list強轉為列表,列表里面放字典
        # publish_list=list(Book.objects.all().values("title","price"))

        # 序列化方式2:
        # from django.forms.models import model_to_dict
        # data=[]
        # for obj in book_list:
        #     data.append(model_to_dict(obj))
        # print(data)
        # return HttpResponse("ok")

        # 序列化方式3:
        # data=serializers.serialize("json",book_list)
        # return HttpResponse(data)

        # 序列化方式4:
        bs=BookSerializer(book_list,many=True)
        return Response(bs.data) 

2、ModelSerializer

只需要寫下面幾步代碼會自動幫我們重建BookSerializer那一堆代碼

#將一個queryset或者model對象序列化為json數據
class
BookModelSerializers(serializers.ModelSerializer): class Meta: model = Book fields = "__all__" # depth=1 # 上面展示的是第一幅圖:默認展示一對多和多對多的主鍵值,加了這個之后展示給我們的是第二幅圖 #上面在轉換一對多或多對多的時候會展示多的一方的主鍵值,我們也可自定義顯示方法,定義了下面幾行代碼后get請求顯示方式如第三幅圖 publish=serializers.CharField(source="publish.name") #一對多 authors=serializers.SerializerMethodField() #多對多 def get_authors(self, obj): temp = [] for author in obj.authors.all(): temp.append(author.name) return temp 

 

 3、get請求和post請求 

url(r'^books/$', views.BookView.as_view(),name="books"),

上面展示的畫面就是利用下面的get請求獲取的

class BookView(APIView):
    def get(self,request):
        book_list=Book.objects.all()
        # bs=BookSerializer(book_list,many=True)       #利用自己定義的BookSerializer顯示
        bs=BookModelSerializers(book_list,many=True)   #利用BookMdelSerializers展現的數據,不需要我們寫BookSerializer那一堆代碼,這個是序列化queryset # return HttpResponse(bs.data)  #返回的是下面的字符串
        #OrderedDict([('title', '三體'), ('price', 233), ('pub_date', None)])
        # OrderedDict([('title', '追風箏的人'), ('price', 333), ('pub_date', None)])
        return Response(bs.data)  #顯示的是上面的畫面,可讀性更強

    def post(self,request):
        # post請求的數據
        bs=BookModelSerializers(data=request.data) #序列化數據----->queryset--->數據記錄
        if bs.is_valid():
            print(bs.validated_data)
            bs.save()# create方法:把生成的數據保存到數據庫中
            return Response(bs.data)  #返回提交數據
        else:
            return Response(bs.errors) #提交信息有錯返回錯誤信息 

4、重寫save中的create方法

post請求提交的數據:

  

 當我們發post請求上面post中的save方法走的是ModelSerializer里面的create方法,但這個方法不支持我們自定制顯示的玩法(不支持source="publish.pk"),

所以就需要我們重寫save中的create方法 ,post請求時就會走我們自己定義的create方法(如果我們不加自定制的publish字段就不需要自定制create方法)

有個疑點:

class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
        # depth=1

    publish=serializers.CharField(source="publish.pk") #一對多

  def create(self, validated_data): print("validated_data->",validated_data) #validated_data-> {'publish': {'pk': '1'}, 'title': 'go', 'price': 100,'pub_date': datetime.date(2012, 12, 12), 'authors': [<Author: alex>, <Author: egon>]} book = Book.objects.create(title=validated_data["title"],price=validated_data["price"],pub_date=validated_data["pub_date"],publish_id=validated_data["publish"]["pk"]) book.authors.add(*validated_data["authors"]) return book

post請求成功后返回的畫面

 5、單條數據的get、put和delete請求

book表:

 

    url(r'^books/(\d+)/$', views.BookDetailView.as_view(),name="detailbook"),
class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"

class BookDetailView(APIView):

    #單條數據的查看
    def get(self,request,pk):
        book=Book.objects.filter(pk=pk).first()
        bs=BookModelSerializers(book)  #序列化model對象
        return Response(bs.data)

    #單條數據的更新
    def put(self,request,pk):
        book=Book.objects.filter(pk=pk).first()
        bs=BookModelSerializers(book,data=request.data)
        if bs.is_valid():#校驗put請求提交的數據
            bs.save()  #update操作
            return Response(bs.data)
        else:
            return Response(bs.errors)

    # 單條數據的刪除
    def delete(self,request,pk):
        Book.objects.filter(pk=id).delete()
        return Response()  #刪除后返回空

 

 6、超鏈接API:Hyperlinked

url(r'^publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(),name="detailpublish"),
class BookModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"

    # publish=serializers.CharField(source="publish.pk")
    publish=serializers.HyperlinkedIdentityField(
            view_name="detailpublish",  #url的別名
            lookup_field="publish_id",  #取當前循環字段關聯publish的id值
            lookup_url_kwarg="pk"       #把上面找到的id值放到pk組中
    )
    #     publishes/(?P<pk>\d+)/$

需要注意的是在使用Hyperlinked這個方法后,上面的get、post、put中的BookModelSerializers中都需要加context={'request': request}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM