01-初始drf
前后端混合开发和前后端分离
我们使用django开发的BBS,实际上就属于前后端混合开发,前端界面和后端逻辑全部都通过django来完成。
前后端分离则是后端只负责写逻辑,并且返回对应的数据,一般是json给前端,专业的前端界面让前端去完成,至于前端拿到数据之后要开发网页,还是APP活着小程序开发,都是前端自己说了算。
# 前后端混合开发
BBS项目 ---> 混合开发
django写后端,写了模板语言(Django Template Languate)
- 模板语法 --> 对模板(index.html) 渲染(后端完成) --> 模板语法的执行在后端执行
- 我们后端人员,即写了后端,也写了前端
# 前后端分离开发
- 后端只写接口 ---> 配接口 ---> 不需要动前端
- 前端只写前端 ---> 调用接口 --> APP/web 前端人员自己去处理数据的使用
前后端混合开发
前后端分离开发
API接口
概念
web后端提供给前端可以调用的接口,并且通过这个接口能拿到数据,那么这个接口称之为API接口
API接口应该包含哪些
- url地址
- 请求方式,例如 get post delete put
- 请求参数
- 地址栏中的参数,比如:127.0.0.1:8000/index?name=小满&age=3
- 请求体携带参数:常见的编码格式
- 响应结果,目前主流的响应结果为json以及xml
协议算吗?
- 不算,API接口调用的协议都是:HTTP协议,没有别的协议
接口测试工具postman的简单使用
postman :https://www.postman.com/
body的编码格式
get 请求,可以在地址栏中携带数据 ---> 能不能再body体中携带数据?---> 可以
- 注意:可以提交到后端,但是django框架没有放在request.POST中,而是放在request.body中
urlencoded编码格式 ---> 请求体中 ---> name=%E5%B0%8F%E6%BB%A1
form-data格式:携带文件和数据
- 文件从:request.FILES.get('myfile') 获取
myfile
是自己写的变量名- 数据从:request.POST.get() 去获取
- request.body 能不能用,取决于文件的大小,一般不需要打印body(会报错)
json格式
- request.POST 是没有数据的
- 数据存在于request.body中 ---> 需要我们自己去转
请求方式 | 说明 |
---|---|
request.POST | 只有urlencode和form-data才能从request.POST取出来,json取出来是空的,只能从request.body中取出来 |
前端PUT请求 | PUT请求的方式在request.POST中是拿不到数据的,只能通过request.body里面拿,拿到的数据是b'%..' 需要自己去再次处理 |
前端GET请求 | 一样需要通过request.body去拿数据,然后需要自己去再次处理 |
前端JSON请求 | 前端通过json请求是在request.POST中拿不到数据的,只能在request.body里面获取数据,不过可以通过json.loads(数据)反序列化,更方便处理。 |
restful规范
只要写api接口,就建议遵守这个规范。
REST全称是Representational State Transfer,中文意思是表述(通常译为表征性状态转义)。它首次出现在2000年Roy Fielding的博士论文中。
RESTful是一种定义web API接口的设计风格,尤其适用于前后端分离的应用模式中。
我们可以使用任何一个框架都可以实现符合restful规范的API接口
restful的十条规范
-
数据的安全保障
- url链接一般都采用https协议进行传输
- 注:采用https协议,可以提高数据交互过程中的安全性
-
url地址中代接口表示
https://api.xx.com https://www.xx.com/api/
-
url中代版本标识
- 接口有版本
https://api.xx.com/v1/login https://api.xx.com/v2/login
-
数据即是资源,均使用名词(可复数)
- 写给自己:以后所有的接口路径中,尽量不要出现动词,无法避免的除外
- login
- register
- ...
https://api.xx.com/v1/users https://api.xx.com/v1/books https://api.xx.com/v1/books/3
- 写给自己:以后所有的接口路径中,尽量不要出现动词,无法避免的除外
-
请求方式决定如何操作资源【增、删、改、查 检车 curd】
https://api.xx.com/books - get请求:获取所有书 https://api.xx.com/books/1 - get请求:获取主键为1的书 https://api.xx.com/books - post请求:新增一本书 https://api.xx.com/books/1 - put请求:整体修改主键为1的书 https://api.xx.com/books/1 - delete请求:删除主键为1的书
-
url带搜索条件
https://api.xx.com/goods?name=红buff 指定返回搜索的数据
-
响应中带状态码
1xx:请求正在处理 --> 客户端看不到 2xx::正常响应 200:请求成功 201创建成功 3xx:重定向 301临时重定向 302永久重定向 4xx:客户端异常 403:客户端出错 404:页面不存在 5xx:服务器错误 500 503 如果mysql-->链接不上会报错,有一个数字 ,后续遇到这个问题根据这个数字去搜索解决方案就行 例如:MySQL报错1045 自己定制状态码:1001,1002之类,配合上说明
-
响应中带信息描述(错误 或 正常)
- msg
- message
-
针对不同操作符合以下规范
GET /collection: 返回资源对象的列表(数组) {code: 100, msg: 成功, result: [{}, {}, {}...]} GET /collection/resource:返回单个资源对象 {} {code: 100, msg: 成功, result:{}} POST /collection:返回新生成的资源对象 {} PUT /connection/resource:返回完整的资源对象 {} DELETE /collection/resource:返回一个空文档 '' 不过通常情况下,我们可以重新指定 {code:100, msg: 删除成功}
-
返回的数据中带链接,即url
某网站的自定义错误码参考
序列化和反序列化
# api接口开发,最核心最常见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化可以分两个阶段:【序列化值的是转换数据格式:序列化,返序列化】
# 序列化: 把我们识别的数据转换成指定的格式提供给别人
python后端:把python的对象【字典,列表,对象】---》转成json/xml格式字符串过程称之为序列化
例如:我们在django中获取到的数据默认是模型对象(qs/单个对象),但是模型对象数据无法直接提供给前端或别的平台使用,所以我们需要把数据进行序列化,变成字符串或者json数据,提供给别人。
# 反序列化:把别人提供的数据转换/还原成我们需要的格式。
例如:前端js提供过来的json/xml数据,对于python而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中
# js 如何把对象序列化成字符串:【JSON.stringify()】,把字符串饭序列化成对象:【JSON.parse()】
CBV源码分析
# 1 在路由中:path('index/',IndexView.as_view())
# 2 请求来了---》路由匹配成功--》执行 IndexView.as_view()(request)
-看View类的as_view的返回结果[可以加括号执行]---》猜:函数内存地址
# 3 View类的as_view
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs) # cls--》IndexView
return self.dispatch(request, *args, **kwargs)
return view
# 4 IndexView.as_view() 本质就是 --》view--》内存函数view
# 5 IndexView.as_view()(request)---》view(request)
# 6 本质 执行 self.dispatch--》self 是对象--》谁的对象?视图类的对象IndexView类的对象
return self.dispatch(request, *args, **kwargs)
# 7 IndexView没有dispatch--》View类中的dispatch
# request 当次请求的requets
def dispatch(self, request, *args, **kwargs):
#1 取出请求方式,转成小写,判断在不在列表中 get请求在
#2 self.http_method_names
if request.method.lower() in self.http_method_names:
# 3 反射:去 self IndexView类的对象中通过字符串get找属性或方法
# 找到了get方法,赋值给了handler
handler = getattr(self, request.method.lower())
else:
handler = self.http_method_not_allowed
# 4 执行handler--》本质是get(request)
# 执行了IndexView类中的get方法--》把request传进去了
return handler(request, *args, **kwargs)
# 8 总结:
路由匹配成功---》会根据请求方式执行视图类中跟请求方式同名的方法
通过postman结合djangoCBV实现中间件获取IP地址和请求头加入数据库
# urls
from django.urls import path, re_path
from .views import TaskView, TaskDetailView
app_name = 'app02'
urlpatterns = [
path('v1/', TaskView.as_view()),
path('v1/<int:num>/', TaskDetailView.as_view()),
]
# 中间件
from django.utils.deprecation import MiddlewareMixin
from django.http import JsonResponse
from app02.models import UserLog
class IPMiddleware(MiddlewareMixin):
def process_request(self, request):
method = request.method
if method.lower() == "delete":
return JsonResponse({'code': 100, 'msg': '禁止删除!'})
path = request.path
ip = request.META.get("REMOTE_ADDR")
user_agent = request.META.get('HTTP_USER_AGENT')
UserLog.objects.create(method=method, path=path, ip=ip, user_agent=user_agent)
return JsonResponse({"code": 200, "msg": f"来自{ip}的朋友,访问成功!"})
def process_exception(self, request, exception):
msg = '访问的页面已丢失!'
return JsonResponse({'code': 100, "msg": msg})
# 模型层
from django.db import models
# Create your models here.
class UserLog(models.Model):
ip = models.CharField(max_length=32, null=True)
method = models.CharField(max_length=10, null=True)
path = models.CharField(max_length=22, null=True)
user_agent = models.CharField(max_length=255, null=True)
time = models.DateTimeField(auto_now=True, null=True)
class Meta:
db_table = 'user_log'
DRF快速体验
相当于django上的app,作用是帮助我们快速实现符合restful规范的接口
安装模块 djangorestframework
注意:
需要django4以上的版本
如果安装django4以上的版本,那么MySQL版本要8以上
解决方案
- 更新MySQL到8以上
- 注释掉源码的一段代码
# 使用mysql 作为数据库,django 4.x 会报错 django.db.utils.NotSupportedError: MySQL 8 or later is required (found 5.7.44). def init_connection_state(self): # self.check_database_version_supported() 注释掉
# 安装模块
pip install djangorestframework
基于drf的测试代码
# urls.py
from rest_framework.routers import SimpleRouter
from .views import TaskView
# 创建一个简单路由器对象
router = SimpleRouter()
# 注册 TaskView 视图集,并映射到 URL 路径 'task/' 上,指定名称为 'task'
router.register("task", TaskView, 'task')
urlpatterns = [
# 这里可以添加其他 urlpatterns
]
# 将路由器的 URL 配置添加到 urlpatterns 中
urlpatterns += router.urls
# views.py
from .models import NeWTask
from .serializers import TaskSerializer
from rest_framework.viewsets import ModelViewSet
# 创建一个视图集 TaskView,继承自 ModelViewSet,用于处理 CRUD 操作
class TaskView(ModelViewSet):
# 指定视图集的 queryset 为 NeWTask 模型的所有对象
queryset = NeWTask.objects.all()
# 指定视图集的 serializer_class 为 TaskSerializer
serializer_class = TaskSerializer
# serializers.py
from .models import NeWTask
from rest_framework import serializers
# 创建一个序列化器 TaskSerializer,继承自 ModelSerializer
class TaskSerializer(serializers.ModelSerializer):
class Meta:
# 指定序列化器的 Meta 类中的 model 为 NeWTask 模型
model = NeWTask
# 指定序列化器的 Meta 类中的 fields 为 '__all__',表示序列化所有字段
fields = "__all__"
# models.py
from django.db import models
# 创建一个模型 NeWTask,用于表示任务信息
class NeWTask(models.Model):
# 定义任务ID字段,类型为 CharField,最大长度为 128,且唯一
task_id = models.CharField(max_length=128, verbose_name="任务id 类型是uuid", unique=True)
# 定义任务名称字段,类型为 CharField,最大长度为 32
task_name = models.CharField(max_length=32, verbose_name='任务名称')
# 定义任务时间字段,类型为 DateTimeField,用于记录任务创建时间,auto_now 参数表示每次更新时自动更新时间
task_time = models.DateTimeField(verbose_name='任务时间', auto_now=True)
# 定义任务描述字段,类型为 TextField,用于记录任务描述信息
task_desc = models.TextField(verbose_name="任务描述")
class Meta:
# 指定模型的数据库表名为 'new_task'
db_table = "new_task"
本文作者:小满三岁啦
本文链接:https://www.cnblogs.com/ccsvip/p/18127739
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。