验证, 序列化的简单方法,视图的封装 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()), ]
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)
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
序列化进阶《简单版》: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()), ]
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)
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,,这是个坑!!
需要什么就显示什么,但是会有代码冗余现象,开发效率高
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()), ]
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)
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}} #给默写字段指定参数:正序不显示
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()), ]
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}} #给默写字段指定参数:正序不显示
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("删除对象不存在")
第二版本的封装,第一版本完整的封装后,只是简化了继承的类
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)
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()), ]
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}} #给默写字段指定参数:正序不显示
第三版本精简
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
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"})), ]
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}} #给默写字段指定参数:正序不显示
路由的组件:
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) 编辑 收藏 举报