1 drf框架 2 全称: 3 4 """ 5 1.接口:什么是接口 restful 接口规范 6 2.CBV 生命请求周期源码 ,基于restful 规范下的CBV 接口 7 3.请求组件,解析组件,响应组件 8 4.序列化组件(灵魂) 9 5.三大认证(重中之重): 认证,权限(权限六表),频率 10 6.其他组件: 过滤,筛选,排序,分页,路由 11 """ 12 13 # 难点: 源码分析 14 15 接口: 16 """ 17 接口:联系两个物质的媒介, 完成信息交互 18 web程序中: 联系前台页面与后台数据库的媒介 19 web接口组成: 20 url: 长的像放回数据的url 链接 21 请求参数: 前台按照指定的key提供数据给后台 22 响应数据: 后台与数据库交互后将数据反馈给前台 23 """ 24 25 restful 接口规范 26 27 接口规范:就是为了采用不同的后台语言,也能使用同样的接口获取到同样的数据 28 29 如何写接口: 接口规范是 规范化书写接口的, 写接口要写url, 响应数据 30 ps: 如果将请求参数也纳入考量范围, 那就写接口文档 31 32 两大部分: url 响应数据 33 34 .url: 35 1) 用api 关键字标识接口url 36 例: www.baidu.com/api | api.baidu.com 37 2) 接口数据安全性决定优先选择https协议 38 3) 如果一个接口有多版本共存 需要在url 中标识体现 39 4) 接口操作的数据源 称之 为 资源, 在url中一般采用资源复数形式, 一个接口可以概括对该资源的多种操作方式 40 api.baidu.com/books | api.baidu.com/books/(pk) 41 5) 请求方式有多种, 用一个 url 处理如何保证不混乱 - 通过请求方式 标识操作资源的方式 42 /books get 获取所有 43 /books post 增加一个(多个) 44 /books/(pk) delete 删除一个 45 /books/(pk) put(update的意思) 整体更新一个 46 /books/(pk) patch 局部更新一个 47 6) 资源往往涉及数据的各种操作方式 - 筛选 排序 限制 48 api.baidu.com/books/?search=西&ordering=-price&limit=3 49 50 .响应数据 51 1) http 请求的响应会有响应状态码, 接口用来返回操作的资源数据 可以拥有操作数据结果的状态码 52 status 0(操作资源成功) 1(操作资源失败) 2(操作资源成功,但没匹配结果) 53 ps: 资源状态码不像http状态码 一般都是后台与前台或者客户约定的 54 55 2) 资源的状态码文字提示 56 status ok '账户有误' '密码错误' '用户锁定' 57 3) 资源本身 results ps: 删除资源成功不做任何数据返回(返回空字符串) 58 4) 不能直接返回的资源(子资源,图片,视频等资源), 返回该资源的url链接 59 60 基于restful规范的原生Django接口 61 62 主路由:url.py 63 64 ```python 65 from django.conf.urls import url, include 66 from django.contrib import admin 67 68 69 urlpatterns = [ 70 url(r'^admin/', admin.site.urls), 71 # 路由分发 72 url(r'^api/', include('api.urls')) 73 ] 74 ``` 75 76 api组件的子路由:api/url.py 77 78 ```python 79 from django.conf.urls import url 80 81 from . import views 82 urlpatterns = [ 83 url(r'^books/', views.Book.as_view()), 84 url(r'^books/(?P<pk>.*)/$', views.Book.as_view()), 85 ] 86 ``` 87 88 模型层:model.py 89 90 ```python 91 from django.db import models 92 93 class Book(models.Model): 94 title = models.CharField(max_length=64) 95 price = models.DecimalField(max_digits=5, decimal_places=2) 96 97 class Meta: 98 db_table = 'old_boy_book' # 自定义表 99 verbose_name = '书籍' # admin 默认加s 100 verbose_name_plural = verbose_name # 去掉s 101 102 def __str__(self): 103 return '《%s》' % self.title 104 ``` 105 106 后台层:admin.py 107 108 ```python 109 from django.contrib import admin 110 111 from . import models 112 113 admin.site.register(models.Book) 114 ``` 115 116 #数据库迁移 117 python manage.py makemigrations 118 python manage.py migrate 119 120 python manage.py createsuperuser 121 122 视图层:views.py 123 124 ```python 125 from django.http import JsonResponse 126 127 from django.views import View 128 from . import models 129 130 131 # 六大基础接口:获取一个 获取所有 增加一个 删除一个 整体更新一个 局部更新一个 132 # 十大接口:群增 群删 整体改群改 局部改群改 133 class Book(View): 134 def get(self, request, *args, **kwargs): 135 pk = kwargs.get('pk') 136 if not pk: # 群查 137 # 操作数据库 138 book_obj_list = models.Book.objects.all() 139 # 序列化过程 140 book_list = [] 141 for obj in book_obj_list: 142 dic = {} 143 dic['title'] = obj.title 144 dic['price'] = obj.price 145 book_list.append(dic) 146 # 响应数据 147 return JsonResponse({ 148 'status': 0, 149 'msg': 'ok', 150 'results': book_list 151 }, json_dumps_params={'ensure_ascii': False}) 152 else: # 单查 153 book_dic = models.Book.objects.filter(pk=pk).values('title', 'price').first() 154 if book_dic: 155 return JsonResponse({ 156 'status': 0, 157 'msg': 'ok', 158 'results': book_dic 159 }, json_dumps_params={'ensure_ascii': False}) 160 return JsonResponse({ 161 'status': 2, 162 'msg': '无结果', 163 }, json_dumps_params={'ensure_ascii': False}) 164 165 166 # postman可以完成不同方式的请求:get | post | put ... 167 # postman发送数据包有三种方式:form-data | urlencoding | json 168 # 原生django对urlencoding方式数据兼容最好 169 def post(self, request, *args, **kwargs): 170 # 前台通过urlencoding方式提交数据 171 try: 172 book_obj = models.Book.objects.create(**request.POST.dict()) 173 if book_obj: 174 return JsonResponse({ 175 'status': 0, 176 'msg': 'ok', 177 'results': {'title': book_obj.title, 'price': book_obj.price} 178 }, json_dumps_params={'ensure_ascii': False}) 179 except: 180 return JsonResponse({ 181 'status': 1, 182 'msg': '参数有误', 183 }, json_dumps_params={'ensure_ascii': False}) 184 185 return JsonResponse({ 186 'status': 2, 187 'msg': '新增失败', 188 }, json_dumps_params={'ensure_ascii': False}) 189 ``` 190 191 Postman接口工具 192 193 官网下载安装 194 195 get请求,携带参数采用Params 196 197 post等请求,提交数据包可以采用三种方式:form-date、urlencoding、json 198 199 所有请求都可以携带请求头 200 201 202 DRF框架 203 安装: pip3 install djangorestframework 204 205 drf框架规矩的封装风格 206 207 ```python 208 from rest_framework.views import APIView 209 from rest_framework.response import Response 210 from rest_framework.request import Request 211 from rest_framework.serializers import Serializer 212 from rest_framework.settings import APISettings 213 from rest_framework.filters import SearchFilter 214 from rest_framework.pagination import PageNumberPagination 215 from rest_framework.authentication import TokenAuthentication 216 from rest_framework.permissions import IsAuthenticated 217 from rest_framework.throttling import SimpleRateThrottle 218 219 class Test(APIView): 220 def get(self, request, *args, **kwargs): 221 return Response('drf get ok') 222 ``` 223 224 drf请求生命周期 225 226 """ 227 1) 请求走的是APIView 的as_view函数 228 2) 在APIView的as_view 调用父类(django原生) 的as_view, 还禁用了csrf 认证 229 3) 在父类的as_view 中 dispatch 方法请求走的又是APIView 的dispatch 230 4) 完成任务方法交给视图类的请求函数处理, 得到请求的响应结果 返回给前台 231 """ 232 233 #请求模块:request对象 234 235 ## 源码入口 236 237 APIView类的dispatch方法中:request = self.initialize_request(request, *args, **kwargs) 238 239 # 源码分析 240 """ 241 # 二次封装得到def的request对象 242 request = self.initialize_request(request, *args, **kwargs) 点进去 243 244 # 在rest_framework.request.Request实例化方法中 245 self._request = request 将原生request作为新request的_request属性 246 247 # 在rest_framework.request.Request的__getattr__方法中 248 try: 249 return getattr(self._request, attr) # 访问属性完全兼容原生request 250 except AttributeError: 251 return self.__getattribute__(attr) 252 """ 253 254 重点总结 255 256 # 1) drf 对原生request做了二次封装,request._request就是原生request 257 # 2) 原生request对象的属性和方法都可以被drf的request对象直接访问(兼容) 258 # 3) drf 请求的所有url 拼接参数都被解析到query_params中,所有数据包数据都被解析到data 259 260 class Test(APIView): 261 def get(self, request, *args, **kwargs): 262 # url拼接的参数 263 print(request._request.GET) # 二次封装方式 264 print(request.GET) # 兼容 265 print(request.query_params) # 拓展 266 267 return Response('drf get ok') 268 269 def post(self, request, *args, **kwargs): 270 # 所有请求方式携带的数据包 271 print(request._request.POST) # 二次封装方式 272 print(request.POST) # 兼容 273 print(request.data) # 拓展,兼容性最强,三种数据方式都可以 274 275 print(request.query_params) 276 277 return Response('drf post ok') 278 279 280 渲染模块:浏览器和Postman请求结果渲染数据的方式不一样 281 282 ##源码入口 283 284 APIView类的dispatch方法中:self.response = self.finalize_response(request, response, *args, **kwargs) 285 286 源码分析 287 """ 288 # 最后解析reponse对象数据 289 self.response = self.finalize_response(request, response, *args, **kwargs) 点进去 290 291 # 拿到运行的解析类的对象们 292 neg = self.perform_content_negotiation(request, force=True) 点进去 293 294 # 获得解析类对象 295 renderers = self.get_renderers() 点进去 296 297 # 从视图类中得到renderer_classes请求类,如何实例化一个个对象形参解析类对象列表 298 return [renderer() for renderer in self.renderer_classes] 299 300 # 重点:self.renderer_classes 获取 renderer_classes的顺序 301 # 自己视图类的类属性(局部配置) => 302 # APIView类的类属性设置 => 303 # 自己配置文件的DEFAULT_RENDERER_CLASSES(全局配置) => 304 # drf配置文件的DEFAULT_RENDERER_CLASSES 305 """ 306 307 全局配置:所有视图类统一处理,在项目的settings.py中 308 309 ```python 310 REST_FRAMEWORK = { 311 # drf提供的渲染类 312 'DEFAULT_RENDERER_CLASSES': [ 313 'rest_framework.renderers.JSONRenderer', 314 'rest_framework.renderers.BrowsableAPIRenderer', 315 ], 316 } 317 ``` 318 319 局部配置:某一个或一些实体类单独处理,在views.py视图类中提供对应的类属性 320 321 ```python 322 class Test(APIView): 323 def get(self, request, *args, **kwargs): 324 return Response('drf get ok') 325 326 def post(self, request, *args, **kwargs): 327 return Response('drf post ok') 328 329 # 在setting.py中配置REST_FRAMEWORK,完成的是全局配置,所有接口统一处理 330 # 如果只有部分接口特殊化,可以完成 - 局部配置 331 from rest_framework.renderers import JSONRenderer 332 class Test2(APIView): 333 # 局部配置 334 renderer_classes = [JSONRenderer] 335 def get(self, request, *args, **kwargs): 336 return Response('drf get ok 2') 337 338 def post(self, request, *args, **kwargs): 339 return Response('drf post ok 2') 340 ```