zoukankan      html  css  js  c++  java
  • 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
    user_agent:Google
    contentType:urlencoded
    
    "
              "POST url http/1.1
    user_agent:Google
    contentType:urlencoded
    
    a=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_frameworkviews.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}

  • 相关阅读:
    vue cli3使用官方方法配置sass全局变量报错ValidationError: Invalid options object. Sass Loader has been initialised using an options object that does not match the API schema.
    面试必备:HashMap、Hashtable、ConcurrentHashMap的原理与区别
    Lombok介绍、使用方法和总结
    位运算
    【ZooKeeper系列】3.ZooKeeper源码环境搭建
    【ZooKeeper系列】2.用Java实现ZooKeeper API的调用
    【ZooKeeper系列】1.ZooKeeper单机版、伪集群和集群环境搭建
    弄明白CMS和G1,就靠这一篇了
    面试官,不要再问我三次握手和四次挥手
    【面试必备】小伙伴栽在了JVM的内存分配策略。。。
  • 原文地址:https://www.cnblogs.com/zh-xiaoyuan/p/12952605.html
Copyright © 2011-2022 走看看