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()

    
    
                        
    
        
本文概况 

参考

快速实例: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):
     passdef 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可以拿到所有请求(不包括GET请求)过来的数据

c、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': '[email protected]'}

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)
        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}

猜你喜欢

转载自www.cnblogs.com/zh-xiaoyuan/p/12952605.html