#### 本文从分析现在流行的前后端分离Web应用模式说起,然后介绍如何设计REST API,通过使用Django来实现一个REST API为例,明确后端开发REST API要做的最核心工作,然后介绍Django REST framework能帮助我们简化开发REST API的工作。 # 完整版笔记直接地址: [请移步这里](https:///yinuo112/backend/blob/master/django/django-DRF知识点大集合共5大模块/django-DRF知识点大集合共5大模块.md) --- ## 共 5 章,24 子模块,总计1.7w+ 字 ![](https://it-res-md-1300471212.cos.ap-beijing./blog_md/images/django-DRF知识点大集合共5大模块/0.jpg) ![](https://it-res-md-1300471212.cos.ap-beijing./blog_md/images/django-DRF知识点大集合共5大模块/2.jpg) --- # 引入Django REST framework 在本章中,我们要大家介绍为什么学习Django REST framework,它能帮助我们做哪些事情。 **课 程思路**: 我们从分析现在流行的前后端分离Web应用模式说起,然后介绍如何设计REST API,通过使用Django来实现一个REST API为例,明确后端开发REST API要做的最核心工作,然后介绍Django REST framework能帮助我们简化开发REST API的工作。 # 使用Django开发REST 接口 我们以在Django框架中使用的图书英雄案例来写一套支持图书数据增删改查的REST API接口,来理解REST API的开发。 在此案例中,前后端均发送JSON格式数据。 # views.py from datetime import datetime class BookListView(View): """ 查询所有图书、增加图书 """ def get(self, request): """ 查询所有图书 路由:GET /books/ """ 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, 'image': book.image.url if book.image else '' }) return JsonResponse(book_list, safe=False) def post(self, request): """ 新增图书 路由:POST /books/ """ json_bytes = request.body json_str = json_bytes.decode() book_dict = json.loads(json_str) # 此处详细的校验参数省 book = BookInfo.objects.create( btitle=book_dict.get('btitle'), bpub_date=book_dict.get('bpub_date') ) return JsonResponse({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }, status=201) ```python class BookDetailView(View): def get(self, request, pk): """ 单个图书信息 路由: GET /books/<pk>/ """ try: book = BookInfo.objects.get(pk=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, 'image': book.image.url if book.image else '' }) def put(self, request, pk): """ 修改图书信息 路由: PUT /books/<pk> """ try: book = BookInfo.objects.get(pk=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.bpub_date = book_dict.get('bpub_date') book.save() return JsonResponse({ 'id': book.id, 'btitle': book.btitle, 'bpub_date': book.bpub_date, 'bread': book.bread, 'bcomment': book.bcomment, 'image': book.image.url if book.image else '' }) def delete(self, request, pk): """ 删除图书 路由: DELETE /books/<pk>/ """ try: book = BookInfo.objects.get(pk=pk) except BookInfo.DoesNotExist: return HttpResponse(status=404) book.delete() return HttpResponse(status=204) # urls.py urlpatterns = [ url(r'^books/$', views.BookListView.as_view()), url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()) ] #### 测试 使用Postman测试上述接口 1) 所有图书数据 GET 方式访问 > 127.0.0.1:8000/books/ 返回状态码200,数据如下 ```json [ { "id": 1, "btitle": "射雕英雄传", "bpub_date": "1980-05-01", "bread": 12, "bcomment": 34, "image": "" }, { "id": 2, "btitle": "天龙八部", "bpub_date": "1986-07-24", "bread": 36, "bcomment": 40, "image": "" }, { "id": 3, "btitle": "笑傲江湖", "bpub_date": "1995-12-24", "bread": 20, "bcomment": 80, "image": "" }, { "id": 4, "btitle": "雪山飞狐", "bpub_date": "1987-11-11", "bread": 58, "bcomment": 24, "image": "" }, { "id": 5, "btitle": "西游记", "bpub_date": "1988-01-01", "bread": 10, "bcomment": 10, "image": "booktest/xiyouji.png" }, { "id": 6, "btitle": "水浒传", "bpub_date": "1992-01-01", "bread": 10, "bcomment": 11, "image": "" }, { "id": 7, "btitle": "红楼梦", "bpub_date": "1990-01-01", "bread": 0, "bcomment": 0, "image": "" } ] ``` 2)单一图书数据 GET 访问 127.0.0.1:8000/books/5/,返回状态码200, 数据如下 ```json { "id": 5, "btitle": "西游记", "bpub_date": "1988-01-01", "bread": 10, "bcomment": 10, "image": "booktest/xiyouji.png" } ``` GET 访问 127.0.0.1:8000/books/100/,返回状态码404 3)新增图书数据 POST 访问 127.0.0.1:8000/books/,发送JSON数据 { "btitle": "三国演义", "bpub_date": "1990-02-03" } 返回状态码201,数据如下 { "id": 8, "btitle": "三国演义", "bpub_date": "1990-02-03", "bread": 0, "bcomment": 0, "image": "" } 4)修改图书数据 PUT 访问 127.0.0.1:8000/books/8/,发送JSON数据 { "btitle": "三国演义(第二版)", "bpub_date": "1990-02-03" } 返回状态码200,数据如下 { "id": 8, "btitle": "三国演义(第二版)", "bpub_date": "1990-02-03", "bread": 0, "bcomment": 0, "image": "" } 5)删除图书数据 DELETE 访问 127.0.0.1:8000/books/8/,返回204状态码 # 明确REST接口开发的核心任务 分析一下上节的案例,可以发现,在开发REST API接口时,视图中做的最主要有三件事: * 将请求的数据(如JSON格式)转换为模型类对象 * 操作数据库 * 将模型类对象转换为响应的数据(如JSON格式) ## 序列化Serialization 维基百科中对于序列化的定义: **序 列化**(serialization)在计算机科学的资料处理中,是指将数据结构或物件状态转换成可取用格式(例如存成档案,存于缓冲,或经由网络中传送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新字节的结果时,可以利用它来产生与原始物件相同语义的副本。对于许多物件,像是使用大量参照的复杂物件,这种序列化重建的过程并不容易。面向对象中的物件序列化,并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组, deserialization, unmarshalling)。 **序 列化**在计算机科学中通常有以下定义: 在数据储存与传送的部分是指将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等,或者透过网络传送资料时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象。这程序被应用在不同应用程序之间传送对象,以及服务器将对象储存到档案或数据库。相反的过程又称为**反序列化**。 简而言之,我们可以将 **序 列化**理解为:**将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等),例如将Django中的模型类对象装换为JSON字符串,这个转换过程我们称为序列化。** 如: 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, 'image': book.image.url if book.image else '' }) return JsonResponse(book_list, safe=False) **反 之,将其他格式(字典、JSON、XML等)转换为程序中的数据,例如将JSON字符串转换为Django中的模型类对象,这个过程我们称为反序列化。** 如: json_bytes = request.body json_str = json_bytes.decode() # 反序列化 book_dict = json.loads(json_str) book = BookInfo.objects.create( btitle=book_dict.get('btitle'), bpub_date=book_dict.get('bpub_date') ) 我们可以看到, **在 开发REST API时,视图中要频繁的进行序列化与反序列化的编写。** ## 总结 在开发REST API接口时,我们在 **视 图**中需要做的最核心的事是: * **将 数据库数据序列化为前端所需要的格式,并返回;** * **将 前端发送的数据反序列化为模型类对象,并保存到数据库中。** ## 未完待续 下一期 下一篇 # 完整笔记请看文章开头 |
|