不要追求更好的方法来尽快完成任务,而要追求更好的任务,让你做得不想停下来。
在进行后端接口开发中, 一般遵循一下顺序:
- 需求整理和数据库设计
- 编写model和view代码(view是存放业务代码的地方).
- 配置路由.
- 测试.
1. 需求整理
- 前端通过分页的方式来获取单词本列表. 每个数据项应该包含基本信息和下载地址.
- 前端通过下载地址下载指定图书.
- 管理员通过管理后台上传单词本.
2. 数据层
新建api.models.book.py
文件, 构建单词本的实体类Book
:
from django.db import models
class Book(models.Model):
name = models.CharField('书名', max_length=100)
path = models.FileField('上传文件', upload_to='book/') # 上传到 settings.MEDIA_ROOT + upload_to 文件夹内
class Meta:
ordering = ('pk', ) # 排序方式按主键升序
这里建议大家打开django的文档认真阅读这些新字段的具体使用.
在api.models.book.py
创建model的序列化和反序列化处理类, 它有几个作用:
- 序列化model为json传递给前端.
- 验证前端的请求参数并反序列化前端的入参为python对象.
from rest_framework import serializers
class BookSerializer(serializers.ModelSerializer):
path = serializers.FileField(use_url=False) # use_url=False会将绝对路径URL转换为相对路径
class Meta:
model = Book # 关联指定的 model
fields = '__all__' # model 所有字段都需要处理
3. view 层
这里我们处理两个业务: 拉取单词本列表和处理下载单词本请求.
3.1 统一处理返回json格式
作者在做前端时, 被后端各种不规范的接口返回搞得头大, 现在让我们一起处理一下. 大部分语言的架构都是基于继承进行代码组织的, 在这里我们通过override基类的方法, 来统一后端的返回格式:
{
"message": xxx,
"code": xxx,
"data": xxx
}
新建api.views.base.py
文件, 拦截返回数据并组织成统一的格式:
from rest_framework.views import APIView
class BaseView(APIView):
def finalize_response(self, request, response, *args, **kwargs):
response.data = {
'code': 0,
'message': 'ok',
'data': response.data
}
return super(BaseView, self).finalize_response(request, response, *args, **kwargs)
这里假设所有response都是成功状态, 请大家思考如何处理异常状态, 可以加群和作者讨论.
3.1 单词本分页接口
新建api.views.book.py
文件, 处理拉取单词本的业务:
from rest_framework import viewsets, mixins
from .base import BaseView
from api.models.book import BookSerializer, Book
class BookViewSet(BaseView, mixins.ListModelMixin, viewsets.GenericViewSet): # 这里只需要处理分页
serializer_class = BookSerializer # 序列化和反序列化
queryset = Book.objects.all() # 类似数据库连接
authentication_classes = [] # 不需要用户认真
permission_classes = [] # 不需要鉴权
嘿, 就这么简单
4. 配置路由
前端的http请求到达后端程序时需要通过路由转发到对应的处理函数/类中, 那么这个路由规则需要我们来配置一下:
# api.urls.py
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from api.views.book import BookViewSet
app_name = 'api'
router = SimpleRouter()
router.register('book', BookViewSet, basename='book') # 自动处理路径+请求方法 -> 处理类/函数之间的映射关系
urlpatterns = [
path('', include(router.urls)),
]
# backend.urls.py
from django.urls import path, include
urlpatterns = [
path('api/v1/', include('api.urls')), # api/v1/book 的请求转发给BookViewSet处理
...
]
5. 图书下载接口
有几个关键点:
- 通过前端的参数读取指定路径的文件.
- 返回csv格式文件.
到这里大家应该知道下一步是什么了, 是的, 我们先编写view层代码:
# api.view.download.py
from rest_framework import response, renderers, views
from django.conf import settings
from os.path import join
class CSVRenderer(renderers.BaseRenderer): # 默认是JsonRender, 但是现在我们需要定制一下
media_type = 'text/csv'
format = 'csv'
def render(self, data, accepted_media_type=None, renderer_context=None):
return data
class DownloadView(views.APIView): # 注意这里没继承BaseView
authentication_classes = []
permission_classes = []
renderer_classes = [CSVRenderer] # 将response渲染成csv文件格式
def get(self, request, path):
path = join(settings.MEDIA_ROOT, path) # 根据前端传来的path参数, 获取文件本地路径
data = open(path, 'rb').read() # 读取二进制
return response.Response(data=data)
然后呢? 当然是配置路由喽:
# backend.urls.py
from django.urls import re_path
from api.views.download import DownloadView
urlpatterns = [
...
re_path(r'^upload/(?P<path>.*)$', DownloadView.as_view()), # 子匹配的值会作为参数传入处理函数中
...
]
6. 使用django-admin进行图书管理
Django 自带后台管理功能, 我们需要做的只是将需要管理的model注册一下:
# api.admin.py
from django.contrib import admin
from api.models.book import Book
admin.site.register(Book)
7. 迁移, 运行, 测试
刚才我们只是配置了model层, 但是还没有真正去创建数据库表结构, 所以在运行之前还要进行数据库迁移.
迁移和运行的方式请参考上一章.
运行之后我们需要对接口进行测试, 作者使用的是Postman工具, 大家可以选择自己熟悉的工具进行测试.
最后, 大家打开127.0.0.1:8000/admin
, 进入管理页, 上传单词本吧(注意必须是csv格式的哦~).
csv格式的单词本大家可以去这里下载: github.com/ourongxing/…, 感谢开源~
很简单是不是. 但是后端能做的东西还是有很多的, 下面列举一些, 供读者以后自己练习:
- 使用django-admin进行图书管理.
- 加入用户管理模块.
- 支持https.
- 将服务端部署到云端等等...
代码已开源: github.com/oooooocean/…, 如果觉得有帮助, 请给个Star, 鼓励下作者.
如果大家对代码有疑问, 或者遇到什么问题, 欢迎加群和作者讨论: