Rest Framework:一,认识RESTful
一、CBV的源码分析
-Class Base View(基于类的视图)
-Function Base View(基于函数的视图)
-def as_view 类方法
-def view:类方法内部
闭包函数定义:内层函数包含对外部作用域的引用
-python中一切皆对象:函数也是对象
-hasattr(self, 'get')--判断self类中是不是有该(get)方法
-反射 setattr(self,get,get_all):相当于把get函数,变成了get_all
-getattr(self, 'get'):拿到get函数的内存地址
# 执行:dispatch:谁的dispatch方法?写的cbv的那个c,视图中的那个视图类
# 我这个类如果没有写dispatch,会执行View中的dispatch方法
return self.dispatch(request, *args, **kwargs)
与上方截图是同一地方代码。
下面作用:在路由选择之前(urls.py),是走哪个请求(例如:'get','post'等),是由dispatch来决定的。
-defdispatch(self,request,*args,**kwargs):#request.method前台请求的方法,转成了小写#http_method_namesView中定义的一个列表:是一堆请求方式ifrequest.method.lower()inself.http_method_names:#http_method_names=['get','post','put','patch','delete','head','options','trace']#getattr的第三个参数是默认值:self.http_method_not_allowed#拿到get方法的内存地址handler=getattr(self,request.method.lower(),self.http_method_not_allowed)else:handler=self.http_method_not_allowed#get(request,*args,**kwargs)returnhandler(request,*args,**kwargs)
总结:*******请求来了--->as_view---->view---->dispatch--->分发到不同的函数,执行函数,拿到结果,然后返回
urls.py
# as_view(),是从View中继承过来的,用类来调用的,它是一个类的方法。
# 如果是get请求,会影响到类内部,执行get(或是post)方法
# View类内部函数的内存地址。(例如:get与post的函数重写)
url(r'^login/',views.Test.as_view()),
views.py
fromdjango.viewsimportViewclassTest(View):defget(self,request,*args,**kwargs):print('get')returnrender(request,'login.html')defpost(self,request):#知道这里没传,所以没写,正常情况下要写上->defpost(self,request,*args,**kwargs)name=request.POST.get('name')pwd=request.POST.get('pwd')ifname=='user'andpwd=='123':returnHttpResponse('successful')else:returnrender(request,'login.html',{'error':'用户名密码错误'})
templates/login.html
<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>login</title></head><body><formaction=""method="post"><p>用户名:<inputtype="text"name="name"></p><p>密码:<inputtype="password"name="pwd"></p><p><inputtype="submit"value="提交"><span>{{error}}</span></p></form></body></html>
访问:http://127.0.0.1:8000/login/
登录中是整个页面刷新的,如果只是局部刷新的话,应该用的是ajax提交的表单
阅读源码:(pycharm)
左侧工程栏--->设置图标-->点击--->show members(能看到py文件,类的方法)
二、resful规范(是什么)
- 是一个规范
- 面向资源编程:把网络中所有东西,想象成资源
-规范:
-10条规范
1、-API与用户的通信协议,总是使用HTTPs协议:https比http安全
2、-域名
https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
https://example.org/api/ API很简单
例如写一个查询所有图书的api接口:
https://api.example.com/books
https://127.0.0.1/api/books
3、版本:每个接口都应该有版本
URL
如:https://api.example.com/v1/
https://127.0.0.1/api/v2/books(推荐用这种)
请求头 跨域时,引发发送多次请求
4、路径,视网络上任何东西都是资源,均使用名词表示(可复数)
https://api.example.com/v1/books
https://api.example.com/v1/animals
https://api.example.com/v1/employees
不能这么写:
-获取所有图书:https://127.0.0.1/api/get_all_books
-新增一本书:https://127.0.0.1/api/add_book
同一都用这个:
https://api.example.com/v1/books
5、method
GET :从服务器取出资源(一项或多项)
POST :在服务器新建一个资源
PUT :在服务器更新资源(客户端提供改变后的完整资源)
PATCH :在服务器更新资源(客户端提供改变的属性)
DELETE :从服务器删除资源
6、过滤,通过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
7、状态码
请求回去,需要有状态码
自定义状态码
status: 100表示成功
101表示用户名密码错误
102我也不知道什么错误
8、错误处理,应返回错误信息,error当做key。
-{status:100,error:'错误信息写上'}
9、返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /books:返回资源对象的列表(数组)
GET /books/1:返回单个资源对象
POST /books:返回新生成的资源对象 -新增,传数据,一旦新增完成,把新的资源对象返回
PUT /books/1:返回完整的资源对象
PATCH /books/1:返回完整的资源对象
DELETE /books/1:返回一个空文档
10、Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
{
status:100
msg:成功
url:127.0.0.1/books/1
}
核心:返回结果中提供链接
1、django写resful规范的接口与postman软件:模拟发请求的软件
-格式化json格式数据
-https://www.json.cn/
put请求,django不会帮我解析body内的数据,需要自己处理
models.py
classBook(models.Model):name=models.CharField(max_length=32)price=models.CharField(max_length=32)
数据库迁移
python3 manage.py makemigrations
python3 manage.py migrate
urls.py
url(r'^books/$',views.Books.as_view()),url(r'^books/(?P<pk>\d+)',views.Books.as_view()),
views.py
fromdjango.httpimportJsonResponsefromdjango.viewsimportViewfromapp01importmodelsclassBooks(View):defget(self,request):response={'status':100,'data':None}books=models.Book.objects.all()lst=[{'name':book.name,'price':book.price}forbookinbooks]response['data']=lstreturnJsonResponse(response,safe=False)defput(self,request,pk):importjsondata=json.loads(str(request.body,encoding='utf-8'))name=data.get('name')price=data.get('price')ret=models.Book.objects.filter(pk=pk).update(name=name,price=price)returnJsonResponse({'status':100,'msg':'修改成功'}
login.html
<!DOCTYPEhtml><htmllang="zh"><head><metacharset="UTF-8"><title>login</title></head><body><formaction=""method="post"><p>用户名:<inputtype="text"name="name"></p><p>密码:<inputtype="password"name="pwd"></p><p><inputtype="submit"value="提交"><span>{{error}}</span></p></form></body></html>
通过postman的get请求查看数据
通过postman的put请求修改数据库中的数据
例如:
查看数据库对应已修改人的数据
2、drf(django rest framework)框架(django的app)
安装:djangorestframework
-它是一个app,要在咱的项目中用,需要配置以下配置
在settings.py文件中的INSTALLED_APPS字段中添加:
'rest_framework',
-只是快速的构建resful规范的接口
-csrf_exempt:局部禁用csrf(csrf是可以局部使用,局部禁用)
-以后再执行的dispatch方法是APIView的dispatch方法
-getattr和setattr
urls.py
url(r'^books/$',views.Books.as_view()),url(r'^books/(?P<pk>\d+)',views.Books.as_view()),
views.py
fromrest_framework.viewsimportAPIViewclassBooks(APIView):#现在这个request对象,已经不是原来django中的request对象了,它是rest_framework.request下的Requestdefput(self,request,pk):#django.core.handlers.wsgi.WSGIRequest----原来的djagno中的request的类#现在的request已经成了:rest_framework.request.Request#print(request.PUT)#以后再取数据,直接从request.data中取print(request.data)#前端传过来的编码格式:json格式:{'name':'二狗子','price':'9879797987'}#前端传过来的编码格式:urlencoded格式:<QueryDict:{'name':['红楼梦'],'price':['20']}>#request.data不同编码格式过来,它可能是不同类的对象,但是用法是一样的#原来的request是:request._requestprint(type(request._request))print(request._request.GET)#也能取出来(method,GET,POST,BODY)print(request.GET)returnJsonResponse({'status':100,'msg':'修改成功'})
models.py(与之前上面的内容一样)
使用postman 测试发送数据
-重点掌握这三点:
-request.data 是个方法,包装成了属性,前台传过来body体中数据的数据,放在里面
-request.query_params 这个是原来GET中的数据
-request把原来的request包装进去了
3、序列化
-1 自己写for循环来处理(麻烦)
-2 django提供的序列化组件(不可控)
from django.core import serializers
ret=serializers.serialize('json','queryset对象')
ret就是序列化之后的字符串了,不需要再序列化了
使用django自带的序列化组件。
urls.py与models.py之前都一样,主要是views.py
fromrest_framework.viewsimportAPIViewfromdjango.coreimportserializers#django序列化组件classBooks(APIView):defget(self,request):response={'status':100,'date':None}book=models.Book.objects.all()#先构造出所有书籍的字典的列表#用django提供的序列化组件ret=serializers.serialize('json',book)print(type(ret),ret)#是我序列化完的值#返回数据是json格式数据response['date']=retreturnHttpResponse(ret)
使用postman查看结果,点击下面json按钮,从二进制转换成了json格式。
-3 drf给咱提供的序列化组件
-1 先导入
from rest_framework.serializers import Serializer
from rest_framework import serializers
-2 写一个类,继承Serializer
-3 在类内部写属性:
name=serializers.CharField()
-4 使用:
-先生成对象,需要传参数 instance:要序列化的对象(可能是queryset,也可能是单个对象)
many:如果是queryset---True,,如果是单个对象--False
-5 对象.data --->是一个字典
urls.py与models.py与上面依然一样不变
views.py
fromrest_framework.serializersimportSerializerfromrest_frameworkimportserializersclassBook_Serializer(Serializer):name=serializers.CharField()#如果只需要看一个对像,那就只写一个就好price=serializers.CharField()#如果models.py里面的是其他类型,不是str类型,那么这里也是可以接收的,只是又转为了str类型classBooks(APIView):defget(self,request):books=models.Book.objects.all()#第三步,实例化产生对象#instance=books要序列化的queryset对象,many=True,表示序列化多条ser=Book_Serializer(instance=books,many=True)#可以不按关键字传,不写的话,便是按位置传参#ser=Book_Serializer(books,many=True)#ser.data拿到的是序列化之后的字典,字典里可能套了列表,所以safe=FalsereturnJsonResponse(ser.data,safe=False)
使用postman 来查结果
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。