具体步骤如下:
- 用户通过浏览器访问服务器
- 首先进入实现了WSGI协议的web服务器
- 进入django的中间件
- 开始路由匹配
- 执行相应的视图函数
- 取模板,取数据,用数据渲染模板
- 返回模板的字符串
- 数据展示到用户浏览器
1、前后端不分离项目
- 前端页面看到的效果都是由后端渲染页面或重定向
- 前端与后端的耦合度很高
2、前后端分离项目
- 前端和后端独立开发
- 通过json格式进行数据交互
- 后端仅返回前端所需的数据,不再渲染HTML页面,不再控制前端的效果
- 前端与后端的耦合度相对较低
视图函数一般有两种:
CBV的执行流程:
路由如果这么配置:url(r'^test/', views.Test.as_view()),
请求通过中间件后进入路由--->根据路由匹配,一旦成功,会执行后面函数(request)--->本质就是执行了as_view内部的view函数---->内部又调用了self.dispatch方法---->根据请求方式,执行不同的方法(比如get请求,就会执行咱们写的视图类的get方法)具体可参考我这篇的源码分析:https://blog.csdn.net/weixin_40406241/article/details/91385702
无论是什么请求方式,都需要经过dispatch()方法,那么我们在中间件做控制的操作就可以直接将dispatch()方法重写来实现。比如访问频率的控制等 。
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^Test/', views.Test.as_view())
]
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
class APIView(View):
def dispatch(self, request, *args, **kwargs):
# 前面写一些频率控制的东西
res = super().dispatch(request, *args, **kwargs)
return res
class Test(APIView):
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def get(self, request, *args, **kwargs):
return HttpResponse('ok')
restful是个什么鬼?
- 它代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
- 所有的数据,不管是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
- 面向资源架构(ROA:Resource Oriented Architecture)
restful API设计规范
- API与用户的通信协议,总是使用HTTPs协议。
- 域名有区分:
https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
https://example.org/api/ API很简单
- 版本:
可以放在路径中,如:https://api.example.com/v1/
也可以放在请求头中
- 路径,视网络上任何东西都是资源,均使用名词表示(重点)
https://api.example.com/v1/zoos
https://api.example.com/v1/books
- 通过method区分是什么操作
-get表示获取
-post表示新增
-delete表示删除
-patch/put 表示修改
- 过滤,通过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?limit=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:指定筛选条件
- 状态码:{"status_code": 100}
- 错误处理,应返回错误信息,error当做key
{"status_code":100,'msg':'登录成功'}
{"status_code":101,'msg':'用户名错误'}
- 返回结果,针对不同操作,服务器向用户返回的结果
-get获取所有资源/get获取一个资源
-127.0.0.1/api/vi/books 获取所有图书
{"status_code":100,'msg':'获取成功',data:[{},{}]}
-127.0.0.1/api/vi/books/3 获取id为3的图书
{"status_code":100,'msg':'获取成功',data:{name:xx,....}}
-新增数据,把新增的数据再返回
-修改了数据,返回完整的资源对象
-删除数据,返回一个空文档
- 返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
参考自:https://www.cnblogs.com/liuqingzheng/articles/9762022.html
models.py:
from django.db import models
class Book(models.Model):
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=32)
publish=models.CharField(max_length=32)
视图函数:
from django.http import JsonResponse
from app01 import models
def books(request):
# 获取所有图书
if request.method == 'POST':
books = models.Book.objects.all()
# 前后端分离,需要把queryset对象转成json格式返回
'''
ls = []
for book in books:
bo = {'name': book.name, 'publish': book.publish}
ls.append(bo)
'''
# 上面的for循环换成列表推导式
ls = [{'name': book.name, 'publish': book.publish} for book in books]
response = {'code': 100, 'msg': '查询成功', 'data': ls}
# safe=False,如果json序列化的对象中有列表,需要设置
return JsonResponse(response, safe=False, json_dumps_params={'ensure_ascii': False})
安装:
pip3 install djangorestframework
或者pycharm直接安装
使用了drf框架后,以后的视图都要写成CBV。
使用时,需要在settings的app注册里注册:
INSTALLED_APPS= [
……
'rest_framework'
]
往之前的表里插入两条数据:
先来写一个符合规范的简单get请求 :
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^books/', views.Books.as_view()),
]
视图函数:
from rest_framework.views import APIView
from django.http import JsonResponse
class Books(APIView):
def get(self, request):
'''
request是被封装后的request,原生的request在request._request;
如果想用原生requset中的属性,还是原来的用法,因为Request重写了__getattr__方法;
原生django只能处理urlencoded和formdata编码,如果是json格式,原生django是不能处理的,需要自己从body中取出来自行处理;
request.data 不管前端传数据的编码格式是urlencoded,formdata或者是json,都从里面取值;
request.query_params 是原来django原生的GET中的数据;
request.FILES 就是上传的文件.
'''
books = models.Book.objects.all()
ls = [{'b_name': book.name, 'publish': book.publish} for book in books]
dic = {'name': 'shj', 'age': 18, 'girl_friend': ['刘亦菲', '李一桐', '其他女友'], 'book': ls}
return JsonResponse(dic, safe=False, json_dumps_params={'ensure_ascii': False})
浏览器访问拿到的数据如下:
{"name": "shj", "age": 18, "girl_friend": ["刘亦菲", "李一桐", "其他女友"], "book": [{"b_name": "剑来", "publish": "北京出版社"}, {"b_name": "雪中悍刀行", "publish": "上海出版社"}]}
- request是被封装后的request,原生的request在request._request;
- 如果想用原生requset中的属性,还是原来的用法,因为Request重写了__getattr__方法;
- 原生django只能处理urlencoded和formdata编码,如果是json格式,原生django是不能处理的,需要自己从body中取出来自行处理;
- request.data 不管前端传数据的编码格式是urlencoded,formdata或者是json,都从里面取值;
- request.query_params 是原来django原生的GET中的数据;
- request.FILES 就是上传的文件.
APIView实际上继承了django的View
在CBV继承了APIView之后:
1 所有的请求都没有csrf的认证了
2 在APIView中as_view本质还是调用了父类的as_view(View的as_view)
3 as_view中调用dispatch -----> 这个dispatch是APIView的dispatch
调用父类的as_view(),执行时,又要调用dispatch()方法,这时候,父类View有dispatch方法,APIView类也有dispatch方法,那么执行谁的呢?这就与属性查找顺序有关了。我们继承了APIView,APIView继承了View,那么查找的时候应该先找自己的,因为我们没有写,那么就找它的上一级父类,也就是APIView,这时候发现APIView对dispatch方法是重写了的,因此,接下来走的就是APIView的dispatch方法。
我们去 initialize_request中看看它到底对request做了什么。
点进去看一看
再回到initialize_request,可以知道Request()对象已经是封装后的新的request。
再去dispatch中