-
+
-
+ {{ subject.name }}
+
+
+ - {{ subject.intro }} +
diff --git "a/Day41-55/42.\346\267\261\345\205\245\346\250\241\345\236\213.md" "b/Day41-55/42.\346\267\261\345\205\245\346\250\241\345\236\213.md"
index 3f290769395a1458170c116207232b0606e49d33..0d2a7c7859087f0a3730dc2d9742ed69598184e2 100644
--- "a/Day41-55/42.\346\267\261\345\205\245\346\250\241\345\236\213.md"
+++ "b/Day41-55/42.\346\267\261\345\205\245\346\250\241\345\236\213.md"
@@ -334,12 +334,12 @@ Teacher.objects.filter(subject__name__contains='全栈')
```Python
from django.contrib import admin
+
+ from polls.models import Subject, Teacher
-from polls.models import Subject, Teacher
-
class SubjectModelAdmin(admin.ModelAdmin):
- list_display = ('no', 'name', 'intro', 'is_hot')
+ list_display = ('no', 'name', 'intro', 'is_hot')
search_fields = ('name', )
ordering = ('no', )
@@ -388,7 +388,7 @@ from polls.models import Subject, Teacher
})
except (ValueError, Subject.DoesNotExist):
return redirect('/')
- ```
+ ```
2. 修改`templates/subjects.html`和`templates/teachers.html`模板页。
@@ -566,7 +566,7 @@ from polls.models import Subject, Teacher
13. 定义`__str__`方法。
14. 不要将数据文件放在同一个目录中。
-> 说明:以上内容来自于STEELKIWI网站的[*Best Practice working with Django models in Python*](https://steelkiwi.com/blog/best-practices-working-django-models-python/),有兴趣的小伙伴可以阅读原文。
+> **说明**:以上内容来自于STEELKIWI网站的[*Best Practice working with Django models in Python*](https://steelkiwi.com/blog/best-practices-working-django-models-python/),有兴趣的小伙伴可以阅读原文。
#### 模型定义参考
diff --git "a/Day41-55/48.\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\274\200\345\217\221\345\205\245\351\227\250.md" "b/Day41-55/48.\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\274\200\345\217\221\345\205\245\351\227\250.md"
index ab3798c209201c2131637dd1f7ed34a300fc8797..974a9cc4743eed84f041a79cfa8dd5d5fb0610a4 100644
--- "a/Day41-55/48.\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\274\200\345\217\221\345\205\245\351\227\250.md"
+++ "b/Day41-55/48.\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\274\200\345\217\221\345\205\245\351\227\250.md"
@@ -1,6 +1,6 @@
## 前后端分离开发入门
-在传统的Web应用开发中,大多数的程序员会将浏览器作为前后端的分界线。将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端。所谓前后端分离的开发,就是前后端工程师约定好数据交互接口,并行的进行开发和测试,后端只提供数据,不负责将数据渲染到页面上,前端通过HTTP请求获取数据并负责将数据渲染到页面上,这个工作是交给浏览器中的JavaScript代码来完成。
+在传统的Web应用开发中,大多数的程序员会将浏览器作为前后端的分界线。将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器为前端提供业务逻辑和数据准备的所有代码统称为后端。所谓前后端分离的开发,就是前后端工程师约定好数据交互接口,并行的进行开发和测试,后端只提供数据,不负责将数据渲染到页面上,前端通过HTTP请求获取数据并负责将数据渲染到页面上,这个工作是交给浏览器中的JavaScript代码来完成。
使用前后端分离开发有诸多的好处,下面我们简要的说下这些好处:
@@ -30,9 +30,9 @@ def show_subjects(request):
上面的代码中,我们通过循环遍历查询学科得到的`QuerySet`对象,将每个学科的数据处理成一个字典,在将字典保存在名为`subjects`的列表容器中,最后利用`JsonResponse`完成对列表的序列化,向浏览器返回JSON格式的数据。由于`JsonResponse`序列化的是一个列表而不是字典,所以需要指定`safe`参数的值为`False`才能完成对`subjects`的序列化,否则会产生`TypeError`异常。
-可能大家已经发现了,自己写代码将一个对象转成字典是比较麻烦的,如果对象的属性很多而且某些属性又关联到一个比较复杂的对象时,情况会变得更加糟糕。为此我们可以使用一个名为bpmappers的三方库来简化将对象转成字典的操作,这个三方库本身也提供了对Django框架的支持。
+可能大家已经发现了,自己写代码将一个对象转成字典是比较麻烦的,如果对象的属性很多而且某些属性又关联到一个比较复杂的对象时,情况会变得更加糟糕。为此我们可以使用一个名为`bpmappers`的三方库来简化将对象转成字典的操作,这个三方库本身也提供了对Django框架的支持。
-安装三方库bpmappers。
+安装三方库`bpmappers`。
```Shell
pip install bpmappers
@@ -63,15 +63,24 @@ def show_subjects(request):
return JsonResponse(subjects, safe=False)
```
-配置URL映射,然后访问该接口,可以得到如下所示的JSON格式数据。
+配置URL映射。
+
+```Python
+urlpatterns = [
+
+ path('api/subjects/', show_subjects),
+
+]
+```
+
+然后访问该接口,可以得到如下所示的JSON格式数据。
```JSON
[
{
- "no": 101,
+ "no": 1,
"name": "Python全栈+人工智能",
"intro": "Python是一种计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。",
- "create_date": "2017-08-01",
"is_hot": true
},
// 此处省略下面的内容
@@ -92,7 +101,7 @@ class SubjectMapper(ModelMapper):
class Meta:
model = Subject
- exclude = ('create_date', 'is_hot')
+ exclude = ('is_hot', )
```
再次查看学科接口返回的JSON数据。
@@ -109,11 +118,11 @@ class SubjectMapper(ModelMapper):
]
```
-关于bpmappers详细的使用指南,请参考它的[官方文档](
{{ subject.intro }}
+ - + @@ -161,4 +186,4 @@ class SubjectMapper(ModelMapper): 前后端分离的开发需要将前端页面作为静态资源进行部署,项目实际上线的时候,我们会对整个Web应用进行动静分离,静态资源通过Nginx或Apache服务器进行部署,生成动态内容的Python程序部署在uWSGI或者Gunicorn服务器上,对动态内容的请求由Nginx或Apache路由到uWSGI或Gunicorn服务器上。 -在开发阶段,我们通常会使用Django自带的测试服务器,如果要尝试前后端分离,可以先将静态页面放在之前创建的放静态资源的目录下,具体的做法可以参考[项目完整代码]()。 \ No newline at end of file +在开发阶段,我们通常会使用Django自带的测试服务器,如果要尝试前后端分离,可以先将静态页面放在之前创建的放静态资源的目录下,具体的做法可以参考[项目完整代码](https://gitee.com/jackfrued/django19062)。 \ No newline at end of file diff --git "a/Day41-55/49.RESTful\346\236\266\346\236\204\345\222\214DRF\345\205\245\351\227\250.md" "b/Day41-55/49.RESTful\346\236\266\346\236\204\345\222\214DRF\345\205\245\351\227\250.md" index 1af876ffe2ed9034a56db5db7eb414e267bfa6f3..0004429fc02e5b41fc518dcec83fd13bb58bdf70 100644 --- "a/Day41-55/49.RESTful\346\236\266\346\236\204\345\222\214DRF\345\205\245\351\227\250.md" +++ "b/Day41-55/49.RESTful\346\236\266\346\236\204\345\222\214DRF\345\205\245\351\227\250.md" @@ -1,4 +1,387 @@ ## RESTful架构和DRF入门 +把软件(Software)、平台(Platform)、基础设施(Infrastructure)做成服务(Service)是很多IT企业都一直在做的事情,这就是大家经常听到的SasS(软件即服务)、PasS(平台即服务)和IasS(基础设置即服务)。实现面向服务的架构(SOA)有诸多的方式,包括RPC(远程过程调用)、Web Service、REST等,在技术层面上,SOA是一种**抽象的、松散耦合的粗粒度软件架构**;在业务层面上,SOA的核心概念是“**重用**”和“**互操作**”,它将系统资源整合成可操作的、标准的服务,使得这些资源能够被重新组合和应用。在实现SOA的诸多方案中,REST被认为是最适合互联网应用的架构,符合REST规范的架构也经常被称作RESTful架构。 +### REST概述 + +REST这个词,是**Roy Thomas Fielding**在他2000年的博士论文中提出的,Roy是HTTP协议(1.0和1.1版)的主要设计者、Apache服务器软件主要作者、Apache基金会第一任主席。在他的博士论文中,Roy把他对互联网软件的架构原则定名为REST,即**RE**presentational **S**tate **T**ransfer的缩写,中文通常翻译为“**表现层状态转移**”或“**表述状态转移**”。 + +这里的“表现层”其实指的是“资源”的“表现层”。所谓资源,就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲或一种服务。我们可以用一个URI(统一资源定位符)指向资源,要获取到这个资源,访问它的URI即可,URI就是资源在互联网上的唯一标识。资源可以有多种外在表现形式。我们把资源具体呈现出来的形式,叫做它的“表现层”。比如,文本可以用`text/plain`格式表现,也可以用`text/html`格式、`text/xml`格式、`application/json`格式表现,甚至可以采用二进制格式;图片可以用`image/jpeg`格式表现,也可以用`image/png`格式表现。URI只代表资源的实体,不代表它的表现形式。严格地说,有些网址最后的`.html`后缀名是不必要的,因为这个后缀名表示格式,属于“表现层”范畴,而URI应该只代表“资源”的位置,它的具体表现形式,应该在HTTP请求的头信息中用`Accept`和`Content-Type`字段指定,这两个字段才是对“表现层”的描述。 + +访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。Web应用通常使用HTTP作为其通信协议,客户端想要操作服务器,必须通过HTTP请求,让服务器端发生“状态转移”,而这种转移是建立在表现层之上的,所以就是“表现层状态转移”。客户端通过HTTP的动词GET、POST、PUT(或PATCH)、DELETE,分别对应对资源的四种基本操作,其中GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT(或PATCH)用来更新资源,DELETE用来删除资源。 + +简单的说RESTful架构就是:“每一个URI代表一种资源,客户端通过四个HTTP动词,对服务器端资源进行操作,实现资源的表现层状态转移”。 + +我们在设计Web应用时,如果需要向客户端提供资源,就可以使用REST风格的URI,这是实现RESTful架构的第一步。当然,真正的RESTful架构并不只是URI符合REST风格,更为重要的是“无状态”和“幂等性”两个词,我们在后面的课程中会为大家阐述这两点。下面的例子给出了一些符合REST风格的URI,供大家在设计URI时参考。 + +| 请求方法(HTTP动词) | URI | 解释 | +| -------------------- | -------------------------- | -------------------------------------------- | +| **GET** | `/students/` | 获取所有学生 | +| **POST** | `/students/` | 新建一个学生 | +| **GET** | `/students/ID/` | 获取指定ID的学生信息 | +| **PUT** | `/students/ID/` | 更新指定ID的学生信息(提供该学生的全部信息) | +| **PATCH** | `/students/ID/` | 更新指定ID的学生信息(提供该学生的部分信息) | +| **DELETE** | `/students/ID/` | 删除指定ID的学生信息 | +| **GET** | `/students/ID/friends/` | 列出指定ID的学生的所有朋友 | +| **DELETE** | `/students/ID/friends/ID/` | 删除指定ID的学生的指定ID的朋友 | + +### DRF使用入门 + +在Django项目中,如果要实现REST架构,即将网站的资源发布成REST风格的API接口,可以使用著名的三方库`djangorestframework` ,我们通常将其简称为DRF。 + +#### 安装和配置DRF + +安装DRF。 + +```Shell +pip install djangorestframework +``` + +配置DRF。 + +```Python +INSTALLED_APPS = [ + + 'rest_framework', + +] + +# 下面的配置根据项目需要进行设置 +REST_FRAMEWORK = { + # 配置默认页面大小 + # 'PAGE_SIZE': 10, + # 配置默认的分页类 + # 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + # 配置异常处理器 + # 'EXCEPTION_HANDLER': '...', + # 配置默认解析器 + # 'DEFAULT_PARSER_CLASSES': ( + # 'rest_framework.parsers.JSONParser', + # 'rest_framework.parsers.FormParser', + # 'rest_framework.parsers.MultiPartParser', + # ), + # 配置默认限流类 + # 'DEFAULT_THROTTLE_CLASSES': ( + # '...' + # ), + # 配置默认授权类 + # 'DEFAULT_PERMISSION_CLASSES': ( + # '...', + # ), + # 配置默认认证类 + # 'DEFAULT_AUTHENTICATION_CLASSES': ( + # '...', + # ), +} +``` + +#### 编写序列化器 + +前后端分离的开发需要后端为前端、移动端提供API数据接口,而API接口通常情况下都是返回JSON格式的数据,这就需要对模型对象进行序列化处理。DRF中封装了`Serializer`类和`ModelSerializer`类用于实现序列化操作,通过继承`Serializer`类或`ModelSerializer`类,我们可以自定义序列化器,用于将对象处理成字典,代码如下所示。 + +```Python +class SubjectSerializer(serializers.ModelSerializer): + + class Meta: + model = Subject + fields = '__all__' +``` + +上面的代码直接继承了`ModelSerializer`,通过`Meta`类的`model`属性指定要序列化的模型以及`fields`属性指定需要序列化的模型字段,稍后我们就可以在视图函数中使用该类来实现对`Subject`模型的序列化。 + +#### 编写视图函数 + +DRF框架支持两种实现数据接口的方式,一种是FBV(基于函数的视图),另一种是CBV(基于类的视图)。我们先看看FBV的方式如何实现数据接口,代码如下所示。 + +```Python +@api_view(('GET', )) +def show_subjects(request: HttpRequest) -> HttpResponse: + subjects = Subject.objects.all().order_by('no') + # 创建序列化器对象并指定要序列化的模型 + serializer = SubjectSerializer(subjects, many=True) + # 通过序列化器的data属性获得模型对应的字典并通过创建Response对象返回JSON格式的数据 + return Response(serializer.data) +``` + +对比上一个章节的使用`bpmapper`实现模型序列化的代码,使用DRF的代码更加简单明了,而且DRF本身自带了一套页面,可以方便我们查看我们使用DRF定制的数据接口,如下图所示。 + +![](res/drf-app.png) + +直接使用上一节写好的页面,就可以通过Vue.js把上面接口提供的学科数据渲染并展示出来,此处不再进行赘述。 + +#### 实现老师信息数据接口 + +编写序列化器。 + +```Python +class SubjectSimpleSerializer(serializers.ModelSerializer): + + class Meta: + model = Subject + fields = ('no', 'name') + + +class TeacherSerializer(serializers.ModelSerializer): + + class Meta: + model = Teacher + exclude = ('subject', ) +``` + +编写视图函数。 + +```Python +@api_view(('GET', )) +def show_teachers(request: HttpRequest) -> HttpResponse: + try: + sno = int(request.GET.get('sno')) + subject = Subject.objects.only('name').get(no=sno) + teachers = Teacher.objects.filter(subject=subject).defer('subject').order_by('no') + subject_seri = SubjectSimpleSerializer(subject) + teacher_seri = TeacherSerializer(teachers, many=True) + return Response({'subject': subject_seri.data, 'teachers': teacher_seri.data}) + except (TypeError, ValueError, Subject.DoesNotExist): + return Response(status=404) +``` + +配置URL映射。 + +```Python +urlpatterns = [ + + path('api/teachers/', show_teachers), + +] +``` + +通过Vue.js渲染页面。 + +```Python + + + + +