RESTful规范
Posted di2wu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RESTful规范相关的知识,希望对你有一定的参考价值。
一、学习restframework之前准备
1、json格式若想展示中文,需要ensure_ascii=False
import json dic={‘name‘:‘你好‘} print(json.dumps(dic,ensure_ascii=False))
2、不基于restframework也可以通过django来做符合restframework的规范接口设计,Jsonresponse,若想在json展示中文,如下
def books(request): ll=[{‘name‘:‘python全站开发‘,‘price‘:20},{‘name‘:‘linux‘,‘price‘:30}] # return HttpResponse(json.dumps(ll)) return JsonResponse(ll,safe=False,json_dumps_params={‘ensure_ascii‘:False})
3、原声cbv执行流程
url(r‘^books/$‘, views.Book.as_view()),
原声cbv执行流程---》as_view----》dispatch---》相应到具体的函数 from django.views import View class Book(View): def get(self,reuquest): # reuquest.method return HttpResponse(‘get‘) def post(self,request): return HttpResponse(‘post‘)
3、分析restframework
一 restfu(规范) 是什么: -面向资源编程 -getBooklist:获取图书列表 -符合规范的:books 规范: -method:get----》books----》取到所有的书 post———》books---》新增图书 put/patch--》books/id---》修改图书 delete---》books/id---》删除图书 -https://api.example.com/v1/zoos?limit=10 - 二 drf 安装(app):pip3 install djangorestframework -基于drf写resful的接口,得写CBV -request对象,源码分析 -APIView源码分析
二、restframework使用
1、POST没法解析json格式,可以在body里取值出来序列化反序列化操作转成字典,目前drf可以在前台提交post后台取值的话用data,
from rest_framework.views import APIView class Book(APIView): def get(self,request): # 拿原来的request对象 # request._request # print(request.method) # print(request._request.method) # request.POST # request.method return HttpResponse(‘get‘) def post(self,request): print(request.method) print(request._request.method) print(request.POST) # 用apiview之后,再取数据,从request.data print(request.data) return HttpResponse(‘post‘)
2、用Postman模拟发http请求,网上直接下载,data可以类似于解析器,解析form-data,urlencoded,json格式,而django只能解析form-data,urlencoded两种格式
三、序列化组件
1、从数据库取出来的都是qs类型,里面套了一个一个对象,要传到前台去必须要json格式,符合drf规范的第一种方式
数据库配置
DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘: ‘resful‘, ‘USER‘:‘root‘, ‘PASSWORD‘:‘‘, ‘HOST‘:‘127.0.0.1‘, ‘PORT‘:3306, } }
models取值为qureryset类型,
from app01 import models 序列化组建 第一种方式 class Book(APIView): def get(self,request): response={‘status‘:100,‘msg‘:None} books=models.Book.objects.all() # ll=[] # for book in books: # ll.append({‘name‘:book.name,‘‘}) ll=[ {‘name‘:book.name,‘price‘:book.price} for book in books] response[‘msg‘]=‘查询成功‘ response[‘data‘]=ll return JsonResponse(response,safe=False) # return HttpResponse(‘get‘) def post(self,request): return HttpResponse(‘post‘)
2、第二种方式,用django子自带序列化组件serializers(Django内置的serializers(把对象序列化成json字符串),但是有个缺点不能定制化
from django.core import serializers class Book(APIView): def get(self,request): # response={‘status‘:100,‘msg‘:None} books = models.Book.objects.all() ret = serializers.serialize("json", books) return HttpResponse(ret) # return HttpResponse(‘get‘) def post(self,request): return HttpResponse(‘post‘)
3、用drf自带的组件,建议的话新建个py在APP下,方便解耦,如myserial.py,为符合drf格式,里面新建个response类,见下
-1 导入:from rest_framework import serializers -2 写一个类(名字任意),继承serializers.Serializer class BookSer(serializers.Serializer): nid=serializers.IntegerField() name3=serializers.CharField(source=‘name‘) price=serializers.CharField() # publish_date = serializers.DateField() publish_date = serializers.CharField() # publish=serializers.CharField(source=‘publish.email‘) publish=serializers.CharField(source=‘publish.name‘) xxx=serializers.CharField(source=‘test‘) -3 如果不指定source,字段名,必须跟数据库列名一致 -4 source--》既可以指定数据属性,又可以指定方法属性,可以写(publish.name) -5 使用: -查询出要序列化的数据:books = models.Book.objects.all() -ret=myserial.BookSer(books,many=True)-----》多条(queryset对象),必须指定many=True -ret=myserial.BookSer(books,many=False)-----》一条(Book对象),必须指定many=False -6 aa=serializers.SerializerMethodField() -必须配套一个方法(get_aa(self,obj)),方法返回结果,会赋给aa -在方法内部,可以继续用序列化组件
myserial.py
from rest_framework import serializers class BookSer(serializers.Serializer): nid=serializers.IntegerField() name3=serializers.CharField(source=‘name‘) price=serializers.CharField() # publish_date = serializers.DateField() publish_date = serializers.CharField() # publish=serializers.CharField(source=‘publish.email‘) publish=serializers.CharField(source=‘publish.name‘) xxx=serializers.CharField(source=‘test‘) # authors=serializers.CharField(source=‘authors.all‘) # SerializerMethodField,可以写一个方法方法名叫:get_字段名字,方法返回值,会赋给authors aa=serializers.SerializerMethodField() # def get_authors(self,obj): # authors=obj.authors.all() # # ll=[ author.name for author in authors] # ll=[ {‘name‘:author.name,‘age‘:author.age} for author in authors] # return ll def get_aa(self, obj): authors = obj.authors.all() # ll=[ author.name for author in authors] ser=AuthorSer(authors,many=True) return ser.data
models.py
class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField(auto_now_add=True) publish = models.ForeignKey(to=‘Publish‘,to_field=‘nid‘,on_delete=models.CASCADE) authors=models.ManyToManyField(to=‘Author‘) def test(self): return ‘ttttttt‘ def __str__(self): return self.name
使用,为符合drf格式,里面新建个response类,@property让类方法变属性,不需要(),直接点+属性就ok了
class MyResponse(): def __init__(self): self.status = 100 self.msg = None @property def get_dic(self): return self.__dict__from app01 import myserial
class Book(APIView): queryset=models.Book.objects.all() serializer_class=myserial.BookSer def get(self,request): response=MyResponse() # 多条 # books = models.Book.objects.all() # ret=myserial.BookSer(books,many=True) # 一条 book = self.queryset # ret = myserial.BookSer(book, many=False) ret = self.serializer_class(instance=book, many=True) response.msg=‘查询成功‘ response.data=ret.data return JsonResponse(response.get_dic,safe=False) # return HttpResponse(‘get‘) def post(self,request):
# return HttpResponse(‘post‘)
4、若要进行多对多的查询,book和author,可以用SerializerMethodField方法
-6 aa=serializers.SerializerMethodField() -必须配套一个方法(get_aa(self,obj)),方法返回结果,会赋给aa -在方法内部,可以继续用序列化组件
如下
class BookSer(serializers.Serializer): nid=serializers.IntegerField() name3=serializers.CharField(source=‘name‘) price=serializers.CharField() # publish_date = serializers.DateField() publish_date = serializers.CharField() # publish=serializers.CharField(source=‘publish.email‘) publish=serializers.CharField(source=‘publish.name‘) xxx=serializers.CharField(source=‘test‘) # authors=serializers.CharField(source=‘authors.all‘) # SerializerMethodField,可以写一个方法方法名叫:get_字段名字,方法返回值,会赋给authors aa=serializers.SerializerMethodField() # def get_authors(self,obj): # authors=obj.authors.all() # # ll=[ author.name for author in authors] # ll=[ {‘name‘:author.name,‘age‘:author.age} for author in authors] # return ll def get_aa(self, obj): authors = obj.authors.all() # ll=[ author.name for author in authors] ser=AuthorSer(authors,many=True) return ser.data class AuthorSer(serializers.Serializer): id=serializers.IntegerField(source=‘nid‘) age=serializers.CharField() name=serializers.CharField()
四 序列化组件之serializers.ModelSerializer
-用法同Serializer -不同点: class BookSer(serializers.ModelSerializer): class Meta: # 指定要序列号的表模型是book model=models.Book fields=‘__all__‘ exclude=[‘nid‘] depth=1
例子如下
from app01 import models class BookSer(serializers.ModelSerializer): class Meta: # 指定要序列号的表模型是book model=models.Book # 把所有字段都序列化 # fields=‘__all__‘ # 可以传列表,指定取几个 # fields=[‘name‘,‘authors‘,‘publish‘] # 除了nid都查 exclude=[‘authors‘] #fields和exclude不能同时用 # depth指定深度,个人建议最多用3 # depth=2
五 序列化组件的字段校验和反序列化功能
序列化组件是将对象序列化成字典,但是前台post提交的json数据需要转成字典,再反序列化成对象,最后save()方法才能保存在数据里,需要反序列功能
-只有:ModelSerializer,能直接保存 - def post(self,request): print(request.data) #生成一个序列化对象 ser=myserial.BookSer(data=request.data) #判断字段是否校验通过 if ser.is_valid(): #通过,直接保存 ser.save() else: #错误信息 print(ser.errors) return HttpResponse(‘post‘)
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
exclude=[‘authors‘]
如下
def post(self,request): # print(request.data) ser=myserial.BookSer(data=request.data) if ser.is_valid(): ser.save() return HttpResponse(‘成功‘) else: print(ser.errors) return JsonResponse(ser.errors)
六 序列化组件局部校验和全局校验
-局部校验 name=serializers.CharField() def validate_name(self,value): if value.startswith(‘sb‘): raise ValidationError(‘不能以sb开头‘) else: return value -全局校验 def validate(self,value): print(type(value)) print(value) name=value.get(‘name‘) price=value.get(‘price‘) if name!=price: raise ValidationError(‘书名和价格不相等‘) else: return value
如下
from rest_framework.exceptions import ValidationError from app01 import models class BookSer(serializers.ModelSerializer): class Meta: # 指定要序列号的表模型是book model=models.Book # 把所有字段都序列化 # fields=‘__all__‘ # 可以传列表,指定取几个 # fields=[‘name‘,‘authors‘,‘publish‘] # 除了nid都查 exclude=[‘authors‘] #fields和exclude不能同时用 # depth指定深度,个人建议最多用3 # depth=2 局部校验 name=serializers.CharField(error_messages={‘required‘:‘该字段必填‘}) def validate_name(self,value): if value.startswith(‘sb‘): raise ValidationError(‘不能以sb开头‘) else: return value 全局校验 def validate(self,value): print(type(value)) print(value) name=value.get(‘name‘) price=value.get(‘price‘) if name!=price: raise ValidationError(‘书名和价格不相等‘) else: return value
views,主要验证前台post提交数据的局部和全局验证
from app01 import myserial class Book(APIView): queryset=models.Book.objects.all() serializer_class=myserial.BookSer def get(self,request): response=MyResponse() # 多条 # books = models.Book.objects.all() # ret=myserial.BookSer(books,many=True) # 一条 book = self.queryset # ret = myserial.BookSer(book, many=False) ret = self.serializer_class(instance=book, many=True) response.msg=‘查询成功‘ response.data=ret.data return JsonResponse(response.get_dic,safe=False) # return HttpResponse(‘get‘) def post(self,request): # print(request.data) ser=myserial.BookSer(data=request.data) if ser.is_valid(): ser.save() return HttpResponse(‘成功‘) else: print(ser.errors) return JsonResponse(ser.errors)
七、符合drf的视图类基本写法
1、views.py
class MyResponse():
def __init__(self):
self.status = 100
self.msg = None
@property
def get_dic(self):
return self.__dict__
class BookDetail(APIView): def get(self,request,id): response=MyResponse() ret=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=ret,many=False) response.msg=‘查询成功‘ response.data=ser.data return JsonResponse(response.get_dic,safe=False) def put(self,request,id): # 修改 response=MyResponse() book=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=book,data=request.data) if ser.is_valid(): # 可以新增,可以修改 ser.save() print(ser.data) print(type(ser.instance)) response.msg=‘修改成功‘ response.data=ser.data else: response.msg = ‘修改失败‘ response.status = 101 response.data=ser.errors return JsonResponse(response.get_dic,safe=False) def delete(self,request,id): ret=models.Book.objects.filter(pk=id).delete() return HttpResponse(‘删除成功‘)
2、序列化组件
url(r‘^books/(?P<pk>d+)/‘, views.BookDetail.as_view()),
from app01 import models
class BookSer(serializers.ModelSerializer):
class Meta:
# 指定要序列号的表模型是book
model=models.Book
exclude=[‘authors‘]
以上是关于RESTful规范的主要内容,如果未能解决你的问题,请参考以下文章