本文首发于:行者AI
在python我的项目开发中,前后端拆散的技术框架越来越成熟,在前后端进行通信时,通常须要用对立的格局进行通信,目前利用比拟宽泛的是RESTful API。那后端如何疾速编写基于Django的RESTful API呢?本篇将次要介绍应用DjangoRestFramework(drf)框架来疾速开发合乎REST格调的API。
1. drf概念及特点
1.1 概念
drf框架是基于Django框架,用于疾速构建Web RESTful API的工具。
1.2 特点
(1) 提供了定义序列化器Serializer的办法,能够疾速依据Django ORM 或者其余库主动序列化、反序列化;
(2) 提供了丰盛的类视图、MIXIN扩大类,依据需要组合继承,简化视图的编写;
(3) 丰盛的定制层级:函数视图、类视图、视图汇合到主动生成 API,满足各种须要;
(4) 反对多种身份认证和权限认证形式;
(5) 内置了限流零碎;
(6) 可视化API接口;
(7) 可扩展性 , 插件丰盛。
2. drf的应用
drf对代码的简化次要是对视图的增删改查、申请数据的反序列化和响应数据的序列化进行简化,所以次要介绍drf的序列化器和视图集的应用。
2.1 搭建我的项目
搭建我的项目环境,创立我的项目exercise,创立app利用student,代码如下:
# python==3.6.5virtualenv -p /python/python.exe /virtualenv/exerciseenvcd /virtualenv/exerciseenv/Scripts/activatepip install django==3.1.5 pymysql==1.0.2 djangorestframework==3.12.2cd /study/django-admin startproject exercisecd exercisedjango-admin startapp student
目录构造如下:
而后关上我的项目在/exercise/settings.py
文件中配置数据库,注册app(student和rest_framework)。
2.2 创立模型
在/student/models.py
文件中,建设三张表:班级(Grade)、课程(Course)、学生(Student)。
class Grade(models.Model): # 班级 name = models.CharField(max_length=16, null=False, unique=True) class Meta: db_table = 'grade' ordering = ['id']class Course(models.Model): # 课程 name = models.CharField(max_length=32, unique=True, null=False) class Meta: db_table = 'course' ordering = ['id']class Student(models.Model): # 学生 name = models.CharField(max_length=16, null=False) age = models.IntegerField(null=True) gender = models.BooleanField(null=False, default=0) g = models.ForeignKey(Grade, on_delete=models.CASCADE) c = models.ManyToManyField(Course) class Meta: db_table = 'student' ordering = ['id']
2.3 创立序列化器
在/student/serializers.py
文件中,建设三个模型对应的序列化器;序列化器有两个次要性能:序列化和反序列化。如果前端是GET申请,则结构查问集,将后果返回,这个过程为序列化;如果前端是POST申请,要对数据库进行改变,则须要拿到前端发来的数据,进行校验,校验通过将数据写入数据库,这个过程称为反序列化。这能极大的简化视图代码量,前面会做个比照。代码如下:
class GradeSerializer(serializers.ModelSerializer): class Meta: # 指定序列化器对应的模型 model = Grade # 指定须要序列化的字段,‘__all__’示意所有字段 fields = ['name']class CourseSerializer(serializers.ModelSerializer): class Meta: model = Course fields = ['name']class StudentSerializer(serializers.ModelSerializer): # 自定义序列化和反序列化字段校验条件,默认应用建表束缚校验;也能够应用extra_kwargs # SlugRelatedField指定关联对象的指定字段,关联字段默认为关联对象id c = serializers.SlugRelatedField(slug_field='name', many=True, queryset=Course.objects.all()) g = serializers.SlugRelatedField(slug_field='name', queryset=Grade.objects.all()) class Meta: model = Student # 自定义校验 extra_kwargs = {'age': {'max_value': 30, 'min_value': 0}} fields = '__all__' # 返回数据预处理 def to_representation(self, instance): data = super().to_representation(instance) if data['gender'] == 0: data['gender'] = '女' else: data['gender'] = '男' return data
2.4 编写视图
在/student/views.py
文件中,编写视图,每个模型对应一个视图,继承drf的viewsets.ModelViewSet
类,蕴含增删改查四大操作,通过不同的申请办法映射到drf定义的对应的动作action办法上。action办法包含create(新增)、retrieve(查问详情)、destroy(删除)、update(批改)、list(列表展现)。代码如下:
class StudentView(viewsets.ModelViewSet): queryset = Student.objects.all() # 指定查问后果集 serializer_class = StudentSerializer # 指定序列化器class GradeView(viewsets.ModelViewSet): queryset = Grade.objects.all() serializer_class = GradeSerializerclass CourseView(viewsets.ModelViewSet): queryset = Course.objects.all() serializer_class = CourseSerializer
2.5 注册路由
在/exercise2/urls.py
文件中,注册根路由:
urlpatterns = [ path('api/', include('student.urls'))]
在/student/urls.py
文件中,注册资源路由:
# 应用drf的视图集就不须要编写路由,通过DefaultRouter的register办法注册就能够了router = DefaultRouter()router.register('student', views.StudentView)router.register('course', views.CourseView)router.register('grade', views.GradeView)urlpatterns = [ path('', include(router.urls))]
2.6 列举url
列举一下资源为student的申请门路和形式,其余资源相似:
GET http://127.0.0.1:8000/api/student/ 查问所有学生信息POST http://127.0.0.1:8000/api/student/ 传入学生各项信息,创立该学生对象GET http://127.0.0.1:8000/api/student/1/ 查问id为1的学生信息 默认过滤字段为id,可自定义过滤器DELETE http://127.0.0.1:8000/api/student/1/ 删除id为1的学生,默认过滤字段为idPUT http://127.0.0.1:8000/api/student/1/ 批改id为1的学生信息,默认过滤字段为id
3. drf框架与原生Django的比照
3.1 views.py文件
这里只写了student模型对应的各项操作视图,其余模型相似。StudentListCrate视图蕴含展现学生列表(get)和插入学生数据(post)接口,StudentUpdateRetrieveDestroy视图蕴含对单个学生数据查问(get)、批改(put)、删除(delete)接口。代码如下:
class StudentListCrate(View): def get(self, request): students = Student.objects.all() students_list = [] for stu in students: if stu.gender == 1: stu_gender = '男' else: stu_gender = '女' g_name = Grade.objects.filter(id=stu.g_id).first().name cou_name_list = [] for cou in stu.c.all(): cou_name_list.append(cou.name) students_list.append({'id': stu.id, 'name': stu.name, 'age': stu.age, 'gender': stu_gender, 'courses': cou_name_list, 'g_name': g_name}) return JsonResponse(students_list, safe=False) def post(self, request): form = StudentForm(json.loads(request.body)) if form.is_valid(): name = form.cleaned_data['name'] age = form.cleaned_data['age'] gender = form.cleaned_data['gender'] g = form.cleaned_data['g'].id c = [cou.id for cou in form.cleaned_data['c']] stu = Student.objects.create(name=name, age=age, gender=gender, g_id=g) stu.save() stu.c.add(*c) return JsonResponse({'code': 200, 'msg': '创立胜利'}) return JsonResponse({'code': 200, 'msg': form.errors})class StudentUpdateRetrieveDestroy(View): def get(self, request, pk): stu = Student.objects.filter(pk=pk).first() if not stu: return JsonResponse({'code': 400, 'msg': '没有这个学生'}) g_name = Grade.objects.filter(id=stu.g_id).first().name if stu.gender == 1: stu_gender = '男' else: stu_gender = '女' cou_name_list = [] for cou in stu.c.all(): cou_name_list.append(cou.name) return JsonResponse({'id': stu.id, 'name': stu.name, 'age': stu.age, 'gender': stu_gender, 'courses': cou_name_list, 'g_name': g_name}) def put(self, request, pk): stu_query = Student.objects.filter(pk=pk) stu = stu_query.first() if not stu: return JsonResponse({'code': 400, 'msg': '没有这个学生'}) form = StudentForm(json.loads(request.body)) if form.is_valid(): c = [cou.id for cou in form.cleaned_data['c']] stu.c.set(c) del form.cleaned_data['c'] update_dict = form.cleaned_data stu_query.update(**update_dict) return JsonResponse({'code': 200, 'msg': '创立胜利'}) return JsonResponse({'code': 200, 'msg': form.errors}) def delete(self, request, pk): stu = Student.objects.filter(pk=pk).first() if not stu: return JsonResponse({'code': 400, 'msg': '没有这个学生'}) stu.delete() return JsonResponse({'code': 200, 'msg': '删除胜利'})
3.2 forms.py文件
这是搁置做表单校验类的文件,是在模型束缚之上再定义一层合乎业务实际意义的校验,并且校验未通过,能够将谬误提示信息返回给用户,进步用户体验,代码如下:
class StudentForm(forms.Form): name = forms.CharField(max_length=16, required=True, min_length=2, error_messages={'max_length': '名字最长为16', 'min_length': '名字最短为2', 'required': '名字必填'}) age = forms.IntegerField(max_value=30, min_value=10, error_messages={'max_value': '年龄最大为30', 'min_value': '年龄最小为10'}) gender = forms.BooleanField(required=False, error_messages={'required': '性别必填'}) g = forms.ModelChoiceField(queryset=Grade.objects.all(), error_messages={'queryset': '没有这个班级'}) c = forms.ModelMultipleChoiceField(queryset=Course.objects.all(), error_messages={'queryset': '不存在这个课程'})
3.3 总结
比照发现drf解决三个模型的代码量比原生django解决一个模型的代码都要少,阐明drf框架极大地提高了RESTful API开发效率,不过认真点还能发现因为drf封装地太好,对于解决业务逻辑简单的接口就须要咱们重构相应的办法。drf丰盛的各项性能使咱们开发效率更高,但同时学习老本也是直线回升,本文只是论述序列化器和视图集类的利用,对于细分的各类的利用及组合应用还需进一步钻研学习。