Bootstrap

Django:DjangoRestFramework drf 开发1

Django REST framework 简介

在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的。

在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复用简化编写的:

  • :校验请求数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回

  • :判断要删除的数据是否存在 -> 执行数据库删除

  • :判断要修改的数据是否存在 -> 校验请求的数据 -> 执行反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回

  • :查询数据库 -> 将数据序列化并返回

Django REST framework可以帮助我们简化上述两部分的代码编写,大大提高REST API的开发速度。

Django REST framework 框架是一个用于构建Web API 的强大而又灵活的工具。

通常简称为DRF框架 或 REST framework。

DRF框架是建立在Django框架基础之上,由Tom Christie大牛二次开发的开源项目。

特点

  • 提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;

  • 提供了丰富的类视图、Mixin扩展类,简化视图的编写;

  • 丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;

  • 多种身份认证和权限认证方式的支持;

  • 内置了限流系统;

  • 直观的 API web 界面;

  • 可扩展性,插件丰富。

1. Django RESTFul 协议

1. 服务器端代码

1. 定义类视图

class ***View(View):
	def get(self):
	def post(self):

2. 视图函数处理步骤

  • 接收、验证、处理、响应

3. 配置处理路由规则

4. get或post随便起,但会影响代码可读性和规范性

2. 规范

1. 规则:

  • 规定服务器端程序员需要按照哪些标准定义视图、路由规则

2. 作用:

  • 增强代码可读性,降低前后端程序员的沟通成本,提高效率

2. RESTFul协议设计方法

1. 域名

应该尽量将API部署在专用域名之下

https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。

https://example.org/api/

2. 版本(Versioning)

应该将API的版本号放入URL

http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo
http://www.example.com/app/2.0/foo

3. 路径(Endpoint) 路由规则

路由中的正则表达式必须是名词,建议使用复数,如/books/,/heros/

4. HTTP动词

请求方式数据库数据处理
GET查询
POST增加
PUT修改(PUT需要给所有值赋值,PATCH可以修改部分属性)
DELETE删除

以下请求方式用的相对较少:

请求方式数据库数据处理
PATCH在服务器更新(更新)资源(客户端提供改变的属性)
HEAD获取资源的元数据
OPTIONS获取信息,关于资源的哪些属性是客户端可以改变的

5. 以查询参数提供过滤条件、分页信息、排序规则

  • https://www.baidu.com/python/?a=3&b=5 -->问号后是查询参数

6. 状态码

状态码含义
200查询成功
201新建或修改成功
204删除成功
3xx重定向
4xx客户端请求有错误
5xx服务器有错

7. 返回值

处理方式响应值
查询{json}或[列表,内部有字典]
增加新建的对象{}
修改修改后的对象{}
删除

8. 所有数据以JSON格式返回

比如 错误信息

{
	error: 'Invalid API key'
}

3. 使用Django开发REST接口

以图书的查询、增加、修改、删除为例

处理请求路径请求方式响应值状态码
查询(所有)/books/GET[{},{},…]200
增加/books/POST新增的数据{}201
查询(指定主键)/books/(?P\d+)/GET{}200
修改/books/(?P\d+)/PUT修改后的对象{}201
删除/books/(?P\d+)/DELETE204

开发需要两个类视图,一个不包含pk,一个包含pk。

  • settings.py 注册子应用
'book.apps.BokConfig',
  • book/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
	url(r'^books/$', views.BooksView.as_view()),
	url(r'^books/(?P<pk>\d+)/', views.BookView.as_view()),
]
  • views.py 视图函数的结构
from django.views import View

class BooksView(View):
	def get(self, request):
		'''查询所有'''
		pass
	def post(self, request)'''新增'''
		pass

class BookView(View):
	def get(self, request, pk)
		'''根据主键查询一个图书对象'''
		pass
	def put(self, request, pk)
		'''修改指定主键的图书对象'''
		pass
	def delete(self, request, pk)
		'''删除指定主键的图书对象'''
		pass
  • views.py 具体实现:
from django.views import View
from .models import Books
from django.http import JsonResponse
import json

class BooksView(View):
    """ 图书类视图 """
    def get(self, request):
        """ 获取所有图书信息 """
        # 接收
        # 验证
        # 处理
        # 1. 查询所有图书对象
        book_obj = Books.objects.all()
        # 2. 将图书对象转成dict类型
        book_info = []
        for book in book_obj:
            book_info.append({
                'id': book.id,
                'book_name': book.book_name,
                'author': book.author,
                'type': book.type,
                'published_date': book.published_date,
                'date_joined': book.date_joined
            })
        # 响应
        return JsonResponse(book_info, safe=False)  # 状态码默认是200,此处无需返回状态码

    def post(self, request):
        """ 新增图书 """
        # 接收
        params = json.loads(request.body.decode())
        book_name = params.get('book_name')
        author = params.get('author')
        type = params.get('type')
        published_date = params.get('published_date')
        date_joined = params.get('date_joined')
        # 验证
        book_obj = Books.objects.filter(book_name=book_name).first()
        if book_obj:
            return JsonResponse({'error': 'this book is exist!'})
        # 处理
        # 1. 创建图书
        book = Books.objects.create(book_name=book_name, author=author, type=type, published_date=published_date,date_joined=date_joined)
        # 2. 将新创建的图书对象转成dict
        book_dict = {
            'id': book.id,
            'book_name': book.book_name,
            'author': book.author,
            'type': book.type,
            'published_date': book.published_date,
            'date_joined': book.date_joined
        }
        # 响应
        return JsonResponse(book_dict, status=201)  # 新增成功返回状态码 201

class BookView(View):
    """ 图书类视图(含pk) """

    def get(self, request, pk):
        """ 获取一个图书信息 """
        try:
            book = Books.objects.get(pk=pk)
        except:
            return JsonResponse({"error": "数据不存在"})
        book_dict = {
            'id': book.id,
            'book_name': book.book_name,
            'author': book.author,
            'type': book.type,
            'published_date': book.published_date,
            'date_joined': book.date_joined
        }
        return JsonResponse(book_dict)

    def put(self, request, pk):
        """ 修改一个图书信息 """
        # 接收
        params = json.loads(request.body.decode())
        book_name = params.get('book_name')
        author = params.get('author')
        type = params.get('type')
        published_date = params.get('published_date')
        date_joined = params.get('date_joined')
        # 验证
        try:
            book = Books.objects.get(pk=pk)
        except:
            return JsonResponse({"error": "数据不存在"})
        # 更新数据
        # 这个方法不行,报【AttributeError: 'Heros' object has no attribute 'update'】错。暂时还不知道为啥,就用了未注释的这种
        # book.update(book_name=book_name, author=author, type=type, published_date=published_date,date_joined=date_joined)
        book.book_name = book_name
        book.author = author
        book.type = type
        book.published_date = published_date
        book.date_joined = date_joined
        book.save()
        # 将对象转换成字典
        book_dict = {
            'id': book.id,
            'book_name': book.book_name,
            'author': book.author,
            'type': book.type,
            'published_date': book.published_date,
            'date_joined': book.date_joined
        }
        # 响应
        return JsonResponse(book_dict, status=201)  # 修改成功返回状态码 201
        # 处理

    def delete(self, request, pk):
        """ 删除一个图书 """
        # 接收、验证、处理
        try:
            Books.objects.get(pk=pk).delete()
        except:
            return JsonResponse({"error": "数据不存在"})
        # 响应
        return JsonResponse(data={}, status=204)  # data= 可写可不写
        
     # 以下是patch方法修改模型类的部分信息,用的不多
     def patch(self, request, pk):
      """ 使用patch,根据主键pk修改图书部分信息 """
      # 接收数据
      params = json.loads(request.body.decode())
      # book_name = params.get('book_name')
      author = params.get('author')
      # type = params.get('type')
      # published_date = params.get('published_date')
      # date_joined = params.get('date_joined')
      # 验证
      try:
          book= Books.objects.get(pk=pk)
      except:
          return JsonResponse({"error": "该图书不存在"})
      # 修改
      # book.book_name = book_name
      book.author = author  # 只改图书的作者
      # book.type = type
      # book.published_date = published_date
      # book.date_joined = date_joined
      book.save()
      # 将数据对象转成字典
      book_dict = {
            'id': book.id,
            'book_name': book.book_name,
            'author': book.author,
            'type': book.type,
            'published_date': book.published_date,
            'date_joined': book.date_joined
      }
      return JsonResponse(hero_dict, status=201)

如有不足,请多指教!

;