一、RESTful
REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。一种软件设计风格
1、RESTful API设计
- 协议
- API与用户的通信协议,总是使用HTTPs协议。
- 域名
- 尽量将API部署在专用域名之下 https://api.example.com
- 也可以放在主域名之下 https://example.org/api
- 版本
- 将url版本号放入到url中 https://exmaple.com/v1/
- 路径
- 只能有名词,不能有动词 https://exmaple.com/v1/zoos
- method
- GET(SELECT) 获取资源(一项、多项)
- POST (CREATE) 创建
- PUT(UPDATE) 在更新资源
- DELETE(DELETE) 删除资源
- PATCH(UPDATE) 更新资源(提供改变的属性)
- HEAD 获取资源的元数据
- OPTIONS 获取信息,关于资源的哪些属性是客户端可以改变的
- 过滤
- ?limit=10:指定返回记录数量
- ?offset=10:偏移查询
- ?sortby=name:排序字段
- 状态
- 200 成功
- 201 创建成功
- 204 删除成功
- 401 没有权限
- 403 没有授权
- 404 没有找到
- 500 服务器内部错误
- 错误处理
- {
- error:"错误信息"
- }
- 返回结果
- json
2、RESTful API案例
功能
|
请求方式
|
请求路径
|
获取所有书籍
|
GET
|
/books
|
创建单本书籍
|
POST
|
/books
|
获取单本书籍
|
GET
|
/books/{pk}
|
修改单本书籍
|
PUT
|
/books/{pk}
|
删除单本书籍
|
DELETE
|
/books/{pk}
|
3、创建Django项目
1:使用MySQL数据库首先需要安装驱动程序
pip install PyMySQL
2:在Django的工程同名子目录的__init__.py文件中添加如下语句
from pymysql import install_as_MySQLdb install_as_MySQLdb()
3:配置setting中的DATABASES配置信息

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '39.99.213.203', # 数据库主机 'PORT': 3306, # 数据库端口 'USER': 'root', # 数据库用户名 'PASSWORD': 'mysql', # 数据库用户密码 'NAME': 'django_demo' # 数据库名字 } }
4:在MySQL中创建数据库
create database django_demo default charset=utf8;
5:创建应用booktest,在models.py 文件中定义模型类。

from django.db import models #定义图书模型类BookInfo class BookInfo(models.Model): btitle = models.CharField(max_length=20, verbose_name='名称') bpub_date = models.DateField(verbose_name='发布日期') bread = models.IntegerField(default=0, verbose_name='阅读量') bcomment = models.IntegerField(default=0, verbose_name='评论量') is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') class Meta: db_table = 'tb_books' # 指明数据库表名 verbose_name = '图书' # 在admin站点中显示的名称 verbose_name_plural = verbose_name # 显示的复数名称 def __str__(self): """定义每个数据对象的显示信息""" return self.btitle #定义英雄模型类HeroInfo class HeroInfo(models.Model): GENDER_CHOICES = ( (0, 'female'), (1, 'male') ) hname = models.CharField(max_length=20, verbose_name='名称') hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别') hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息') hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键 is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') class Meta: db_table = 'tb_heros' verbose_name = '英雄' verbose_name_plural = verbose_name def __str__(self): return self.hname
6:生成数据库
python manage.py makemigrations
python manage.py migrate
ps:如果报django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.错误
在Django的工程同名子目录的__init__.py文件中添加如下语句

from pymysql import install_as_MySQLdb import pymysql pymysql.version_info = (1, 3, 13, "final", 0) pymysql.install_as_MySQLdb()
7:初始化数据

insert into tb_books(btitle,bpub_date,bread,bcomment,is_delete) values ('射雕英雄传','1980-5-1',12,34,0), ('天龙八部','1986-7-24',36,40,0), ('笑傲江湖','1995-12-24',20,80,0), ('雪山飞狐','1987-11-11',58,24,0); insert into tb_heros(hname,hgender,hbook_id,hcomment,is_delete) values ('郭靖',1,1,'降龙十八掌',0), ('黄蓉',0,1,'打狗棍法',0), ('黄药师',1,1,'弹指神通',0), ('欧阳锋',1,1,'蛤蟆功',0), ('梅超风',0,1,'九阴白骨爪',0), ('乔峰',1,2,'降龙十八掌',0), ('段誉',1,2,'六脉神剑',0), ('虚竹',1,2,'天山六阳掌',0), ('王语嫣',0,2,'神仙姐姐',0), ('令狐冲',1,3,'独孤九剑',0), ('任盈盈',0,3,'弹琴',0), ('岳不群',1,3,'华山剑法',0), ('东方不败',0,3,'葵花宝典',0), ('胡斐',1,4,'胡家刀法',0), ('苗若兰',0,4,'黄衣',0), ('程灵素',0,4,'医术',0), ('袁紫衣',0,4,'六合拳',0);
二、功能实现
1、利用CBV模式实现
CBV(class base views) 就是在视图里使用类处理请求。
1.1 项目同名的App路由中进行全局配置

from django.contrib import admin from django.urls import path from django.conf.urls import url,include from APP01 import url as app01_books_url urlpatterns = [ url(r'^api/yango/v1/books/',include(app01_books_url)) ]

from django.conf.urls import url from . import views urlpatterns=[ url(r'^info$',views.BookesAPIView.as_view()), ]
资源明细内容
info 表示获取所有
1.2 获取所有书籍

from django.shortcuts import render from django.views import View from .models import BookInfo from datetime import datetime from django.http import JsonResponse ''' 功能 请求方式 请求路径 获取所有书籍 GET /books 创建单本书籍 POST /books 获取单本书籍 GET /books/{pk} 修改单本书籍 PUT /books/{pk} 删除单本书籍 DELETE /books/{pk} ''' #1,列表视图 class BookesAPIView(View): ''' 查询所有屠苏,增加图书 ''' def get(self,request): queryset=BookInfo.objects.all() book_list=[] for book in queryset: book_list.append({ "id":book.id, "btitle":book.btitle, "bpub_date":book.bpub_date, "bread":book.bread, "bcomment":book.bcomment }) return JsonResponse(book_list,safe=False)
BookesAPIView中get方法,获取所有书籍数据
1.3 完整版视图

from django.shortcuts import render, HttpResponse from django.views import View from .models import BookInfo from datetime import datetime from django.http import JsonResponse import json ''' 功能 请求方式 请求路径 获取所有书籍 GET /books 创建单本书籍 POST /books 获取单本书籍 GET /books/{pk} 修改单本书籍 PUT /books/{pk} 删除单本书籍 DELETE /books/{pk} ''' # 1,列表视图 class BooksAPIView(View): ''' 查询所有屠苏,增加图书 ''' def get(self, request): """ 查询所有图书 路由:GET /books/info/ """ queryset = BookInfo.objects.all() book_list = [] for book in queryset: book_list.append({ "id": book.id, "btitle": book.btitle, "bpub_date": book.bpub_date, "bread": book.bread, "bcomment": book.bcomment }) return JsonResponse(book_list, safe=False) def post(self, request): """ 新增图书 路由:POST /books/info/ """ json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str, encoding="utf-8") # 此处详细的校验参数省略 book = BookInfo.objects.create( btitle=book_dict.get('btitle'), bpub_date=datetime.strptime(book_dict.get('bpub_date'), '%Y-%m-%d').date() ) return JsonResponse({ "id": book.id, "btitle": book.btitle, "bpub_date": book.bpub_date, "bread": book.bread, "bcomment": book.bcomment }, status=201) class BookAPIView(View): ''' 查询所有屠苏,增加图书 ''' def get(self, request, pk): """ 根据图书ID查询图书 路由:GET /books/info/pk/ """ try: book = BookInfo.objects.get(id=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) return JsonResponse({ "id": book.id, "btitle": book.btitle, "bpub_date": book.bpub_date, "bread": book.bread, "bcomment": book.bcomment }, status=201) def put(self, request, pk): """ 根据图书ID修改图书 路由:PUT /books/info/pk/ """ try: book = BookInfo.objects.get(id=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str) book.btitle = book_dict.get("btitle") book.save() return JsonResponse({ "id": book.id, "btitle": book.btitle, "bpub_date": book.bpub_date, "bread": book.bread, "bcomment": book.bcomment }) def delete(self, request, pk): """ 根据图书ID删除图书 路由:DELETE /books/info/pk/ """ try: book = BookInfo.objects.get(id=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) book.delete() return JsonResponse({ "id": book.id, "btitle": book.btitle, "bpub_date": book.bpub_date, "bread": book.bread, "bcomment": book.bcomment }, status=204)
1.4 测试(Postman)
1)获取所有图书数据 http://127.0.0.1:8000/api/yango/v1/books/info

[ { "id": 1, "btitle": "射雕英雄传", "bpub_date": "1980-05-01", "bread": 12, "bcomment": 34 }, { "id": 2, "btitle": "天龙八部", "bpub_date": "1986-07-24", "bread": 36, "bcomment": 40 }, { "id": 3, "btitle": "笑傲江湖", "bpub_date": "1995-12-24", "bread": 20, "bcomment": 80 }, { "id": 4, "btitle": "雪山飞狐", "bpub_date": "1987-11-11", "bread": 58, "bcomment": 24 }, { "id": 5, "btitle": "白马啸西风", "bpub_date": "2020-02-02", "bread": 0, "bcomment": 0 }, { "id": 7, "btitle": "连城诀", "bpub_date": "2020-02-02", "bread": 0, "bcomment": 0 } ]
2)获取单一图书数据 http://127.0.0.1:8000/api/yango/v1/books/info/1

{ "id": 1, "btitle": "射雕英雄传", "bpub_date": "1980-05-01", "bread": 12, "bcomment": 34 }
3)新增图书数据 http://127.0.0.1:8000/api/yango/v1/books/info

{ "btitle":"连城诀", "bpub_date":"2020-02-02" }

{ "id": 7, "btitle": "连城诀", "bpub_date": "2020-02-02", "bread": 0, "bcomment": 0 }
4)修改图书数据 http://127.0.0.1:8000/api/yango/v1/books/info/6/

{ "btitle":"白马啸西风1" }

{ "id": 6, "btitle": "白马啸西风1", "bpub_date": "2020-02-02", "bread": 0, "bcomment": 0 }
5)删除图书数据 http://127.0.0.1:8000/api/yango/v1/books/info/6/

{ "id": null, "btitle": "白马啸西风1", "bpub_date": "2020-02-02", "bread": 0, "bcomment": 0 }
三、代码上传
可参考 集腋成裘-21-git使用-03进阶篇 2.4 多人开发