2,DRF-验证-ModelSerializer-APIView和View的区别-视图的封装-类的继承C3算法

 2,DRF-验证-ModelSerializer-APIView和View的区别-视图的封装

 使用DRF,序列化变的简单

DRF,第三天 1-48:00  django生命请求周期     

 

单点登录:比如百度,登录百度帐号,旗下的产品都可以登录了,

本节封装代码: https://www.cnblogs.com/GGGG-XXXX/articles/9675911.html

目录-https://www.cnblogs.com/GGGG-XXXX/articles/9564651.html
项目目录-https://www.cnblogs.com/GGGG-XXXX/articles/9907408.html

/

视图的封装
    -- 请求进来先走wsgiref模块
    -- 中间件
    -- url 跟我们CBV进行匹配
    -- APIView重写封装了request
        -- request.data
        -- request.query_params
        -- _request

 

 

 /

1.fields='__all__':也是不能序列化外键关系的,因此引入depth方法
2.对于分类(选择种类的字段)depth是不起作用的,需要自己写.
3.get_xxx 后面跟某些内容,是默认的钩子,
4.def get_publisher_info(self, obj):  obj就是要序列化的book对象

APIView的源码分析
    1.super的作用,不是单纯的继承父类的方法,加入o依次继承a,b,c,d,e,super(c,cls) 那就是跳过a,b类了,
    2.在APIView里面用的request不是一开始wsgi封装的request,而是经过处理后的request
    3.在APIView里面,_request才是老的request,而request是新封装的(Request类实例化的一个对象)
    4.request.query_params 获取的是原来的request.GET的数据;
    5.request.data 获取的是包括POST,PUT等其他的数据

 

 

/

 

from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, JsonResponse
from .models import Book, Publisher
from django.core import serializers
import json

# Create your views here.


def fbv(request):
    return HttpResponse("测试fbv")


class CBVView(View):
    def get(self, request):
        return HttpResponse("测试CBV")

    def post(self, request):
        pass

# book_list = [
#     {
#         id: 1,
#         title: xx,
#         xxxx: xxx,
#         pulisher: {title: xxx},
#         authors: [{},{}]
#     }
# ]

class BookView(View):
    # 第一版用。values
    # def get(self, request):
    #     book_list = Book.objects.values("id", "title", "put_time", "category", "publisher")
    #     # querset [{}, {}]
    #     book_list = list(book_list)
    #     # ret = json.dumps(book_list, ensure_ascii=False)
    #     # return HttpResponse(ret)
    #     # JsonResponse HttpResponse 区别
    #     # 做了序列化 json.dumps, 还帮助我们序列化了datetime
    #     # book_obj.get_category_display()
    #     for book in book_list:
    #         publisher_obj = Publisher.objects.filter(id=book["publisher"]).first()
    #         book["publisher"] = {
    #             "id": publisher_obj.id,
    #             "title": publisher_obj.title
    #         }
    #     return JsonResponse(book_list, safe=False, json_dumps_params={"ensure_ascii": False})

    # 用django的serialize方法 外键依然不能够被序列化 取出来的依然是id
    def get(self, request):
        book_list = Book.objects.all()
        ret = serializers.serialize("json", book_list, ensure_ascii=False)
        return HttpResponse(ret)
views.py

/

# -*- coding: utf-8 -*-
# __author__ = "maple"
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializers import BookSerializer
from rest_framework.viewsets import ViewSetMixin, ModelViewSet
# postman

# 第一步 下载 pip install djangorestframework
# 第二步 在settings注册一个app  “rest_framework”
# 序列化的第一步 声明一个序列化器
# 视图
# 把这个5个方法抽出来
# queryset  serializer_class

class GenericAPIView(APIView):
    # 帮助我们获得queryset  serializer_class
    queryset = None
    serializer_class = None

    # 获取queryset
    def get_queryset(self):
        print(type(self.queryset))
        print(type(self.queryset.all()))
        return self.queryset.all()

    # 获取序列化器
    def get_serializer(self, *args, **kwargs):
        return self.serializer_class(*args, **kwargs)

class ListModelMixin(object):
    # 我们的get方法
    def list(self, request):
        queryset = self.get_queryset()
        ser_obj = self.get_serializer(queryset, many=True)
        return Response(ser_obj.data)

class CreateModelMixin(object):
    # 我们的post方法
    def create(self, request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            print(ser_obj.validated_data)
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)

class RetrieveModelMixin(object):
    def retrieve(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(book_obj)
        return Response(ser_obj.data)

class UpdateModelMixin(object):
    def update(self, request, id):
        book_obj = self.get_queryset().filter(id=id).first()
        ser_obj = self.get_serializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:
            return Response(ser_obj.errors)

class DestroyModelMixin(object):
    def destroy(self, request, id):
        book_obj =self.get_queryset().filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response("")
        else:
            return Response("删除对象不存在")

class ListCreateModelMixin(GenericAPIView,ListModelMixin, CreateModelMixin):
    # 方便继承 什么也没做
    pass

class RetrieveUpdateDestroyModelMixin(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    pass


class BookAPIView(ListCreateModelMixin):
    # 执行as_view方法,然后进行了如下的操作,
    # 重新封装了request对象 用Request类进行封装
    # request.query_params  GET
    # request.data  POST PUT
    # 旧的_request
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # def get(self, request):
    #     # book_list = Book.objects.all()
    #     queryset = self.get_queryset()
    #     # ser_obj = BookSerializer(book_list, many=True)
    #     ser_obj = self.get_serializer(queryset, many=True)
    #     # return Response("DRF接口测试ok")
    #     return Response(ser_obj.data)
    def get(self, request):
        return self.list(request)

    # def post(self, request):
    #     book_obj = request.data
    #     print(request.data)
    #     ser_obj = BookSerializer(data=book_obj)
    #     if ser_obj.is_valid():
    #         print(ser_obj.validated_data)
    #         ser_obj.save()
    #         return Response(ser_obj.validated_data)
    #     else:
    #         return Response(ser_obj.errors)

    def post(self, request):
        return self.create(request)


class BookEditView(RetrieveUpdateDestroyModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # def get(self, request, id):
    #     book_obj = Book.objects.filter(id=id).first()
    #     ser_obj = BookSerializer(book_obj)
    #     return Response(ser_obj.data)
    def get(self, request, id):
        return self.retrieve(request, id)

    # def patch(self, request, id):
    #     book_obj = Book.objects.filter(id=id).first()
    #     ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
    #     if ser_obj.is_valid():
    #         ser_obj.save()
    #         return Response(ser_obj.validated_data)
    #     else:
    #         return Response(ser_obj.errors)
    def patch(self, request, id):
        return self.update(request, id)

    # def delete(self, request, id):
    #     book_obj = Book.objects.filter(id=id).first()
    #     if book_obj:
    #         book_obj.delete()
    #         return Response("")
    #     else:
    #         return Response("删除对象不存在")
    def delete(self, request, id):
        return self.destroy(request, id)


# class ModelViewSet(ViewSetMixin, ListCreateModelMixin, RetrieveUpdateDestroyModelMixin):
#     pass


class BooksAPIView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
my_views.py 引入序列化器之后的view

/

# -*- coding: utf-8 -*-
# __author__ = "maple"
from rest_framework import serializers
from .models import Book

class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)


class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)

book_obj = {
    "title": "xxx",
    "category": 1,
    "publisher": 1,
    "authors": [1, 2]
}

def my_validate(value):
    print("my_validate")
    # 对敏感信息进行过滤
    if "马化腾" in value.lower():
        raise serializers.ValidationError("不能含有敏感词汇")
    else:
        return value


# class BookSerializer(serializers.Serializer):
#     id = serializers.IntegerField(required=False)
#     title = serializers.CharField(max_length=32, validators=[my_validate])
#     CHOICES = ((1, "Python"), (2, "Linux"), (3, "go"))
#     category = serializers.CharField(max_length=32, source="get_category_display", read_only=True)
#     post_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
#     put_time = serializers.DateField()
#
#     publisher = PublisherSerializer(read_only=True)
#     authors = AuthorSerializer(many=True, read_only=True)
#
#     publisher_id = serializers.IntegerField(write_only=True)
#     author_list = serializers.ListField(write_only=True)
#
#     def create(self, validated_data):
#         # 执行ORM的新增数据的操作
#         book_obj = Book.objects.create(title=validated_data["title"], category=validated_data["post_category"],
#                             put_time=validated_data["put_time"], publisher_id=validated_data["publisher_id"])
#         book_obj.authors.add(*validated_data["author_list"])
#         print(validated_data["author_list"])
#         return book_obj
#
#     def update(self, instance, validated_data):
#         # 有就更新没有就取默认的
#         instance.title = validated_data.get("title", instance.title)
#         instance.category = validated_data.get("post_category", instance.category)
#         instance.put_time = validated_data.get("put_time", instance.put_time)
#         instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
#         if validated_data.get("author_list"):
#             instance.authors.set(*validated_data["author_list"])
#         instance.save()
#         return instance
#
#     def validate_title(self, value):
#         print("validate_title")
#         if "python" not in value.lower():
#             raise serializers.ValidationError("内容必须含有Python")
#         else:
#             return value
#
#     def validate(self, attrs):
#         print("validate")
#         # attrs有我们所有的字段和数据字典
#         # 要求title含有Python 并且 分类是1
#         if "python" in attrs["title"].lower() and attrs["post_category"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError("数据不合法请重新输入")


class BookSerializer(serializers.ModelSerializer):
    category_dis= serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    author_info = serializers.SerializerMethodField(read_only=True)

    def get_author_info(self, obj):
        # 通过obj拿到authors
        # 构建想要的数据结构返回
        authors = obj.authors.all()
        ret = []
        for author in authors:
            ret.append({
                "id": author.id,
                "name": author.name
            })
        return ret


    def get_category_dis(self, obj):
        return obj.get_category_display()

    def get_publisher_info(self, obj):
        # 序列化的Book对象
        # 通过Book对象找到我们的publisher对象
        # 就可以拿到我们想要的字段
        # 拼接成自己想要的数据结构
        ret = {
            "id": obj.publisher.id,
            "title": obj.publisher.title
        }
        return ret

    class Meta:
        model = Book
        # fields = ["id", "title", "put_time"]
        fields = "__all__"
        # 让你这些外键关系的字段变成read_only = True
        # depth = 1
        extra_kwargs = {"category": {"write_only": True},"publisher": {"write_only": True},
                        "authors":{"write_only": True},"title": {"validators": [my_validate]}}
serializers.py 序列化器

/

from django.db import models

# Create your models here.

__all__ = ["Book", "Publisher", "Author"]

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="图书的名字")
    CHOICES = ((1, "Python"), (2, "Linux"), (3, "go"))
    category = models.IntegerField(choices=CHOICES)
    put_time = models.DateField()

    publisher = models.ForeignKey(to="Publisher")
    authors = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title

    class Meta:
        db_table = "01-图书表"
        verbose_name_plural = db_table

class Publisher(models.Model):
    title = models.CharField(max_length=32, verbose_name="出版社的名称")

    def __str__(self):
        return self.title

    class Meta:
        db_table = "02-出版社表"
        verbose_name_plural = db_table


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者的名字")

    def __str__(self):
        return self.name

    class Meta:
        db_table = "03-作者表"
        verbose_name_plural = db_table
models.py

/

"""DRFDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from SerDemo.views import fbv, CBVView, BookView
# from SerDemo.my_views import BookAPIView, BookEditView
from SerDemo.my_views import BooksAPIView


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test-fbv', fbv),
    url(r'^test-cbv', CBVView.as_view()),
    url(r'^books', BookView.as_view()),
    url(r'^api/books', BooksAPIView.as_view({"get": "list", "post": "create"})),
    url(r'^api/book/(?P<pk>\d+)', BooksAPIView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
]
urls.py

 

 

 

 

字段验证

1,自定义的字段验证

def my_validate(value):
    print("my_validate")
    # 对敏感信息进行过滤
    if "马化腾" in value.lower():
        raise serializers.ValidationError("不能含有敏感词汇")
    else:
        return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate])

 

 

2,单字段验证

单个字段的验证,验证title字段,联想form组件的局部钩子函数,进行字段的验证

def validate_title(self, value): print("validate_title") if "python" not in value.lower(): raise serializers.ValidationError("内容必须含有Python") else: return value

 

3,联合字段验证

def validate(self, attrs):
    print("validate")
    # attrs有我们所有的字段和数据字典
    # 要求title含有Python 并且 分类是1
    if "python" in attrs["title"].lower() and attrs["post_category"] == 1:
        return attrs
    else:
        raise serializers.ValidationError("数据不合法请重新输入")

 

三种验证方法的优先级是:自定义>单字段>联合字段

 

 

ModelSerializer-APIView和View的区别

注意:使用ModelSerializer时,添加或者局部更新数据,都不用写create或者update的方法了,已经内部给实现了.

使用ModelSerializer

class BookSerializer(serializers.ModelSerializer):
    category_dis= serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    author_info = serializers.SerializerMethodField(read_only=True)

    def get_author_info(self, obj):
        # 通过obj拿到authors
        # 构建想要的数据结构返回
        authors = obj.authors.all()
        ret = []
        for author in authors:
            ret.append({
                "id": author.id,
                "name": author.name
            })
        return ret

 

/

 

 关于depth

 表与表之间存在外键关系(可能),存在外键关系的表可能与别的表还存在外键关系,

depth=1,就表示只找一层,

depth=2,表示找2层, 

还有,使用depth之后,会让字段都变成 readonly=True,所以不建议使用.还有可能会出现数据的冗余.

 

 

/

 自定义方法,

对于显示的内容,做一个自定义,使用ModelSerializer之后,解决,category显示是数字而不是对于内容的问题,

/

 多对多的显示

 

 视图

 类的继承,C3算法,

# 归并算法
class A:pass
class B(A):pass
class C(A):pass
class D(B):pass
class E(C):pass
class F(D,E):pass

# 第一步 先找出F类的父类的MRO
# D [D,B,A,O]
# E [E,C,A,O]
# merge([D,B,A,O], [E,C,A,O], [D,E])
# 第一个表的表头  后面所有的表去掉表头部分不能含有这个D
# FD merge([B,A,O], [E,C,A,O], [E])
# FDB merge([A,O], [E,C,A,O], [E])
# 不满足条件时 取二个表的表头,假如取不出来表头(([A,0],[O,A])),python是不允许相互继承的,没有意义,在写继承时就已经报错了,
# FDBE merge([A,O], [C,A,O])
# FDBEC merge([A,O], [A,O])
# FDBECAO

print(F.__mro__)
类的继承顺序

/

类的继承顺序,遵循C3算法,C3算法是一种归并算法,
python是不允许相互继承的,没有意义,如果取不出来表头,在写继承时就
已经报错了,

假如继承顺序,是CBEAO,

super继承时,把E放里面,就是找E之后的继承,
不一定是从C找B,

 

 APIView

APIview是继承View的,基于原来的View进行的一些拓展,把csrf进行了豁免.     
返回的view,执行父类的as_view方法了,
执行APIview的dispatch的方法,把django的wsgi封装的request给重做了,进行了赋值了
所以也就没有request.method,request.POST等等方法了,已经是新的request了,

 

 

 

源码分析-----------****************-----------------

执行as_view方法,然后进行了如下的操作,
重新封装了request对象 用Request类进行封装
request.query_params 对应之前的,request.GET
request.data 对应之前的,request.POST PUT
旧的_request

 

 

 现在是增删改查都实现了,但是会出现代码的冗余,进行方法的合并等一些操作,

 进行了类的封装,

 

/from rest_framework.viewsets import ViewSetMixin (路由可以传参了,)

ViewSetMixin重新写了as_views()的方法,拿到路由传参的参数,进行匹配,

 

 

/ModelViewSet

路由是拿pk来识别的,

 

使用ModelSerializer时,添加或者局部更新数据,都不用写create或者update
的方法了,已经内部给实现了, 

 

 

/

/

 

///////////

 

posted @ 2018-10-30 16:13  Flr  阅读(366)  评论(0)    收藏  举报