### Django #### Django 接口开发 ##### 前后端分离 + 传统开发模式 + url ---> 视图函数 (逻辑判断、调用数据库、渲染 HTML) ---> 向浏览器返回 HTML 页面 ```python # views.py def more_goods_list(request): goodstype_id = request.GET.get('goodstype_id') goods_obj_list = Goods.objects.filter(goodstype_id=goodstype_id) return render(request, 'buyer/list.html', {'goods_obj_list': goods_obj_list, 'goodstype_id': goodstype_id}) ``` + 前后端分离模型 + 后端只负责返回数据 (一般返回数据类型为 JSON 或 XML),不再负责渲染页面,前端负责渲染数据 1. Vue.js技术,将后台传递给前端的数据渲染到页面 2. 使用 JsonResponse 将字典数据转换为 JSON 格式 ,后台返回 JSON 数据给前端 ```python def more_goods_list_ajax(request): goodstype_id = request.GET.get('goodstype_id') goods_obj_list = Goods.objects.filter(goodstype_id=goodstype_id) goods_dic_list = [] for goods_obj in goods_obj_list: dic = {'name': goods_obj.name, 'img': goods_obj.image.name, 'price': goods_obj.price} goods_dic_list.append(dic) return JsonResponse(goods_dic_list, safe=False) ``` ##### JSON 和 XML + JSON (JavaScript Object Notation) : 轻量级的数据交换格式, 类似于 python 中的字典 1. JSON 和 Python 字典数据类型对应 | Python | JSON | | ---------------- | ------ | | dict | object | | list,tuple | array | | str, unicode | string | | int, long, float | number | | True | true | | False | false | | None | null | + XML (Extensible Markup Language) : 可拓展标记语言,很少使用 XML 数据传输 + JsonResponse 对象 : 可以将 Python 中的字典或者其他数据类型转换为 JSON 数据 ```python from django.http import JsonResponse def getdata(request): user_list = [ {'name': '张三', 'age': 18}, {'name': '李四', 'age': 22}, {'name': '王五', 'age': 24}, ] return JsonResponse(user_list, safe=False) ``` ##### AJAX 1. AJAX 介绍 + AJAX (Asynchronous Javascript And XML) : 异步 JavaScript 和 XML (即 用 JavaScript 语言与服务器进行异步交互, 传输的数据为 XML 和 JSON) + AJAX 特点 : 当服务器响应时,不用刷新整个页面,可以实现局部刷新 + 应用场景 : 注册时信息校验 2. AJAX 格式 (多使用 jQuery 实现 AJAX 请求) 1. 语法 ``` $.ajax({ 参数1: 值1, 参数2: 值2, 参数3: 值3, ... }) ``` 2. 参数介绍 | 参数 | 描述 | | -------- | ------------------------------------------------------------ | | url | 发送请求的地址 | | type | 请求方式('POST'或'GET'),默认为 'GET'.其他 HTTP 请求方法也可以使用,但在部分浏览器可能不支持 | | data | 发送到服务器的数据,格式 : {key: value, key: value} | | error | 请求失败时调用的函数 | | success | 请求成功后的回调函数.参数:由服务器返回数据 | | dataType | 预期服务器返回数据类型,不指定浏览器将自动判断
 1. "xml" : 返回 XML 文档, 可用 jQuery 处理
 2. "html" : 返回纯 HTML 信息
 3. "script" : 返回纯 JavaScript 代码
 4. "json" : 返回 JSON 数据 | ##### Vue 前端渲染 1. Vue 介绍 + Vue 是一套用于构建用户界面的 JavaScript 框架,前端使用 Vue 的目的就是把 AJAX 里面的数据绑定到前端 2. Vue 基本语法 1. 下载引入 2. 第一个应用 + Django 中 使用 Vue 是会发生语法冲突,需要增加标签 **verbatim** 处理,将 Vue 包裹起来 ``` {% verbatim %}
{{ message }}
{% endverbatim %} ``` + Vue.js 的应用可以分为 2 个重要部分 : 视图(HTML 代码)、脚本 + 视图 ``` {% verbatim %}
{{ message }}
{% endverbatim %} ``` + 脚本 ``` ``` + 注意事项 1. 引入 Vue.js 脚本文件 2. 创建视图部分 3. 创建脚本 Vue 对象 4. 注意 : 变量仅可以在选择器范围内使用 3. 常用的基本语法 1. **插值操作** : 将 Vue 对象中的数据显示到页面上. "Mustache" 语法 (双大括号语法) 的文本插值,将数据显示到 HTML 页面中 2. **v-bind** : "Mustache" 不能作用在 HTML attribute 上,遇到此情况应该使用 v-bind 指令 ```
点击
``` 3. **v-if** : 用于条件性的渲染一块内容.此内容只在指令的表达式返回 true 值是被渲染 ```

{{ msg }}

{{ msg }}

{{ msg }}

{{ msg }}

{{ msg }}

``` 4. **v-for** : 类似于确定数值是否在一定范围内,为 True 显示数据 ```
``` 5. **v-on** : 监听 DOM 事件,并在触发时运行一些 JavaScript 代码 ```
``` ##### REST 风格 + **REST** (Representational State Transfer , 变现层状态转移) 与技术无关, 是一种*软件架构风格*、*设计风格*,不是标准,只是一组设计原则和约束条件 + 使用 REST 风格设计的软件可以*更加简洁、更有层次感、更易于实现存储* + RESTful : 满足约束条件和原则的应用程序或设计 + 10 条规则 1. **协议** : API 与用户的通信协议,总是使用 **HTTPS 协议** 2. **域名** : 在域名上区分不同文件 + **子域名**方式区分 1. 'www.xxx.com' : 访问网站 2. 'api.xxx.com' : 返回 接口数据 (JSON 或 XML) + **Url** 区分 1. 'www.xxx.com' : 访问网站 2. 'www.xxx.com/api/' : 添加一个 api 目录, 返回接口数据 3. **版本** : 在 **URL 上添加版本**以区别不同版本程序 'www.xxx.com/app/v1.0' 4. **路径** : 网络上任何东西都是资源,均**使用名词表示** ,减少使用 类似 'getuser' 之类的动词使用 5. **HTTP 动词** : 对资源的具体操作类型 + 常用 HTTP 动词 <=对应=> SQL 命令 1. GET <==> SELECT : 从服务器取出资源 (一项或多项) 2. POST <==> CREATE : 在服务器新建一个资源 3. PUT <==> UPDATE : 在服务器更新资源 (客户端提供改变后的完整资源) 4. DELETE <==> DELETE : 从服务器删除数据 + 3 个不太常用的 HTTP 动词 1. PATCH <==> UPDATE : 在服务器更新资源 (客户端提供改变的属性) 2. HEAD : 获取资源的元数据 3. OPTIONS : 获取信息,关于资源的那些属性是客户端可以改变的 6. **过滤信息** : 如果记录很多,服务器不会全部返回数据给用户,API 应该提供参数,过滤返回结果 + 常见参数 | 参数 | 描述 | | ------------------------ | -------------------------------------------------------- | | `?limit=10` | 指定返回记录数量 | | `?offset=10` | 指定返回记录的开始位置 | | `?page=2&per_page=10` | 指定第几页以及每页的记录数 | | `?sortby=name&order=asc` | 指定返回结果按照那个属性进行排序,以及排序规则 (顺序倒序) | | `?animal_type_id=1` | 指定筛选条件 | 7. **状态码** : 服务器向用户返回状态码和提示信息 + 状态码 | 状态码 | 描述 | | -------------------------------------------- | ------------------------------------------------------------ | | `200 OK - [GET]` | 服务器成功返回用户请求的数据 | | `201 CREATED - [POST/PUT/PATCH]` | 用户新建或修改数据成功 | | `202 Accepted - [*]` | 表示一个请求已进入后台排序 (异步任务) | | `204 NO CONTENT - [DELETE]` | 用户删除数据成功 | | `400 INVALID REQUEST - [POST/PUT/PATCH]` | 用户发出请求有误,服务器没有进行新建或修改数据操作 | | `401 Unauthorized - [*]` | 表示用户没有权限 (令牌、用户名、密码错误) | | `403 Forbidden - [*]` | 表示用户得到授权 (与 401 错误相对),但是禁止访问 | | `404 NOT FOUND - [*]` | 用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的 | | `406 NOT Acceptable - [GET]` | 用户请求的格式不可得 (如用户请求 XML 格式 只有 JSON 格式) | | `410 Gone - [GET]` | 用户请求的资源被永久删除,且不会再得到 | | `422 Unprocesable entity - [POST/PUT/PATCH]` | 当创建一个对象时,发生一个验证错误 | | `500 INTERNAL SERVER ERROR - [*]` | 服务器发生错误,用户将无法判断发出的请求是否成功 | 8. **错误处理** : 如果状态码是 4xx, 服务器就应该向用户返回出错信息.一般来说,返回的信息中 error 作为键名,出错信息作为键值即可 `{error: 'Invalid API key'}` 9. **返回结果** : 针对不同操作,服务器向用户返回的结果应符合以下规范 1. GET /collection : 返回资源对象列表 (数组) 2. GET /collection/resource : 返回单个资源对象 3. POST /collection : 返回新生成的资源对象 4. PUT /collection/resource : 返回完整的资源对象 5. PATCH /collection/resource : 返回完整的资源对象 6. DELETE /collection/resource : 返回一个空文档 10. **超媒体** : 即 返回结果中提供链接,连向其他 API 方法, 是用户不查文档也可以找到下一步 API 11. **其他** : 服务器返回的数据格式, 尽量使用 JSON 数据, 避免使用 XML ##### FBV (基于函数的视图) 和 CBV (基于类的视图) 1. FBV : 函数至少有一个参数 request, 表示当前请求对象 2. CBV : 视图类必须直接或间接继承 django.views.View 类, 定义方法表示接受对应的请求 (方法中 request 表示请求对象, *args 与 *kwargs 用来接收) ```python from django.views import View class GoodsView(View): def get(self, request, *args, *kwargs): pass # 视图类 urlpatterns = [ path('xxxx/xxx/', GoodsView.view.View) ] ``` 3. SCRF 拦截 : Django 的 CSRF 不回拦截 GET 请求, POST、PUT、DELETE都会拦截,可以使用 postman 工具测试拦截情况 + 使用 csrf_exempt 装饰器,去掉 CSRF 拦截, 先调用 dispatch 方法,然后根据不同的请求,调用对应的方法,再次使用 postman 测试 ```python from django.views.decorators.scrf import csrf_exempt from django.utils.decorators import method_decorator @csrf_exempt def goods(request): pass from django.views import View @method_decorator(csrf_exempt, 'dispatch') class GoodsView(View): def get(self, request, *args, **kwargs): return HttpResponse("get 请求") ``` ##### Django REST Framework (DRF) 框架 1. 安装 DRF 框架 1. 安装 : `pip install djangorestframework` 2. 在 `setting.py` 内注册 app ```python INSTALLED_APP = [ ... 'rest_framework', ] ``` 2. 基本使用 : DRF 框架中的 序列化类 可以进行数据格式转换,将 Python 中字典转换为 JSON 格式 1. 创建 Serializer 类 (`serializers.py`) : 在应用中创建 serializers 文件用于编写序列化类, 需要继承 ModelSerializer 或 HyperlinkedModelSerializer (生成 url 路由) ```python from rest_framework import serializers from Store.models import Goods class MoreListlizers(serializers.ModelSerializer): class Meta: model = Goods fields = "__all__" ``` + Serializer 内部类 Meta 属性解释 1. model : 对应的 model 类 2. fields : model 类要序列化的属性 `__all__` 表示所有属性 3. depth : 关联对象序列化的深度,默认只序列化关联对象的 id, 设置为 1 后序列化关联对象所有 filelds 属性 2. 创建视图 ```python from rest_framework import viewsets from .serializers import MoreListlizers class GoodsView(viewsets.ModelViewSet): queryset = Goods.objects.all() serializer_class = MoreListlizers ``` 3. 路由指出 ```python from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register("goods", GoodsView) urlpatterns = [ ... ] urlpatterns += router.urls ``` 4. 访问测试 5. 简单的分页 : 解决 接口直接返回所有数据 的问题,通过DRF快速分页解决问题 (在 `setting.py` 中配置) ```python REST_FRAMWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', # 分页器 'PAGE_SIZE' = 10, } ``` 3. 视图类 1. 继承 APIView 类 : APIView 对 Django 的 django.views.View 类进一步封装 ```python from rest_framework.views import APIView from rest_framework.response import Response class MoreListView(APIView): def get(self, request, format=None): goodstype_id = request.GET.get('goodstype_id') goods_obj_list = Goods.objects.filter(goodstype_id=goodstype_id) serializer = MoreListSerializer(goods_obj_list, many=True) return Response(serializer.data ) # 路由设置 urls.py path('xxx/', MoreListView.as_view()) ``` 2. 使用 mixins 类 : 对 views 进一步封装 , 提高代码重用率 ```python from rest_framework import generics from rest_framework import mixins class MoreListView(mixins.ListModelMixin, generices.GenericAPIView): def get_queryset(self): goodstype_id = self.request.GET.get('goodstype_id') goods_obj_list = Goods.objectsfilter(goodstype_id=goodstype_id).order_by('-id') return goods_obj_list serializer_class = MoreListSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def get_serializer_context(self): return { 'view': self # 返回本身数据,否则 DRF 框架会自动给图片添加绝对路径 } # 路由 path('xxx/', MoreListView.as_view()) ``` 3. 通用视图类 : mixins 类的使用 使代码量减少,但是 使用 REST 框架的 通用混合视图 仍可以进一步减少 视图 的代码量 ```python class MoreListView(generics.ListAPIView): def get_queryset(self): goodstype_id = self.request.GET.get('goodstype_id') goods_obj_list = Goods.objectsfilter(goodstype_id=goodstype_id).order_by('-id') return goods_obj_list serializer_class = MoreListSerializer def get_serializer_context(self): return { 'view': self # 返回本身数据,否则 DRF 框架会自动给图片添加绝对路径 } # 路由 path('xxx/', MoreListView.as_view()) ``` 4. viewSet 视图和路由器 1. viewSet 视图类 是对通用视图的进一步封装 ````python from rest_framework import viewsets class MoreListViewSet(viewsets.ReadOnlyModelViewSet): def get_queryset(self): goodstype_id = self.request.GET.get('goodstype_id') goods_obj_list = Goods.objectsfilter(goodstype_id=goodstype_id).order_by('-id') return goods_obj_list serializer_class = MoreListSerializer def get_serializer_context(self): return { 'view': self # 返回本身数据,否则 DRF 框架会自动给图片添加绝对路径 } # 路由 from django.urls import path, include from buyer import views from rest_framework.router import DefaultRouter more_list = views.MoreListViewSet.as_view({ 'get': 'list', }) urlpatterns = [ ... path('more_list_view/', more_list) ] ```` 2. 使用 DRF 路由器替代 Django 路由 ```python from django.urls import path, include from buyer import views from rest_framework.router import DefaultRouter # 创建路由 router = DefaultRouter() # 注册视图 router.register('more_list_view', views.MoreListViewSet, basename='') urlpatterns = [ ... path('', include(router.urls)) ] ```