操作系统: windows
IDE: Pycharm
API接口文档:
如果采用前后端分离的架构开发, 后端几乎不负责任何展现界面的工作,只负责对数据进行管理 。数据的管理,主要就是:响应前端的请求, 对数据资源的增加、删除、修改、查询 。
实际生产过程中系统的数据在前后端的往来通过API接口,其中自然包括了客户数据的增查改删接口。设计人员根据需求编好接口文档,将来就需要根据这样的文档来实现后端的功能。
比如接口文档明确说明了,设计针对管理员用户的请求。
前面我们已经为销售员用户专门创建了一个应用:sales 来处理相关的 请求。
所以,我们可以再为管理员用户专门创建一个应用: mgr 来处理相关的 请求。
根目录执行:
python manage.py startapp mgr
添加处理请求模块 :
前面都是在views.py 里面定义函数,处理 http请求的。
但是可以想象,如果请求的类型有很多,那么view.py这个文件会变得非常的庞大,不好维护。所以,我们可以在mgr目录下,设置用不同的 .py 文件处理不同类型的http请求。
比如,这里我们可以新增一个文件 customer.py, 专门处理客户端对 customer 数据的操作。将来如果客户端有对其他类型数据的操作, 比如 order 数据, 我们就可以添加 orders.py 来处理。
处理请求模块的url 路由:
接下来需要从接口文档看需求,我们可以发现对资源的增删改查操作, 都是同一个URL,都是 /api/mgr/medicine
。
而且我们发现,不同的操作请求,使用不同的 HTTP 请求方法 ,添加是POST, 查询是 GET, 修改是 PUT, 删除是 DELETE。
而且请求的参数中都有action参数表明这次请求的操作具体是什么。
注意: Django的url路由功能不支持直接根据HTTP请求的方法和请求体里面的参数进行路由。
就是不能像下面这样,来根据请求 是 post 还是 get 来 路由:
path('customers/', 'app.views.list_customer', method='get'),
path('customers/', 'app.views.add_customer', method='post'),
那么如何实现根据不同的需要选择对应的函数呢?
一种方式是:自己编写一个函数,来根据 http请求的类型和请求体里面的参数分发(或者说路由)给不同的函数进行处理。
我们可以在 mgr\customer.py 中定义如下 dispatcher
函数:
from django.http import JsonResponse
import json
def dispatcher(request):
# 将请求参数统一放入request的params属性中,方便后续处理
# GET请求 参数在url中,同过request 对象的 GET属性获取
if request.method == 'GET':
request.params = request.GET
# POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
elif request.method in ['POST', 'PUT', 'DELETE']:
# 根据接口文档,POST/PUT/DELETE 请求的消息体都是 json格式
# json.loads把json字符串转化为python的字典类型的对象
request.params = json.loads(request.body)
# 根据不同的action分派给不同的函数进行处理
action = request.params['action']
if action == 'list_customer':
return listcustomers(request)
elif action == 'add_customer':
return addcustomer(request)
elif action == 'modify_customer':
return modifycustomer(request)
elif action == 'del_customer':
return deletecustomer(request)
else:
# 把括号内的内容转化为json字符串
return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})
别忘了把路由也要修改:
总路由urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('sales/', include('sales.urls')),
# 加上这条
path('/api/mgr/', include('mgr.urls'))
]
然后再是mgr目录下的路由mgr\urls.py:
from django.urls import path
# 这个比from mgr.customer import dispatcher要好,因为将来可能会有很多个dispatcher
from mgr import customer
urlpatterns = {
path('customers', customer.dispatcher)
}
现在再来实现四个具体的函数,还是在mgr\customer.py下:
列出客户信息(查询全部):
根据接口文档,列出客户数据接口,后端返回的数据格式如下:
{
"ret": 0,
"retlist": [
{
"address": "江苏省常州武进市白云街44号",
"id": 1,
"name": "武进市 袁腾飞",
"phonenumber": "13886666666"
},
{
"address": "北京海淀区",
"id": 4,
"name": "北京海淀区代理 蔡国庆",
"phonenumber": "13990123456"
}
]
}
因为前后端分离,这里我们无需将数据库中获取的数据 转化为供浏览器展示的HTML。
在前后端分离的开发架构中,如何展示数据,那是前端的事情。我们后端只需要根据接口文档, 返回原始数据就行。
我们可以使用如下的函数来返回数据库中查询到的所有的客户数据信息:
# 别忘了导入Customer
from common.models import Customer
# 这里是dispatcher的部分
# 列出用户信息
def listcustomers(request):
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Customer.objects.values()
# 将 QuerySet对象转化为 list 类型
# 否则不能被转化为json字符串
retlist = list(qs)
return JsonResponse({'ret': 0, 'retlist': retlist})
添加客户信息:
根据接口文档,添加客户数据接口,前端提供的客户数据格式如下:
{
"action":"add_customer",
"data":{
"name":"武汉市桥西医院",
"phonenumber":"13345679934",
"address":"武汉市桥西医院北路"
}
}
添加客户信息的函数:
# 添加客户信息
def addcustomer(request):
info = request.params['data']
# 从请求消息中 获取要添加客户的信息
# 使用ORM的方法,把信息插入到数据库中 create就是创建一条记录
# 返回值 就是对应插入记录的对象
record = Customer.objects.create(name=info['name'],
phonenumber=info['phonenumber'],
address=info['address'])
# record就是表里面一条记录 id就是数据库中自增的那个id
return JsonResponse({'ret': 0, 'id': record.id})
Customer.objects.create
方法就可以通过ORM的方式添加一条Customer表里面的记录。
临时取消 CSRF 校验:
根据接口文档,添加客户请求是个Post请求
POST /网站名/api/mgr/signin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
注意,缺省创建的项目, Django 会启用一个 CSRF(跨站请求伪造) 安全防护机制。
在这种情况下, 所有的POST、PUT类型的请求都必须在HTTP请求头中携带用于校验的数据。
为了简单起见,我们先临时取消掉CSRF的校验机制,等以后有需要再打开。
要临时取消掉CSRF的校验机制,非常简单,只需要在项目的配置文件 Django_test/settings.py 中 MIDDLEWARE 配置项里注释掉 ‘django.middleware.csrf.CsrfViewMiddleware’
即可。
如下所示:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
修改客户信息:
根据接口文档,修改客户数据接口,前端提供的数据格式如下
{
"action":"modify_customer",
"id": 6,
"newdata":{
"name":"武汉市桥北医院",
"phonenumber":"13345678888",
"address":"武汉市桥北医院北路"
}
}
相当与对于指定id的客户信息,我们用新的数据覆盖掉老的数据:
# 修改客户信息
def modifycustomer(request):
# 从请求消息中 获取修改客户的信息
# 找到该客户,并且进行修改操作
customerid = request.params['id']
newdata = request.params['newdata']
try:
# 根据id从数据库中找到相应的客户记录
# object.get()方法就是查询记录的一种方式,找到就返回有一个Customer类型的实例化对象
customer = Customer.objects.get(id=customerid)
except Customer.DoesNotExist:
return {
'ret': 1,
'msg': f'id 为`{customerid}`的客户不存在'
}
if 'name' in newdata:
customer.name = newdata['name']
if 'phonenumber' in newdata:
customer.phonenumber = newdata['phonenumber']
if 'address' in newdata:
customer.address = newdata['address']
# 注意,一定要执行save才能将修改信息保存到数据库
customer.save()
return JsonResponse({'ret': 0})
删除客户信息:
根据接口文档,删除客户数据接口,前端只需要提供要删除的客户的ID。
数据格式如下:
{
"action":"del_customer",
"id": 6
}
使用以下的函数来实现:
# 删除客户信息
def deletecustomer(request):
customerid = request.params['id']
try:
# 根据 id 从数据库中找到相应的客户记录
customer = Customer.objects.get(id=customerid)
except Customer.DoesNotExist:
return {
'ret': 1,
'msg': f'id 为`{customerid}`的客户不存在'
}
# delete 方法就将该记录从数据库中删除了
customer.delete()
return JsonResponse({'ret': 0})