验证, 序列化的简单方法,视图的封装 l路由的组件(my)

自定义验证:

#自定义校验必须放在类最外边,如果对字段进行校验
#三个权重分别是自定义>单个字段的验证>全局的联合验证
def my_validate(value):
    #对敏感字符进行过滤
    if "马化腾" in value.lower():
        raise serializers.ValidationError("不能含有敏感字符")
    else:
        return value
PATCH提交数据:{“title”:"马化腾"}

单个字段的验证:

 #验证,单个字段的验证:validate_title

    def validate_title(self, value):  #验证的钩子

        if "go" not in value.lower():
            raise serializers.ValidationError("内容必须含有go")
        else:
            return value
PATCH提交数据:{“title”:"马化腾"}

联合校验的验证:

#联合校验:validate

    def validate(self, attrs):  #attrs有我们所有的字段和数据是个字典
        #要求title必须含有go,并且分类是1
        if "go" in attrs["title"].lower() and attrs["post_category"] == 1:
            return attrs
        else:
            raise serializers.ValidationError('数据不合法,请重新输入')
                # raise 断言抛出异常错误  ValidationError

PATCH提交数据:{“title”:"马化腾"}and{"post_category":1}

实例中的应用:

urls.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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test-fbv', fbv),
    url(r'^test-cbv', CBVView.as_view()),


        #django查看所有图书的接口
    url(r'^books', BookView.as_view()),


    url(r'^api/books', BookAPIView.as_view()),

    #查看单条数据,更新

    url(r'^api/book/(?P<id>\d+)', BookEditView.as_view()),


]
View Code

my_views.py

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


# 第一步 下载 pip install djangorestframework
# 第二步 在settings注册一个app  “rest_framework”
#3,序列化的第一步  声明一个序列化器
#4,写视图



class BookAPIView(APIView):
    def get(self,request):
        book_list = Book.objects.all()
        ser_obj = BookSerializer(book_list, many=True)  # many=True序列化多个
        return Response(ser_obj.data)   #拿到的数据放在data里

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




#查单条调数据
class BookEditView(APIView):
    def get(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)

    def patch(self, request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
                                #instance 更新请求,对谁更新,data:数据,partial=True:允许部分验证
        if ser_obj.is_valid():  #做检验,如果校验成功
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:  #校验不成功
            return Response(ser_obj.errors)
View Code

serializer.py

#序列化器

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]
# }
# (read_only, write_only)针对正序反序字段不统一
# 正序走read_only=True








 #自定义校验必须放在类最外边,如果对字段进行校验
#三个权重分别是自定义>单个字段的验证>全局的联合验证
def my_validate(value):
    #对敏感字符进行过滤
    if "马化腾" in value.lower():
        raise serializers.ValidationError("不能含有敏感字符")
    else:
        return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  #required=False反序列化的时候不进行校验(因为字段不统一)
    title = serializers.CharField(max_length=32,validators=[my_validate])
                                                # validators = [my_validate]  自定义检验
    CHOICES = ((1, "python"), (2, "linux"), (3, "go"))
    category = serializers.CharField(max_length=32,source="get_category_display",read_only=True)#read_only=True展示的时候不显示
                        #get_category_display去中文也可以连表


    post_category =  serializers.ChoiceField(choices=CHOICES,write_only=True)

    pub_time = serializers.DateField()


    publisher = PublisherSerializer(read_only=True)  #创建关联的序列化
    author = AuthorSerializer(many=True,read_only=True)  # many=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"],
                            pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book_obj.author.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.pub_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





    #验证,单个字段的验证:validate_title

    def validate_title(self, value):  #验证的钩子

        if "go" not in value.lower():
            raise serializers.ValidationError("内容必须含有go")
        else:
            return value


#联合校验:validate

    def validate(self, attrs):  #attrs有我们所有的字段和数据是个字典
        #要求title必须含有go,并且分类是1
        if "go" in attrs["title"].lower() and attrs["post_category"] == 1:
            return attrs
        else:
            raise serializers.ValidationError('数据不合法,请重新输入')
                # raise 断言抛出异常错误  ValidationError
View Code

 

 序列化进阶《简单版》:serializers.ModelSerializer

urls.py:

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
   


        #django查看所有图书的接口
    url(r'^books', BookView.as_view()),


    url(r'^api/books', BookAPIView.as_view()),

    #查看单条数据,更新

    url(r'^api/book/(?P<id>\d+)', BookEditView.as_view()),


]
View Code

my_views.py

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


# 第一步 下载 pip install djangorestframework
# 第二步 在settings注册一个app  “rest_framework”
#3,序列化的第一步  声明一个序列化器
#4,写视图



class BookAPIView(APIView):
    def get(self,request):
        book_list = Book.objects.all()
        ser_obj = BookSerializer(book_list, many=True)  # many=True序列化多个
        return Response(ser_obj.data)   #拿到的数据放在data里

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




#查单条调数据
class BookEditView(APIView):
    def get(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)

    def patch(self, request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
                                #instance 更新请求,对谁更新,data:数据,partial=True:允许部分验证
        if ser_obj.is_valid():  #做检验,如果校验成功
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:  #校验不成功
            return Response(ser_obj.errors)
View Code

serializer.py

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)
#序列化进阶版,serializers.ModelSerializer
class BookSerializer(serializers.ModelSerializer):
    category = serializers.CharField(source="get_category_display")#depth获取不到自己写
    class Meta:
        model = Book  #指定的魔性是book
        #fields = ["id","title","pub_time"]   #指定默认展示哪些字段
        fields = "__all__"  #取所有字段
        depth = 1  #能取到外键的字段,category没有取到,需要自己写覆盖里边的category字段
        #depth = 1,数字是虚招外键关系的层数,depth = 2,寻找外键关系第二层,
        # 这个方法让你这些外键关系的字段变成read_only=True,,这是个坑!!
View Code

 需要什么就显示什么,但是会有代码冗余现象,开发效率高

urls.py:

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),



        #django查看所有图书的接口
    url(r'^books', BookView.as_view()),


    url(r'^api/books', BookAPIView.as_view()),

    #查看单条数据,更新

    url(r'^api/book/(?P<id>\d+)', BookEditView.as_view()),


]
View Code

my_views.py

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


# 第一步 下载 pip install djangorestframework
# 第二步 在settings注册一个app  “rest_framework”
#3,序列化的第一步  声明一个序列化器
#4,写视图



class BookAPIView(APIView):
    def get(self,request):
        book_list = Book.objects.all()
        ser_obj = BookSerializer(book_list, many=True)  # many=True序列化多个
        return Response(ser_obj.data)   #拿到的数据放在data里

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




#查单条调数据
class BookEditView(APIView):
    def get(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)

    def patch(self, request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
                                #instance 更新请求,对谁更新,data:数据,partial=True:允许部分验证
        if ser_obj.is_valid():  #做检验,如果校验成功
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:  #校验不成功
            return Response(ser_obj.errors)
View Code

serializer.py

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)
#有些属性需要显示,有些属性不需要显示
class BookSerializer(serializers.ModelSerializer):
    category_dis = serializers.SerializerMethodField(read_only=True)#depth获取不到自己写
    publisher_info = serializers.SerializerMethodField(read_only=True)
    author_info = serializers.SerializerMethodField(read_only=True)

    def get_author_info(self,obj):
        authors = obj.author.all()   #通过obj拿到author
        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):
        #obj序列化的Book对象
        #通过Book对象找到我们的publisher对象
       #就可以拿到我们想要的字段,拼接成自己想要的数据结构
        ret = {
            "id":obj.publisher.id,
            "title":obj.publisher.title
        }
        return ret

    class Meta:
        model = Book  #指定的魔性是book
        #fields = ["id","title","pub_time"]   #指定默认展示哪些字段
        fields = "__all__"  #取所有字段
        # depth = 1  #能取到外键的字段,category没有取到,需要自己写覆盖里边的category字段
        #depth = 1,数字是虚招外键关系的层数,depth = 2,寻找外键关系第二层,
        # 这个方法让你这些外键关系的字段变成read_only=True,,这是个坑!!

        extra_kwargs = {"category":{"write_only":True},"publisher":{"write_only":True},
                        "authors": {"write_only": True}}
        #给默写字段指定参数:正序不显示
View Code

 

APIView和View的区别:

APIView继承View在原来的基础上做了一些拓展。

 视图的封装

第一版本的封装

urls.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

urlpatterns = [
    url(r'^admin/', admin.site.urls),



        #django查看所有图书的接口
    url(r'^books', BookView.as_view()),


    url(r'^api/books', BookAPIView.as_view()),

    #查看单条数据,更新

    url(r'^api/book/(?P<id>\d+)', BookEditView.as_view()),


]
View Code

serializer.py

#序列化器

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)
#有些属性需要显示,有些属性不需要显示
class BookSerializer(serializers.ModelSerializer):
    category_dis = serializers.SerializerMethodField(read_only=True)#depth获取不到自己写
    publisher_info = serializers.SerializerMethodField(read_only=True)
    author_info = serializers.SerializerMethodField(read_only=True)

    def get_author_info(self,obj):
        authors = obj.author.all()   #通过obj拿到author
        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):
        #obj序列化的Book对象
        #通过Book对象找到我们的publisher对象
       #就可以拿到我们想要的字段,拼接成自己想要的数据结构
        ret = {
            "id":obj.publisher.id,
            "title":obj.publisher.title
        }
        return ret

    class Meta:
        model = Book  #指定的魔性是book
        #fields = ["id","title","pub_time"]   #指定默认展示哪些字段
        fields = "__all__"  #取所有字段
        # depth = 1  #能取到外键的字段,category没有取到,需要自己写覆盖里边的category字段
        #depth = 1,数字是虚招外键关系的层数,depth = 2,寻找外键关系第二层,
        # 这个方法让你这些外键关系的字段变成read_only=True,,这是个坑!!

        extra_kwargs = {"category":{"write_only":True},"publisher":{"write_only":True},
                        "authors": {"write_only": True}}
        #给默写字段指定参数:正序不显示
View Code

my_views.py

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


# 第一步 下载 pip install djangorestframework
# 第二步 在settings注册一个app  “rest_framework”
#3,序列化的第一步  声明一个序列化器
#4,写视图


# 如果有很多表就要写很多的代码,代码就会冗余,所以要把这5个方法共同的部分抽出来
#queryst   serializer_class 是不同的

class GenericAPIView(APIView):  #自定义一个类封装,抽取共同部分,让他们继承
    #帮助我们获得queryset,serializer_class
    queryset = None
    serializer_class = None
    #获取queryset
    def get_queryset(self):

        return self.queryset.all()

    # 获取序列化器
    def get_serializer(self,*args,**kwargs):  #接收参数

        return self.serializer_class(*args,**kwargs)#  *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)  # 拿到的数据放在data里


class CreateModelMixin(object):#封装,用于post的逻辑继承
    def create(self,request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)  #验证通过
        else:
            return Response(ser_obj.errors)


class BookAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):
    #重新封装了request对象  用Request类进行封装
    #request.quest_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)  # many=True序列化多个
    #     ser_obj = self.get_serializer(queryset,many=True)  #传参
    #
    #     return Response(ser_obj.data)   #拿到的数据放在data里

# 改装后的get  展示
    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)  #反序data
    #     if ser_obj.is_valid():
    #         ser_obj.save()
    #         return Response(ser_obj.validated_data)  #验证通过
    #     else:
    #         return Response(ser_obj.errors)


# 封装后的post增加
    def post(self,request):
        return self.create(request)


#查单条调数据
class BookEditView(APIView):
    def get(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)

    # 更新
    def patch(self, request,id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
                                #instance 更新请求,对谁更新,data:数据,partial=True:允许部分验证
        if ser_obj.is_valid():  #做检验,如果校验成功
            ser_obj.save()
            return Response(ser_obj.validated_data)
        else:  #校验不成功
            return Response(ser_obj.errors)
    #删除
    def delete(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        if book_obj:
            book_obj.delete()
            return Response("")
        else:
            return Response("删除对象不存在")
View Code

第二版本的封装,第一版本完整的封装后,只是简化了继承的类

my_views.py

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


# 第一步 下载 pip install djangorestframework
# 第二步 在settings注册一个app  “rest_framework”
#3,序列化的第一步  声明一个序列化器
#4,写视图


# 如果有很多表就要写很多的代码,代码就会冗余,所以要把这5个方法共同的部分抽出来
#queryst   serializer_class 是不同的

class GenericAPIView(APIView):  #自定义一个类封装,抽取展示增加的共同部分,让他们继承
    #帮助我们获得queryset,serializer_class
    queryset = None
    serializer_class = None
    #获取queryset
    def get_queryset(self):

        return self.queryset.all()

    # 获取序列化器
    def get_serializer(self,*args,**kwargs):  #接收参数

        return self.serializer_class(*args,**kwargs)#  *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)  # 拿到的数据放在data里


class CreateModelMixin(object):#封装,用于post的逻辑继承
    def create(self,request):
        ser_obj = self.get_serializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)  #验证通过
        else:
            return Response(ser_obj.errors)



class RetrieveModelMixin(object):#自定义一个类封装,用于查询单条数据get继承
    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):  #用于封装更新patch继承
    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): #用于封装删除delete继承
    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):
    #重新封装了request对象  用Request类进行封装
    #request.quest_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)  # many=True序列化多个
    #     ser_obj = self.get_serializer(queryset,many=True)  #传参
    #
    #     return Response(ser_obj.data)   #拿到的数据放在data里

# 改装后的get  展示
    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)  #反序data
    #     if ser_obj.is_valid():
    #         ser_obj.save()
    #         return Response(ser_obj.validated_data)  #验证通过
    #     else:
    #         return Response(ser_obj.errors)


# 封装后的post增加
    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)


    #封装后的get
    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)
    #                             #instance 更新请求,对谁更新,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)
View Code

urls.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'))
"""
# url(r'^test-fbv', fbv),    #测试fbv
# url(r'^test-cbv', CBVView.as_view()),#测试cbv


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

urlpatterns = [
    url(r'^admin/', admin.site.urls),



        #django查看所有图书的接口
    url(r'^books', BookView.as_view()),


    url(r'^api/books', BookAPIView.as_view()),

    #查看单条数据,更新

    url(r'^api/book/(?P<id>\d+)', BookEditView.as_view()),


]
View Code

serializer.py

#序列化器

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]
# }
# (read_only, write_only)针对正序反序字段不统一
# 正序走read_only=True








 #自定义校验必须放在类最外边,如果对字段进行校验
#三个权重分别是自定义>单个字段的验证>全局的联合验证
def my_validate(value):
    #对敏感字符进行过滤
    if "马化腾" in value.lower():
        raise serializers.ValidationError("不能含有敏感字符")
    else:
        return value


# class BookSerializer(serializers.Serializer):
#     id = serializers.IntegerField(required=False)  #required=False反序列化的时候不进行校验(因为字段不统一)
#     title = serializers.CharField(max_length=32,validators=[my_validate])
#                                                 # validators = [my_validate]  自定义检验
#     CHOICES = ((1, "python"), (2, "linux"), (3, "go"))
#     category = serializers.CharField(max_length=32,source="get_category_display",read_only=True)#read_only=True展示的时候不显示
#                         #get_category_display去中文也可以连表
#
#
#     post_category =  serializers.ChoiceField(choices=CHOICES,write_only=True)
#
#     pub_time = serializers.DateField()
#
#
#     publisher = PublisherSerializer(read_only=True)  #创建关联的序列化
#     author = AuthorSerializer(many=True,read_only=True)  # many=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"],
#                             pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
#         book_obj.author.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.pub_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
#
#
#
#
#
#     #验证,单个字段的验证:validate_title
#
#     def validate_title(self, value):  #验证的钩子
#
#         if "go" not in value.lower():
#             raise serializers.ValidationError("内容必须含有go")
#         else:
#             return value
#
#
# #联合校验:validate
#
#     def validate(self, attrs):  #attrs有我们所有的字段和数据是个字典
#         #要求title必须含有go,并且分类是1
#         if "go" in attrs["title"].lower() and attrs["post_category"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError('数据不合法,请重新输入')
#                 # raise 断言抛出异常错误  ValidationError



#有些属性需要显示,有些属性不需要显示
class BookSerializer(serializers.ModelSerializer):
    category_dis = serializers.SerializerMethodField(read_only=True)#depth获取不到自己写
    publisher_info = serializers.SerializerMethodField(read_only=True)
    author_info = serializers.SerializerMethodField(read_only=True)

    def get_author_info(self,obj):
        authors = obj.author.all()   #通过obj拿到author
        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):
        #obj序列化的Book对象
        #通过Book对象找到我们的publisher对象
       #就可以拿到我们想要的字段,拼接成自己想要的数据结构
        ret = {
            "id":obj.publisher.id,
            "title":obj.publisher.title
        }
        return ret

    class Meta:
        model = Book  #指定的魔性是book
        #fields = ["id","title","pub_time"]   #指定默认展示哪些字段
        fields = "__all__"  #取所有字段
        # depth = 1  #能取到外键的字段,category没有取到,需要自己写覆盖里边的category字段
        #depth = 1,数字是虚招外键关系的层数,depth = 2,寻找外键关系第二层,
        # 这个方法让你这些外键关系的字段变成read_only=True,,这是个坑!!

        extra_kwargs = {"category":{"write_only":True},"publisher":{"write_only":True},
                        "authors": {"write_only": True}}
        #给默写字段指定参数:正序不显示
View Code

第三版本精简

 my_views.py

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


# class ModelViewSet(ViewSetMixin, ListCreateModelMixin, RetrieveUpdateDestroyModelMixin):
#     pass  如果用这种方法RetrieveModelMixin 里的id需要改成 pk 跟url相对应

#ModelViewSet  是DRF模块里自带的,所以不需要继承以上方法
class BooksAPIView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
View Code

urls.py

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

        #django查看所有图书的接口
    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"})),
]
View Code

serializer.py

#序列化器

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]
# }
# (read_only, write_only)针对正序反序字段不统一
# 正序走read_only=True








 #自定义校验必须放在类最外边,如果对字段进行校验
#三个权重分别是自定义>单个字段的验证>全局的联合验证
def my_validate(value):
    #对敏感字符进行过滤
    if "马化腾" in value.lower():
        raise serializers.ValidationError("不能含有敏感字符")
    else:
        return value


# class BookSerializer(serializers.Serializer):
#     id = serializers.IntegerField(required=False)  #required=False反序列化的时候不进行校验(因为字段不统一)
#     title = serializers.CharField(max_length=32,validators=[my_validate])
#                                                 # validators = [my_validate]  自定义检验
#     CHOICES = ((1, "python"), (2, "linux"), (3, "go"))
#     category = serializers.CharField(max_length=32,source="get_category_display",read_only=True)#read_only=True展示的时候不显示
#                         #get_category_display去中文也可以连表
#
#
#     post_category =  serializers.ChoiceField(choices=CHOICES,write_only=True)
#
#     pub_time = serializers.DateField()
#
#
#     publisher = PublisherSerializer(read_only=True)  #创建关联的序列化
#     author = AuthorSerializer(many=True,read_only=True)  # many=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"],
#                             pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
#         book_obj.author.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.pub_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
#
#
#
#
#
#     #验证,单个字段的验证:validate_title
#
#     def validate_title(self, value):  #验证的钩子
#
#         if "go" not in value.lower():
#             raise serializers.ValidationError("内容必须含有go")
#         else:
#             return value
#
#
# #联合校验:validate
#
#     def validate(self, attrs):  #attrs有我们所有的字段和数据是个字典
#         #要求title必须含有go,并且分类是1
#         if "go" in attrs["title"].lower() and attrs["post_category"] == 1:
#             return attrs
#         else:
#             raise serializers.ValidationError('数据不合法,请重新输入')
#                 # raise 断言抛出异常错误  ValidationError



#有些属性需要显示,有些属性不需要显示
class BookSerializer(serializers.ModelSerializer):
    category_dis = serializers.SerializerMethodField(read_only=True)#depth获取不到自己写
    publisher_info = serializers.SerializerMethodField(read_only=True)
    author_info = serializers.SerializerMethodField(read_only=True)

    def get_author_info(self,obj):
        authors = obj.author.all()   #通过obj拿到author
        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):
        #obj序列化的Book对象
        #通过Book对象找到我们的publisher对象
       #就可以拿到我们想要的字段,拼接成自己想要的数据结构
        ret = {
            "id":obj.publisher.id,
            "title":obj.publisher.title
        }
        return ret

    class Meta:
        model = Book  #指定的魔性是book
        #fields = ["id","title","pub_time"]   #指定默认展示哪些字段
        fields = "__all__"  #取所有字段
        # depth = 1  #能取到外键的字段,category没有取到,需要自己写覆盖里边的category字段
        #depth = 1,数字是虚招外键关系的层数,depth = 2,寻找外键关系第二层,
        # 这个方法让你这些外键关系的字段变成read_only=True,,这是个坑!!

        extra_kwargs = {"category":{"write_only":True},"publisher":{"write_only":True},
                        "authors": {"write_only": True}}
        #给默写字段指定参数:正序不显示
View Code

 路由的组件:

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
from rest_framework.routers import DefaultRouter    #路由组件



# 实例化DefaultRouter对象
router = DefaultRouter()
#在router里注册路由以及路由匹配的视图
router.register(r"book",BooksAPIView)  #查所有http://127.0.0.1:8000/book可查单条



urlpatterns = [

    url(r'^admin/', admin.site.urls),

        #django查看所有图书的接口
    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"})),
]


urlpatterns += router.urls      #路由组件   

 

posted on 2018-10-30 16:05  liangliang123456  阅读(152)  评论(0编辑  收藏  举报

导航