DRF-(2)

内容概览

  • APIView基本使用
  • APIView源码分析
  • Request类源码分析
  • 序列化组件介绍
  • 序列化组件基本使用
  • 反序列化

APIView基本使用

  • drf是一个第三方的app,只能够在django上使用
  • 安装后需要在setting中注册这个app:rest_framework
  • 安装了drf后,在views中导入视图类APIView,所有后期要是用drf写视图类,都是继承APIView及其子类
使用View+JsonResponse写获取所有图书接口
class BookView(View)
	def get(request):
		books = models.Book.objects.all()
		book_list = []  # JsonResponse不能够直接序列化Queryset对象
		for book in books:
			book_list.append({'title':book.title,'price':book.price,'publish':book.publish})  # 将每本书的数据以字典的形式追加到列表中
		return JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii':False})  # safe=False才能够序列化列表
使用APIView+Response写获取所有图书接口
from rest_framework.views import APIView
from rest_framework.response import Response


class BookView(APIView):
	    def get(self, request):
        books = models.Book.objects.all()
        book_list = []
        for book in books:
            book_list.append({'title': book.title, 'price': book.price, 'publish': book.publish})
        return Response(book_list)

APIView源码分析

"""还是先找视图类的as_view方法,自身没有去父类APIView找"""
@classmethod
def as_view(cls, **initkwargs):
    # 又调用了父类(View)的as_view
    view = super().as_view(**initkwargs)
    return csrf_exempt(view)
    """
    返回值等同于
    index=csrf_exempt(index)    装饰器原理
    return index
    csrf_exempt是取消校验csrf的装饰器,代表以后所有请求都不会校验csrf了
    """
"""请求来了以后,会执行dispatch方法,还是从自身开始查询,然后是APIView
所以真正执行的是APIView的dispatch"""
def dispatch(self, request, *args, **kwargs):
    # 参数的request是原来的django原生的request
    # 下面的request,变成了drf提供的Request类的对象---》return Request(。。。)
    request = self.initialize_request(request, *args, **kwargs)
    # self 是视图类的对象,视图类对象.request=request 新的request
    self.request = request
    try:
        # 执行了认证,频率,权限
        self.initial(request, *args, **kwargs)
        # 原来的View的dispatch的东西
        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)
    except Exception as exc:
        # 如果出了异常,捕获异常,处理异常,正常返回
        # 在执行三大认证和视图类中方法过程中,如果出了异常,是能被捕获并处理的---》全局异常的处理
        response = self.handle_exception(exc)
    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response
"""
总结:
	1 只要继承APIView都没有csrf的认证了
	2 以后视图类中使用的request对象,已经变成了drf提供的Request类的对象了
	3 执行视图类的方法之前,执行了3大认证(认证,权限,频率)
	4 在执行三大认证和视图类的方法过程中只要报错,都会被捕获处理
"""

Request类源码分析

"""在调用dispatch方法的时候执行了一个方法使request变成了drf提供的Request类的对象"""
def initialize_request(self, request, *args, **kwargs):
    return Request(request,...)

class Request:
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        self._request = request
"""
将原来的request存在_reqeust中
但还是能和之前的request一样使用
原因是Request中使用了__getattr__魔法方法:当点的属性不存在时触发
"""
def __getattr__(self, attr):
    try:
        return getattr(self._request, attr)  # 如果不存在去原来的request中获取
    except AttributeError:
        return self.__getattribute__(attr)

"""
Request类中有一个data方法,被property装饰了,可以直接当做属性调用
	以后body体中提交的数据,都可以从这里取到(request.POST)
	urlencoded/form-data提交的数据在request.POST中,Json格式提交的数据在request.body中
	三种数据格式都可以在request.data中取到

query_params:get请求提交的参数,等同于request.GET

文件还是在reqeust.FILES中获取
"""

序列化组件介绍

序列化组件是什么:drf提供的一个类,我们继承它,写自己的类
序列化组件的作用:可以快速实现序列化

序列化组件基本使用

定义一个序列化类
"""创建一个py文件,编写序列化类给book进行序列化"""
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title = serializers.CharField()  # 需要序列化的字段
    price = serializers.CharField()
    publish = serializers.CharField()
使用序列化类,序列化多条数据
from app01.serializers import BookSerializer  # 先导入类

class BookView(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        bs = BookSerializer(instance=books, many=True)  # instance代表序列化的数据,如果是多条数据(queryset对象),需要使用many=True表示序列化多条数据
        return Response(bs.data)
使用序列化类,序列化单条数据
class BookDetailView(APIView):
    def get(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        bs = BookSerializer(instance=book)
        return Response(bs.data)

反序列化

系列化类也有数据校验功能

新增

views.py:

def post(self, request):
    bs = BookSerializer(data=request.data)
    if bs.is_valid():  # 校验数据
        bs.save()  # 调用save会触发BookSerializer的save方法,判断,如果生成类的时候instance有值执行update,没有值执行create
        return Response(bs.data)  # 根据规范,返回新增对象数据
    else:
        return Response(bs.errors)  # 返回错误信息

只写上述代码会报错,需要重写create方法
serializers.py:

class BookSerializer(serializers.Serializer):
    title = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        res = models.Book.objects.create(**validated_data)
        return res
修改

views.py:

def put(self, request, pk):
	book = models.Book.objects.filter(pk=pk).first()
    bs = BookSerializer(instance=book, data=request.data)
    if bs.is_valid():  # 校验数据
        bs.save()  # 调用save会触发BookSerializer的save方法,判断,如果生成类的时候instance有值执行update,没有值执行create
        return Response(bs.data)  # 根据规范,返回修改对象数据
    else:
        return Response(bs.errors)  # 返回错误信息

修改也需要重写update方法
serializers.py:

def update(self, instance, validated_data):
    # instance要修改的对象
    # validated_data 校验过后的数据
    instance.name = validated_data.get('name')
    instance.price = validated_data.get('price')
    instance.publish = validated_data.get('publish')
    instance.save()
    return instance
删除
def delete(self, request, pk):
    models.Book.objects.filter(pk=pk).delete()
    return Response()  # 返回空

了解

1 http协议版本区别
1. http/0.9:只有GET命令,服务器只能回应HTML格式字符串
2. http/1.0:每个TCP连接只能发送一个请求,还要发送请求需要再次连接
3. http/1.1:可以持久连接,TCP连接默认不关闭,可以被多个请求复用;keep-alive
4. http/2:复用TCP协议,在一个连接里客户端与浏览器都可以同时发送多个请求或回应,不用按照顺序一一对应
2 http请求头有哪些
1. Accept:设置接受的内容类型
2. Accept-Charset:设置接受的字符编码
3. Accept-Encoding:设置支持的内容编码的优先级顺序
4. Accept-Language:设置接受的语言
5. Connection:设置当前事务完成后,是否会关闭网络连接
6. Connection-Length:设置请求体的字节长度
7. Content-Type:设置请求体的MIME类型
8. referer:包含了当前请求页面的来源页面地址
9. Cookie:设置服务器使用set-cookie发送的http cookie

练习

1 继承apiview写5个接口

urls.py:

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.BookView.as_view()),
    path('books/<int:pk>/', views.BookDetailView.as_view()),
使用APIView

views.py:

from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.serializers import BookSerializer


class BookView(APIView):
    def get(self, request):
        book = models.Book.objects.all()
        bs = BookSerializer(instance=book, many=True)
        return Response(bs.data)

    def post(self, request):
        bs = BookSerializer(data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data) 
        else:
            return Response(bs.errors)


class BookDetailView(APIView):
    def get(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        bs = BookSerializer(instance=book)
        return Response(bs.data)

    def put(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        bs = BookSerializer(instance=book, data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).delete()
        return Response()

serializers.py:

from rest_framework import serializers
from app01 import models


class BookSerializer(serializers.Serializer):
    title = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        res = models.Book.objects.create(**validated_data)
        return res

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance
不使用APIView

views.py:

from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django import views
from app01 import models
from app01.MyForms import Forms_book

class BookView(views.View):
    def get(self, reqeust):
        books = models.Book.objects.all()
        book_list = []  # JsonResponse不能够直接序列化Queryset对象
        for book in books:
            book_list.append({'title': book.title, 'price': book.price, 'publish': book.publish})  # 将每本书的数据以字典的形式追加到列表中
        return JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii': False})  # safe=False才能够序列化列表

    def post(self, request):
        data_dict = json.loads(request.body)
        form_obj = Forms_book(data_dict)
        if form_obj.is_valid():
            data = form_obj.cleaned_data
            models.Book.objects.create(**data)
            return JsonResponse(data)
        else:
            return JsonResponse(form_obj.errors)


class BookDetailView(views.View):
    def get(self, request, pk):
        book = models.Book.objects.filter(pk=pk).first()
        return JsonResponse({'title':book.title,'price':book.price,'publish':book.publish})

    def put(self, request, pk):
        data_dict = json.loads(request.body)
        form_obj = Forms_book(data_dict)
        if form_obj.is_valid():
            data = form_obj.cleaned_data
            models.Book.objects.filter(pk=pk).update(**data)
            return JsonResponse(data)
        else:
            return JsonResponse(json.dumps(form_obj.errors))

    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).delete()
        return HttpResponse()

MyForms.py:

from django import forms

class Forms_book(forms.Form):
    title = forms.CharField(max_length=12)
    price = forms.CharField(max_length=4)
    publish = forms.CharField(max_length=32)
2 fbv写——>写个装饰器,装饰在视图函数,只要一装饰,以后的request就可以使用request.data,这个data无论是那种编码格式,都有数据
def outer(func_name):
    def inner(request, *args, **kwargs):
        if request.POST:
            request.data = request.POST
        else:
            data_dict = json.loads(request.body)
            request.data = data_dict
        res = func_name(request, *args, **kwargs)
        return res
    return inner
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值