diff --git a/bluewhale/core/serializers.py b/bluewhale/core/serializers.py index e393c47..cb8959c 100644 --- a/bluewhale/core/serializers.py +++ b/bluewhale/core/serializers.py @@ -21,4 +21,14 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = get_user_model() - fields = ('id', 'email', 'phone', 'nickname', 'date_joined', 'last_login', 'last_login_ip', 'description', 'groups') + fields = ( + 'id', + 'email', + 'phone', + 'nickname', + 'date_joined', + 'last_login', + 'last_login_ip', + 'description', + 'groups', + ) diff --git a/images/task04-api-error.png b/images/task04-api-error.png new file mode 100644 index 0000000..cf22224 Binary files /dev/null and b/images/task04-api-error.png differ diff --git a/images/task04-db-after-migration.png b/images/task04-db-after-migration.png new file mode 100644 index 0000000..969cb27 Binary files /dev/null and b/images/task04-db-after-migration.png differ diff --git a/images/task04-django-reload.png b/images/task04-django-reload.png new file mode 100644 index 0000000..bdd8630 Binary files /dev/null and b/images/task04-django-reload.png differ diff --git a/images/task04-migrate.png b/images/task04-migrate.png new file mode 100644 index 0000000..f340676 Binary files /dev/null and b/images/task04-migrate.png differ diff --git a/images/task04-migration-script.png b/images/task04-migration-script.png new file mode 100644 index 0000000..efba1e1 Binary files /dev/null and b/images/task04-migration-script.png differ diff --git a/task04.md b/task04.md new file mode 100644 index 0000000..f8d4636 --- /dev/null +++ b/task04.md @@ -0,0 +1,169 @@ +# 前言 + +本节课程,你将依照在[task02](./task02.md)中编写的用户管理接口规范,实现用户管理相关后端接口及前端界面。 + +# 后端接口相关 + +该章节你将学习实现接口所涉及的代码。 + +## Model & Migrate + +在[task01](./task01.md)课程中,你已熟悉`User`这个Model类。按照需求,需要扩展用户相关属性。 + +如期望增加学校字段`school`,可以在`User`该类中添加相关属性(文件路径`bluewhale/core/models.py`): + +```python + # 已定义属性 + school = models.CharField(_('school'), max_length=64, blank=True) + + objects = UserManager() +``` + +保存文件后,你将能看到命令行中展示如下信息: + +![django reload](./images/task04-django-reload.png) + +该信息表明Django识别到文件发生变动,并重新加载了变动。这时再次访问接口 +[http://127.0.0.1:8000/api/v1/me](http://127.0.0.1:8000/api/v1/me)将会看到如下错误信息: + +![api error](./images/task04-api-error.png) + +这是因为我们新增了字段,但是还没有处理数据。通过`Ctrl+C`停掉后端接口进程,然后执行下面命令可以处理数据库相关事项: + +* `python manage.py makemigrations` - 生成migration脚本 +* `python manage.py migrate` - 执行migration脚本 + +执行结果如下: + +![migrate](./images/task04-migrate.png) + +生成的migration脚本可以在app目录下面的migrations文件夹中找到,如下: + +![db after migration](./images/task04-db-after-migration.png) + +至此数据库相关的修改已完成。 + +## Serializer + +通过`python manage.py runserver`重新启动服务后,再次访问 +[http://127.0.0.1:8000/api/v1/me](http://127.0.0.1:8000/api/v1/me),会发现结果中 +并没有`school`属性: + +```json +{ + "data": { + "id": 1, + "email": "admin@example.com", + "phone": "", + "nickname": "", + "date_joined": "2021-01-25T03:28:09.214616Z", + "last_login": "2021-04-27T06:22:06.690042Z", + "last_login_ip": "127.0.0.1", + "description": "", + "groups": [] + }, + "code": 0 +} +``` + +原因是我们还需处理序列化相关的代码,增加这部分的序列化配置。文件路径为`bluewhale/core/serializers.py`, +类为`UserSerializer`。通过定义该类中`Meta`类的`fields`属性,我们可以添加我们需要序列化的字段。 + +添加`school`项,并刷新页面[http://127.0.0.1:8000/api/v1/me](http://127.0.0.1:8000/api/v1/me), +观察返回的结果数据。 + +至此序列化相关的修改已完成。 + +## APIView & URL + +要新增用户管理相关后端接口实现,我们需要创建`APIView`并在`urls.py`中添加URL路由至APIView的映射。 + +`APIView`是一种特殊的类,Django将REST接口相关的增删改查的操作(HTTP Method)映射为`APIView`类中对应的方法: +* 查询列表或单个数据项 - `get -> retrieve` +* 新增 - `post -> create` +* 修改 - `put -> update` & `patch -> partial_update` +* 删除 - `delete -> destroy` + +如果需要对特定的接口做特殊的处理,可以通过`Override`实际处理函数进行处理,具体示例可以参考`bluewhale/blog/views.py` +中的处理(该示例中使用非自增的id作为主键,而是使用生成uuid的方式作为主键): + +```python +class ArticleListCreateView(BasicListCreateAPIView): + permission_classes = [IsAuthenticated|ReadOnly] + serializer_class = ArticleSerializer + queryset = Article.objects.all() + + def create(self, request, *args, **kwargs): + data = request.data + data['id'] = shortuuid.uuid() + serializer = self.get_serializer(data=data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response( + { + 'data': serializer.data, + 'code': 0, + }, + status=status.HTTP_201_CREATED, headers=headers + ) + + def perform_create(self, serializer): + serializer.save(author=self.request.user) + + +class ArticleDetailView(BasicRetrieveUpdateDestroyAPIView): + permission_classes = [IsAuthenticated|ReadOnly] + serializer_class = ArticleSerializer + queryset = Article.objects.all() +``` + +最后在`bluewhale/bluewhale/urls.py`中,对所要的接口路径进行URL与APIView的映射,如: + +```python + path(f'{api_prefix}/articles', ArticleListCreateView.as_view(), name='articles'), + path(f'{api_prefix}/articles/', ArticleDetailView.as_view(), name='article'), +``` + +至此接口及View处理完毕。 + +# 服务端部署 + +在本次课程中,我们需要将我们编写的代码上传至服务端并运行(服务器用户及密码等信息由助教提供)。 + +## 同步后端代码 + +在clone的项目根目录,运行如下命令: + +```shell +export USER=team00 # 替换成助教提供的用户名 +export HOST=127.0.0.1 # 替换成助教提供的服务器地址 +rsync -avzh --delete --exclude=*.pyc --exclude=.venv --exclude=.idea --exclude=.env \ + --exclude=.git --exclude=__pycache__ \ + bluewhale $USER@$HOST: +``` + +该命令将后端代码目录同步至远程服务器中。登录到远程服务器,在用户主目录下将看到`bluewhale`文件夹, +其中为后端代码。参考课程[task00](./task00.md)中环境搭建-后端服务的部分,初始化后端项目db及用户。 + +最终运行时,指定监听的端口(**端口号由助教提供**): + +```shell + python manage.py runserver 127.0.0.1:8800 +``` + +## 同步前端代码 + +在clone的项目子目录`client`,编译前端文件,然后同步至服务端: + +```shell +npm run build # 编译前端代码 + +export USER=team00 # 替换成助教提供的用户名 +export HOST=127.0.0.1 # 替换成助教提供的服务器地址 +rsync -avzh dist $USER@$HOST:/usr/share/caddy/$USER +``` + +该命令将编译后的前端代码目录`dist`同步至远程服务器中。 + +部署完成后,打开浏览器输入服务器地址,你将能看到实现的界面。 diff --git a/task05.md b/task05.md new file mode 100644 index 0000000..5a693a0 --- /dev/null +++ b/task05.md @@ -0,0 +1,3 @@ +# 前言 + +本节课程,你将依照在[task02](./task02.md)中编写的赛事管理接口规范,实现赛事管理相关后端接口及前端界面。