在开发Web应用中,有两种应用模式:css
为了在团队内部造成共识、防止我的习惯差别引发的混乱,咱们须要找到一种你们都以为很好的接口实现规范,并且这种规范可以让后端写的接口,用途一目了然,减小双方之间的合做成本。html
目前市面上大部分公司开发人员使用的接口服务架构主要有:restful、rpc。前端
rpc: 翻译成中文:远程过程调用[远程服务调用].python
http://www.lufei.com/apimysql
post请求linux
action=get_all_student¶ms=301&sex=1git
接口多了,对应函数名和参数就多了,前端在请求api接口时,就会比较难找.容易出现重复的接口github
restful: 翻译成中文: 资源状态转换.web
把后端全部的数据/文件都当作资源.sql
那么接口请求数据,本质上来讲就是对资源的操做了.
web项目中操做资源,无非就是增删查改.因此要求在地址栏中声明要操做的资源是什么,而后经过http请求动词来讲明对资源进行哪种操做.
POST http://www.lufei.com/api/students/ 添加学生数据
GET http://www.lufei.com/api/students/ 获取全部学生
DELETE http://www.lufei.com/api/students/
REST全称是Representational State Transfer,中文意思是表述(编者注:一般译为表征)性状态转移。 它首次出如今2000年Roy Fielding的博士论文中。
RESTful是一种定义Web API接口的设计风格,尤为适用于先后端分离的应用模式中。
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,因此在定义接口时,客户端访问的URL路径就表示这种要操做的数据资源。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动做来表达对数据的增删查改。
请求方法 | 请求地址 | 后端操做 |
---|---|---|
GET | /students | 获取全部学生 |
POST | /students | 增长学生 |
GET | /students/
|
获取编号为pk的学生 |
PUT | /students/
|
修改编号为pk的学生 |
DELETE | /students/
|
删除编号为pk的学生 |
事实上,咱们能够使用任何一个框架均可以实现符合restful规范的API接口。
参考文档:http://www.runoob.com/w3cnote/restful-architecture.html
api接口开发,最核心最多见的一个过程就是序列化,所谓序列化就是把数据转换格式,序列化能够分两个阶段:
序列化: 把咱们识别的数据转换成指定的格式提供给别人。
例如:咱们在django中获取到的数据默认是模型对象,可是模型对象数据没法直接提供给前端或别的平台使用,因此咱们须要把数据进行序列化,变成字符串或者json数据,提供给别人。
反序列化:把别人提供的数据转换/还原成咱们须要的格式。
例如:前端js提供过来的json数据,对于python而言就是字符串,咱们须要进行反序列化换成模型类对象,这样咱们才能把数据保存到数据库中。
核心思想: 缩减编写api接口的代码
Django REST framework是一个创建在Django基础之上的Web 应用开发框架,能够快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,能够帮助咱们简化序列化与反序列化的过程,不只如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工做。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
中文文档:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework
github: https://github.com/encode/django-rest-framework/tree/master
DRF须要如下依赖:
DRF是以Django扩展应用的方式提供的,因此咱们能够直接利用已有的Django环境而无需重新建立。(若没有Django环境,须要先建立环境安装Django)
前提是已经安装了django,建议安装在虚拟环境
# mkvirtualenv drfdemo -p python3 # pip install django pip install djangorestframework pip install pymysql
linux 复制 shift+insert
cd ~/Desktop django-admin startproject drfdemo
使用pycharm打开项目,设置虚拟环境的解析器,并修改manage.py中的后缀参数。
在settings.py的INSTALLED_APPS中添加'rest_framework'。
INSTALLED_APPS = [ ... 'rest_framework', ]
接下来就可使用DRF提供的功能进行api接口开发了。在项目中若是使用rest_framework框架实现API接口,主要有如下三个步骤:
接下来,咱们快速体验下四天后咱们学习完成drf之后的开发代码。接下来代码不须要理解,看步骤。
class Student(models.Model): # 模型字段 name = models.CharField(max_length=100,verbose_name="姓名") sex = models.BooleanField(default=1,verbose_name="性别") age = models.IntegerField(verbose_name="年龄") class_null = models.CharField(max_length=5,verbose_name="班级编号") description = models.TextField(max_length=1000,verbose_name="个性签名") class Meta: db_table="tb_student" verbose_name = "学生" verbose_name_plural = verbose_name
为了方便测试,因此咱们能够先建立一个数据库。
mysql -uroot -p; create database students charset=utf8;
把students子应用添加到INSTALL_APPS中
初始化数据库链接
安装pymysql pip install pymysql
主引用中__init__.py
设置使用pymysql做为数据库驱动
import pymysql pymysql.install_as_MySQLdb()
settings.py配置文件中设置mysql的帐号密码
DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # }, 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': "students", "HOST": "127.0.0.1", "PORT": 3306, "USER": "root", "PASSWORD":"123", } }
终端下,执行数据迁移。
python manage.py makemigrations python manage.py migrate
错误列表
# 执行数据迁移 python manage.py makemigrations 报错以下:
解决方案:
注释掉 backends/mysql/base.py中的35和36行代码。
# 执行数据迁移发生如下错误:
解决方法:
backends/mysql/operations.py146行里面新增一个行代码:
例如,在django项目中建立学生子应用。
python manage.py startapp students
在syudents应用目录中新建serializers.py用于保存该应用的序列化器。
建立一个StudentModelSerializer用于序列化与反序列化。
# 建立序列化器类,回头会在试图中被调用 class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__"
在students应用的views.py中建立视图StudentViewSet,这是一个视图集合。
from rest_framework.viewsets import ModelViewSet from .models import Student from .serializers import StudentModelSerializer # Create your views here. class StudentViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer
在students应用的urls.py中定义路由信息。
from . import views from rest_framework.routers import DefaultRouter # 路由列表 urlpatterns = [] router = DefaultRouter() # 能够处理视图的路由器 router.register('students', views.StudentViewSet) # 向路由器中注册视图集 urlpatterns += router.urls # 将路由器中的因此路由信息追到到django的路由列表中
最后把students子应用中的路由文件加载到总路由文件中.
from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path("stu/",include("students.urls")), ]
运行当前程序(与运行Django同样)
python manage.py runserver
在浏览器中输入网址127.0.0.1:8000,能够看到DRF提供的API Web浏览页面:
1)点击连接127.0.0.1:8000/stu/students 能够访问获取全部数据的接口,呈现以下页面:
2)在页面底下表单部分填写学生信息,能够访问添加新学生的接口,保存学生信息:
点击POST后,返回以下页面信息:
3)在浏览器中输入网址127.0.0.1:8000/stu/students/5/,能够访问获取单一学生信息的接口(id为5的学生),呈现以下页面:
4)在页面底部表单中填写学生信息,能够访问修改学生的接口:
点击PUT,返回以下页面信息:
5)点击DELETE按钮,能够访问删除学生的接口:
返回,以下页面:
做用:
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
接下来,为了方便演示序列化器的使用,咱们先建立一个新的子应用sers
python manage.py startapp sers
咱们已有了一个数据库模型类students/models.py
models.py
from django.db import models # Create your models here. class Student(models.Model): # 模型字段 name = models.CharField(max_length=100,verbose_name="姓名",help_text="提示文本:帐号不能为空!") sex = models.BooleanField(default=True,verbose_name="性别") age = models.IntegerField(verbose_name="年龄") class_null = models.CharField(max_length=5,verbose_name="班级编号") description = models.TextField(verbose_name="个性签名") class Meta: db_table="tb_student" verbose_name = "学生" verbose_name_plural = verbose_name
咱们想为这个模型类提供一个序列化器,能够定义以下:
from rest_framework import serializers # 声明序列化器,全部的序列化器都要直接或者间接继承于 Serializer # 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化 class StudentSerializer(serializers.Serializer): """学生信息序列化器""" # 1. 须要进行数据转换的字段 id = serializers.IntegerField() name = serializers.CharField() age = serializers.IntegerField() sex = serializers.BooleanField() description = serializers.CharField() # 2. 若是序列化器集成的是ModelSerializer,则须要声明调用的模型信息 # 3. 验证代码 # 4. 编写添加和更新模型的代码
注意:serializer不是只能为数据库模型类定义,也能够为非数据库模型类的数据定义。serializer是独立于数据库以外的存在。
经常使用字段类型:
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(max*length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9*-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=, min_length=None, max_length=None) |
DictField | DictField(child=) |
选项参数:
参数名称 | 做用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否容许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用参数:
参数名称 | 说明 |
---|---|
read_only | 代表该字段仅用于序列化输出,默认False |
write_only | 代表该字段仅用于反序列化输入,默认False |
required | 代表该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 代表该字段是否容许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展现API页面时,显示的字段名称 |
help_text | 用于HTML展现API页面时,显示的字段帮助提示信息 |
定义好Serializer类后,就能够建立Serializer对象了。
Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可经过context参数额外添加数据,如
serializer = AccountSerializer(account, context={'request': request})
经过context参数附加的数据,能够经过Serializer对象的context属性获取。
序列化器的使用分两个阶段:
1) 先查询出一个学生对象
from students.models import Student student = Student.objects.get(id=3)
2) 构造序列化器对象
from .serializers import StudentSerializer serializer = StudentSerializer(instance=student)
3)获取序列化数据
经过data属性能够获取序列化后的数据
serializer.data # {'id': 4, 'name': '小张', 'age': 18, 'sex': True, 'description': '猴赛雷'}
完整视图代码:
views.py
from django.views import View from students.models import Student from .serializers import StudentSerializer from django.http.response import JsonResponse class StudentView(View): """使用序列化器序列化转换单个模型数据""" def get(self,request,pk): # 获取数据 student = Student.objects.get(pk=pk) # 数据转换[序列化过程] serializer = StudentSerializer(instance=student) print(serializer.data) # 响应数据 return JsonResponse(serializer.data)
4)若是要被序列化的是包含多条数据的查询集QuerySet,能够经过添加many=True参数补充说明
"""使用序列化器序列化转换多个模型数据""" def get(self,request): # 获取数据 student_list = Student.objects.all() # 转换数据[序列化过程] # 若是转换多个模型对象数据,则须要加上many=True serializer = StudentSerializer(instance=student_list,many=True) print( serializer.data ) # 序列化器转换后的数据 # 响应数据给客户端 # 返回的json数据,若是是列表,则须要声明safe=False return JsonResponse(serializer.data,safe=False) # 访问结果: # [OrderedDict([('id', 1), ('name', 'xiaoming'), ('age', 20), ('sex', True), ('description', '测试')]), OrderedDict([('id', 2), ('name', 'xiaohui'), ('age', 22), ('sex', True), ('description', '后面来的测试')]), OrderedDict([('id', 4), ('name', '小张'), ('age', 18), ('sex', True), ('description', '猴赛雷')])]
使用序列化器进行反序列化时,须要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,不然返回False。
验证失败,能够经过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。若是是非字段错误,能够经过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,能够经过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每一个字段的序列化类型和选项参数,自己就是一种验证行为。
如咱们前面定义过的BookInfoSerializer
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" id = serializers.IntegerField(label='ID', read_only=True) btitle = serializers.CharField(label='名称', max_length=20) bpub_date = serializers.DateField(label='发布日期', required=False) bread = serializers.IntegerField(label='阅读量', required=False) bcomment = serializers.IntegerField(label='评论量', required=False) image = serializers.ImageField(label='图片', required=False)
经过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
测试:
from booktest.serializers import BookInfoSerializer data = {'bpub_date': 123} serializer = BookInfoSerializer(data=data) serializer.is_valid() # 返回False serializer.errors # {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]} serializer.validated_data # {} data = {'btitle': 'python'} serializer = BookInfoSerializer(data=data) serializer.is_valid() # True serializer.errors # {} serializer.validated_data # OrderedDict([('btitle', 'python')])
is_valid()方法还能够在验证失败时抛出异常serializers.ValidationError,能够经过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
# Return a 400 response if the data was invalid. serializer.is_valid(raise_exception=True)
若是以为这些还不够,须要再补充定义验证行为,可使用如下三种方法:
对<field_name>
字段进行验证,如
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" ... def validate_btitle(self, value): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的") return value
测试
from booktest.serializers import BookInfoSerializer data = {'btitle': 'python'} serializer = BookInfoSerializer(data=data) serializer.is_valid() # False serializer.errors # {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
在序列化器中须要同时对多个字段进行比较验证时,能够定义validate方法来验证,如
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" ... def validate(self, attrs): bread = attrs['bread'] bcomment = attrs['bcomment'] if bread < bcomment: raise serializers.ValidationError('阅读量小于评论量') return attrs
测试
from booktest.serializers import BookInfoSerializer data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20} s = BookInfoSerializer(data=data) s.is_valid() # False s.errors # {'non_field_errors': [ErrorDetail(string='阅读量小于评论量', code='invalid')]}
在字段中添加validators选项参数,也能够补充验证行为,如
def about_django(value): if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的") class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" id = serializers.IntegerField(label='ID', read_only=True) btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django]) bpub_date = serializers.DateField(label='发布日期', required=False) bread = serializers.IntegerField(label='阅读量', required=False) bcomment = serializers.IntegerField(label='评论量', required=False) image = serializers.ImageField(label='图片', required=False)
测试:
from booktest.serializers import BookInfoSerializer data = {'btitle': 'python'} serializer = BookInfoSerializer(data=data) serializer.is_valid() # False serializer.errors # {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
前面的验证数据成功后,咱们可使用序列化器来完成数据反序列化的过程.这个过程能够把数据转成模型类对象.
能够经过实现create()和update()两个方法来实现。
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" ... def create(self, validated_data): """新建""" return BookInfo(**validated_data) def update(self, instance, validated_data): """更新,instance为要更新的对象实例""" instance.btitle = validated_data.get('btitle', instance.btitle) instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date) instance.bread = validated_data.get('bread', instance.bread) instance.bcomment = validated_data.get('bcomment', instance.bcomment) return instance
若是须要在返回数据对象的时候,也将数据保存到数据库中,则能够进行以下修改
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" ... def create(self, validated_data): """新建""" return BookInfo.objects.create(**validated_data) def update(self, instance, validated_data): """更新,instance为要更新的对象实例""" instance.btitle = validated_data.get('btitle', instance.btitle) instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date) instance.bread = validated_data.get('bread', instance.bread) instance.bcomment = validated_data.get('bcomment', instance.bcomment) instance.save() return instance
实现了上述两个方法后,在反序列化数据的时候,就能够经过save()方法返回一个数据对象实例了
book = serializer.save()
若是建立序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,若是传递了instance实例,则调用save()方法的时候,update()被调用。
from db.serializers import BookInfoSerializer data = {'btitle': '封神演义'} serializer = BookInfoSerializer(data=data) serializer.is_valid() # True serializer.save() # <BookInfo: 封神演义> from db.models import BookInfo book = BookInfo.objects.get(id=2) data = {'btitle': '倚天剑'} serializer = BookInfoSerializer(book, data=data) serializer.is_valid() # True serializer.save() # <BookInfo: 倚天剑> book.btitle # '倚天剑'
1) 在对序列化器进行save()保存时,能够额外传递数据,这些数据能够在create()和update()中的validated_data参数获取到
# request.user 是django中记录当前登陆用户的模型对象 serializer.save(owner=request.user)
2)默认序列化器必须传递全部required的字段,不然会抛出验证异常。但是咱们可使用partial参数来容许部分字段更新
# Update `comment` with partial data serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)
若是咱们想要使用序列化器对应的是Django的模型类,DRF为咱们提供了ModelSerializer模型类序列化器来帮助咱们快速建立一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
好比咱们建立一个BookInfoSerializer
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = '__all__'
咱们能够在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现
>>> from booktest.serializers import BookInfoSerializer >>> serializer = BookInfoSerializer() >>> serializer BookInfoSerializer(): id = IntegerField(label='ID', read_only=True) btitle = CharField(label='名称', max_length=20) bpub_date = DateField(allow_null=True, label='发布日期', required=False) bread = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False) bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False) image = ImageField(allow_null=True, label='图片', max_length=100, required=False)
1) 使用fields来明确字段,__all__
表名包含全部字段,也能够写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = ('id', 'btitle', 'bpub_date')
2) 使用exclude能够明确排除掉哪些字段
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo exclude = ('image',)
3) 显示指明字段,如:
class HeroInfoSerializer(serializers.ModelSerializer): hbook = BookInfoSerializer() class Meta: model = HeroInfo fields = ('id', 'hname', 'hgender', 'hcomment', 'hbook')
4) 指明只读字段
能够经过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment') read_only_fields = ('id', 'bread', 'bcomment')
咱们可使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment') extra_kwargs = { 'bread': {'min_value': 0, 'required': True}, 'bcomment': {'min_value': 0, 'required': True}, } # BookInfoSerializer(): # id = IntegerField(label='ID', read_only=True) # btitle = CharField(label='名称', max_length=20) # bpub_date = DateField(allow_null=True, label='发布日期', required=False) # bread = IntegerField(label='阅读量', max_value=2147483647, min_value=0, required=True) # bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=0, required=True)
django中一共提供了两种视图:分别是函数视图[function view]和类视图[class view]。
# 函数视图 def login(request): """登陆功能""" # 登陆功能代码 return Response({“message”:"ok"})
接下来,方便学习,因此咱们建立一个新的子应用clsview
python manage.py startapp clsview
函数视图,实现功能,须要手动判断用户的请求动做,并且当函数视图数量多了,就不要概括整理。
"""函数视图的登陆功能""" from django.http import HttpResponse def login_form(request): """显示登陆页面""" html = """ <form method="post" action="/clsview/login_data/"> 帐号: <input type="text" name="usernane"><br><br> 密码: <input type="password" name="password"><br><br> <input type="submit" value="登陆"> </form> """ return HttpResponse(html) def login_data(request): """验证登陆""" print( request.POST ) return HttpResponse("登陆成功") """"路由代码""""" from django.urls.conf import path from . import views urlpatterns = [ path(r"login_form/",views.login_form), path(r"login_data/",views.login_data), ]
类视图,能够实现django自动根据用户的http请求动做,自动识别执行对应名称的视图方法。
form django.views import View class MemberView(View): def get(self,request): """获取用户数据""" ... def post(self,request): """添加用户数据""" ... def put(self,request): """修改用户数据""" ... def delete(self,request): """删除用户数据""" ....
代码:
from django.http import HttpResponse from django.views import View class LoginView(View): def get(self,request): """显示登陆页面""" html = """ <form method="post" action="/clsview/login_data/"> 帐号: <input type="text" name="usernane"><br><br> 密码: <input type="password" name="password"><br><br> <input type="submit" value="登陆"> </form> """ return HttpResponse(html) def post(self,request): """处理登陆验证""" print( request.POST ) return HttpResponse("登陆成功")
类视图核心的实现代码就是as_view和dispatch方法。
类视图中的视图方法都是固定名称,只能是http请求动做的小写名称。
drf除了在数据序列化部分简写代码之外,还在视图中提供了简写操做。因此在django原有的django.views.View类基础上,drf封装了多个子类出来提供给咱们使用。
Django REST framwork 提供的视图的主要做用:
为了方便咱们学习,因此先建立一个子应用req
python manage.py startapp req
REST framework 传入视图的request对象再也不是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。
Request对象的数据是自动根据前端发送数据的格式进行解析以后的结果。
不管前端发送的哪一种格式的数据,咱们均可以以统一的方式读取数据。
request.data
返回解析以后的请求体数据。相似于Django中标准的request.POST
和 request.FILES
属性,但提供以下特性:
request.query_params
与Django标准的request.GET
相同,只是更换了更正确的名称而已。
rest_framework.response.Response
REST framework提供了一个响应类Response
,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
REST framework提供了Renderer
渲染器,用来根据请求头中的Accept
(接收数据类型声明)来自动转换响应数据到对应格式。若是前端请求中未进行Accept声明,则会采用默认方式处理响应数据,咱们能够经过配置来修改默认响应格式。
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类 'rest_framework.renderers.JSONRenderer', # json渲染器 'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器 ) }
Response(data, status=None, template_name=None, headers=None, content_type=None)
data
数据不要是render处理以后的数据,只需传递python的内建类型数据便可,REST framework会使用renderer
渲染器处理data
。
data
不能是复杂结构的数据,如Django的模型类对象,对于这样的数据咱们可使用Serializer
序列化器序列化处理后(转为了Python字典类型)再传递给data
参数。
参数说明:
data
: 为响应准备的序列化处理后的数据;status
: 状态码,默认200;template_name
: 模板名称,若是使用HTMLRenderer
时需指明;headers
: 用于存放响应头信息的字典;content_type
: 响应数据的Content-Type,一般此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。传给response对象的序列化后,但还没有render处理的数据
状态码的数字
通过render处理后的响应数据
为了方便设置状态码,REST framewrok在rest_framework.status
模块中提供了经常使用状态码常量。
HTTP_100_CONTINUE HTTP_101_SWITCHING_PROTOCOLS
HTTP_200_OK HTTP_201_CREATED HTTP_202_ACCEPTED HTTP_203_NON_AUTHORITATIVE_INFORMATION HTTP_204_NO_CONTENT HTTP_205_RESET_CONTENT HTTP_206_PARTIAL_CONTENT HTTP_207_MULTI_STATUS
HTTP_300_MULTIPLE_CHOICES HTTP_301_MOVED_PERMANENTLY HTTP_302_FOUND HTTP_303_SEE_OTHER HTTP_304_NOT_MODIFIED HTTP_305_USE_PROXY HTTP_306_RESERVED HTTP_307_TEMPORARY_REDIRECT
HTTP_400_BAD_REQUEST HTTP_401_UNAUTHORIZED HTTP_402_PAYMENT_REQUIRED HTTP_403_FORBIDDEN HTTP_404_NOT_FOUND HTTP_405_METHOD_NOT_ALLOWED HTTP_406_NOT_ACCEPTABLE HTTP_407_PROXY_AUTHENTICATION_REQUIRED HTTP_408_REQUEST_TIMEOUT HTTP_409_CONFLICT HTTP_410_GONE HTTP_411_LENGTH_REQUIRED HTTP_412_PRECONDITION_FAILED HTTP_413_REQUEST_ENTITY_TOO_LARGE HTTP_414_REQUEST_URI_TOO_LONG HTTP_415_UNSUPPORTED_MEDIA_TYPE HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE HTTP_417_EXPECTATION_FAILED HTTP_422_UNPROCESSABLE_ENTITY HTTP_423_LOCKED HTTP_424_FAILED_DEPENDENCY HTTP_428_PRECONDITION_REQUIRED HTTP_429_TOO_MANY_REQUESTS HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
HTTP_500_INTERNAL_SERVER_ERROR HTTP_501_NOT_IMPLEMENTED HTTP_502_BAD_GATEWAY HTTP_503_SERVICE_UNAVAILABLE HTTP_504_GATEWAY_TIMEOUT HTTP_505_HTTP_VERSION_NOT_SUPPORTED HTTP_507_INSUFFICIENT_STORAGE HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
rest_framework.views.APIView
APIView
是REST framework提供的全部视图的基类,继承自Django的View
父类。
APIView
与View
的不一样之处在于:
Request
对象,而不是Django的HttpRequeset
对象;Response
对象,视图会为响应数据设置(render)符合前端要求的格式;APIException
异常都会被捕获到,而且处理成合适的响应信息;支持定义的类属性
在APIView
中仍以常规的类视图定义方法来实现get() 、post() 或者其余请求方式的方法。
举例:
from rest_framework.views import APIView from rest_framework.response import Response # url(r'^students/$', views.StudentsAPIView.as_view()), class StudentsAPIView(APIView): def get(self, request): data_list = Student.objects.all() serializer = StudentModelSerializer(instance=data_list, many=True) return Response(serializer.data)
rest_framework.generics.GenericAPIView
继承自APIVIew
,主要增长了操做序列化器和数据库查询的方法,做用是为下面Mixin扩展类的执行提供方法支持。一般在使用时,可搭配一个或多个Mixin扩展类。
提供的关于序列化器使用的属性与方法
属性:
方法:
get_serializer_class(self)
当出现一个视图类中调用多个序列化器时,那么能够经过条件判断在get_serializer_class方法中经过返回不一样的序列化器类名就可让视图方法执行不一样的序列化器对象了。
返回序列化器类,默认返回serializer_class
,能够重写,例如:
def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer
返回序列化器对象,主要用来提供给Mixin扩展类使用,若是咱们在视图中想要获取序列化器对象,也能够直接调用此方法。
注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象能够在定义序列化器时使用。
提供的关于数据库查询的属性与方法
属性:
方法:
get_queryset(self)
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset
属性,能够重写,例如:
def get_queryset(self): user = self.request.user return user.accounts.all()
get_object(self)
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中能够调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404。
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
举例:
# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()), class BookDetailView(GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self, request, pk): book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象 serializer = self.get_serializer(book) return Response(serializer.data)
其余能够设置的属性
为了方便学习上面的GenericAPIView通用视图类,咱们新建一个子应用。
python manage.py startapp gen
代码:
from rest_framework.generics import GenericAPIView from students.models import Student from .serializers import StudentModelSerializer, StudentModel2Serializer from rest_framework.response import Response class StudentsGenericAPIView(GenericAPIView): # 本次视图类中要操做的数据[必填] queryset = Student.objects.all() # 本次视图类中要调用的默认序列化器[选填] serializer_class = StudentModelSerializer def get(self, request): """获取全部学生信息""" serializer = self.get_serializer(instance=self.get_queryset(), many=True) return Response(serializer.data) def post(self,request): data = request.data serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) instance = serializer.save() serializer = self.get_serializer(instance=instance) return Response(serializer.data) class StudentGenericAPIView(GenericAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get_serializer_class(self): """重写获取序列化器类的方法""" if self.request.method == "GET": return StudentModel2Serializer else: return StudentModelSerializer # 在使用GenericAPIView视图获取或操做单个数据时,视图方法中的表明主键的参数最好是pk def get(self,request,pk): """获取一条数据""" serializer = self.get_serializer(instance=self.get_object()) return Response(serializer.data) def put(self,request,pk): data = request.data serializer = self.get_serializer(instance=self.get_object(),data=data) serializer.is_valid(raise_exception=True) serializer.save() serializer = self.get_serializer(instance=self.get_object()) return Response(serializer.data)
序列化器类:
from rest_framework import serializers from students.models import Student class StudentModelSerializer(serializers.ModelSerializer): class Meta: model= Student fields = "__all__" class StudentModel2Serializer(serializers.ModelSerializer): class Meta: model= Student fields = ("name","class_null")
做用:
提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,若是须要编写的视图属于这五种,则视图能够经过继承相应的扩展类来复用代码,减小本身编写的代码量。
这五个扩展类须要搭配GenericAPIView父类,由于五个扩展类的实现须要调用GenericAPIView提供的序列化器与数据库查询的方法。
列表视图扩展类,提供list(request, *args, **kwargs)
方法快速实现列表视图,返回200状态码。
该Mixin的list方法会对数据进行过滤和分页。
源代码:
class ListModelMixin(object): """ List a queryset. """ def list(self, request, *args, **kwargs): # 过滤 queryset = self.filter_queryset(self.get_queryset()) # 分页 page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) # 序列化 serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
举例:
from rest_framework.mixins import ListModelMixin class BookListView(ListModelMixin, GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self, request): return self.list(request)
建立视图扩展类,提供create(request, *args, **kwargs)
方法快速实现建立资源的视图,成功返回201状态码。
若是序列化器对前端发送的数据验证失败,返回400错误。
源代码:
class CreateModelMixin(object): """ Create a model instance. """ def create(self, request, *args, **kwargs): # 获取序列化器 serializer = self.get_serializer(data=request.data) # 验证 serializer.is_valid(raise_exception=True) # 保存 self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
详情视图扩展类,提供retrieve(request, *args, **kwargs)
方法,能够快速实现返回一个存在的数据对象。
若是存在,返回200, 不然返回404。
源代码:
class RetrieveModelMixin(object): """ Retrieve a model instance. """ def retrieve(self, request, *args, **kwargs): # 获取对象,会检查对象的权限 instance = self.get_object() # 序列化 serializer = self.get_serializer(instance) return Response(serializer.data)
举例:
class BookDetailView(RetrieveModelMixin, GenericAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer def get(self, request, pk): return self.retrieve(request)
更新视图扩展类,提供update(request, *args, **kwargs)
方法,能够快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)
方法,能够实现局部更新。****
成功返回200,序列化器校验数据失败时,返回400错误。
源代码:
class UpdateModelMixin(object): """ Update a model instance. """ def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) self.perform_update(serializer) if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} return Response(serializer.data) def perform_update(self, serializer): serializer.save() def partial_update(self, request, *args, **kwargs): kwargs['partial'] = True return self.update(request, *args, **kwargs)
删除视图扩展类,提供destroy(request, *args, **kwargs)
方法,能够快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。
源代码:
class DestroyModelMixin(object): """ Destroy a model instance. """ def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) def perform_destroy(self, instance): instance.delete()
使用GenericAPIView和视图扩展类,实现api接口,代码:
"""GenericAPIView结合视图扩展类实现api接口""" from rest_framework.mixins import ListModelMixin,CreateModelMixin class Students2GenericAPIView(GenericAPIView,ListModelMixin,CreateModelMixin): # 本次视图类中要操做的数据[必填] queryset = Student.objects.all() # 本次视图类中要调用的默认序列化器[玄天] serializer_class = StudentModelSerializer def get(self, request): """获取多个学生信息""" return self.list(request) def post(self,request): """添加学生信息""" return self.create(request) from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student2GenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer # 在使用GenericAPIView视图获取或操做单个数据时,视图方法中的表明主键的参数最好是pk def get(self,request,pk): """获取一条数据""" return self.retrieve(request,pk) def put(self,request,pk): """更新一条数据""" return self.update(request,pk) def delete(self,request,pk): """删除一条数据""" return self.destroy(request,pk)
提供 post 方法
继承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
使用视图集ViewSet,能够将一系列逻辑相关的动做放到一个类中:
ViewSet视图集类再也不实现get()、post()等方法,而是实现动做 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动做与具体请求方式对应上。如:
class BookInfoViewSet(viewsets.ViewSet): def list(self, request): books = BookInfo.objects.all() serializer = BookInfoSerializer(books, many=True) return Response(serializer.data) def retrieve(self, request, pk=None): try: books = BookInfo.objects.get(id=pk) except BookInfo.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) serializer = BookInfoSerializer(books) return Response(serializer.data)
在设置路由时,咱们能够以下操做
urlpatterns = [ url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}), url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'}) ]
继承自APIView
与ViewSetMixin
,做用也与APIView基本相似,提供了身份认证、权限校验、流量管理等。
ViewSet主要经过继承ViewSetMixin来实如今调用as_view()时传入字典(如{'get':'list'})的映射处理工做。
在ViewSet中,没有提供任何动做action方法,须要咱们本身实现action方法。
使用ViewSet一般并不方便,由于list、retrieve、create、update、destory等方法都须要本身编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,因此咱们能够经过继承Mixin扩展类来复用这些方法而无需本身编写。可是Mixin扩展类依赖与GenericAPIView
,因此还须要继承GenericAPIView
。
GenericViewSet就帮助咱们完成了这样的继承工做,继承自GenericAPIView
与ViewSetMixin
,在实现了调用as_view()时传入字典(如{'get':'list'}
)的映射处理工做的同时,还提供了GenericAPIView
提供的基础方法,能够直接搭配Mixin扩展类使用。
举例:
from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin): queryset = Student.objects.all() serializer_class = StudentModelSerializer
url的定义
urlpatterns = [ path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})), re_path("students7/(?P<pk>\d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})), ]
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin。
在视图集中,除了上述默认的方法动做外,还能够添加自定义动做。
举例:
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer def login(self,request): """学生登陆功能""" return Response({"message":"登陆成功"})
url的定义
urlpatterns = [ path("students8/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})), re_path("students8/(?P<pk>\d+)/", views.StudentModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})), path("stu/login/",views.StudentModelViewSet.as_view({"get":"login"})) ]
在视图集中,咱们能够经过action对象属性来获取当前请求视图集时的action动做是哪一个。
例如:
from rest_framework.viewsets import ModelViewSet from students.models import Student from .serializers import StudentModelSerializer from rest_framework.response import Response class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer def get_new_5(self,request): """获取最近添加的5个学生信息""" # 操做数据库 print(self.action) # 获取本次请求的视图方法名 经过路由访问到当前方法中.能够看到本次的action就是请求的方法名
对于视图集ViewSet,咱们除了能够本身手动指明请求方式与动做action之间的对应关系外,还可使用Routers来帮助咱们快速实现路由信息。
REST framework提供了两个router
1) 建立router对象,并注册视图集,例如
from rest_framework import routers router = routers.DefaultRouter() router.register(r'router_stu', StudentModelViewSet, base_name='student')
register(prefix, viewset, base_name)
如上述代码会造成的路由以下:
^books/$ name: book-list ^books/{pk}/$ name: book-detail
2)添加路由数据
能够有两种方式:
urlpatterns = [ ... ] urlpatterns += router.urls
或
urlpatterns = [ ... url(r'^', include(router.urls)) ]
使用路由类给视图集生成了路由地址
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer def login(self,request): """学生登陆功能""" print(self.action) return Response({"message":"登陆成功"})
路由代码:
from django.urls import path, re_path from . import views urlpatterns = [ ... ] """使用drf提供路由类router给视图集生成路由列表""" # 实例化路由类 # drf提供一共提供了两个路由类给咱们使用,他们用法一致,功能几乎同样 from rest_framework.routers import DefaultRouter router = DefaultRouter() # 注册视图集 # router.register("路由前缀",视图集类) router.register("router_stu",views.StudentModelViewSet) # 把生成的路由列表追加到urlpatterns print( router.urls ) urlpatterns += router.urls
上面的代码就成功生成了路由地址[增/删/改/查一条/查多条的功能],可是不会自动咱们在视图集自定义方法的路由。
因此咱们若是也要给自定义方法生成路由,则须要进行action动做的声明。
在视图集中,若是想要让Router自动帮助咱们为自定义的动做生成路由信息,须要使用rest_framework.decorators.action
装饰器。
以action装饰器装饰的方法名会做为action动做名,与list、retrieve等同。
action装饰器能够接收两个参数:
methods: 声明该action对应的请求方式,列表传递
detail
: 声明该action的路径是否与单一资源对应,及是不是
xxx/<pk>/action方法名/
xxx/<pk>/action方法名/
xxx/action方法名/
举例:
from rest_framework.viewsets import ModelViewSet from rest_framework.decorators import action class StudentModelViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentModelSerializer # methods 设置当前方法容许哪些http请求访问当前视图方法 # detail 设置当前视图方法是不是操做一个数据 # detail为True,表示路径名格式应该为 router_stu/{pk}/login/ @action(methods=['get'], detail=True) def login(self, request,pk): """登陆""" ... # detail为False 表示路径名格式应该为 router_stu/get_new_5/ @action(methods=['put'], detail=False) def get_new_5(self, request): """获取最新添加的5个学生信息""" ...
由路由器自动为此视图集自定义action方法造成的路由会是以下内容:
^router_stu/get_new_5/$ name: router_stu-get_new_5 ^router_stu/{pk}/login/$ name: router_stu-login
1) SimpleRouter
2)DefaultRouter
DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含全部列表视图的超连接响应数据。
能够在配置文件中配置全局默认的认证方案
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', # session认证 'rest_framework.authentication.BasicAuthentication', # 基本认证 ) }
也能够在每一个视图中经过设置authentication_classess属性来设置
from rest_framework.authentication import SessionAuthentication, BasicAuthentication from rest_framework.views import APIView class ExampleView(APIView): # 类属性 authentication_classes = [SessionAuthentication, BasicAuthentication] ...
认证失败会有两种可能的返回值:
权限控制能够限制用户对于视图的访问和对于具体数据对象的访问。
能够在配置文件中全局设置默认的权限管理类,如
REST_FRAMEWORK = { .... 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ) }
若是未指明,则采用以下默认配置
'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.AllowAny', )
也能够在具体的视图中经过permission_classes属性来设置,如
from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView class ExampleView(APIView): permission_classes = (IsAuthenticated,) ...
举例
from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.generics import RetrieveAPIView class StudentAPIView(RetrieveAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated]
如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现如下两个任何一个方法或所有
.has_permission(self, request, view)
是否能够访问视图, view表示当前视图对象
.has_object_permission(self, request, view, obj)
是否能够访问数据对象, view表示当前视图, obj为数据对象
例如:
在当前子应用下,建立一个权限文件permissions.py中声明自定义权限类:
from rest_framework.permissions import BasePermission class IsXiaoMingPermission(BasePermission): def has_permission(self, request, view): if( request.user.username == "xiaoming" ): return True
from .permissions import IsXiaoMingPermission class StudentViewSet(ModelViewSet): queryset = Student.objects.all() serializer_class = StudentSerializer permission_classes = [IsXiaoMingPermission]
能够对接口访问的频次进行限制,以减轻服务器压力。
通常用于付费购买次数,投票等场景使用.
能够在配置文件中,使用DEFAULT_THROTTLE_CLASSES
和 DEFAULT_THROTTLE_RATES
进行全局配置,
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ), 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', 'user': '1000/day' } }
DEFAULT_THROTTLE_RATES
可使用 second
, minute
, hour
或day
来指明周期。
也能够在具体视图中经过throttle_classess属性来配置,如
from rest_framework.throttling import UserRateThrottle from rest_framework.views import APIView class ExampleView(APIView): throttle_classes = (UserRateThrottle,) ...
1) AnonRateThrottle
限制全部匿名未认证用户,使用IP区分用户。
使用DEFAULT_THROTTLE_RATES['anon']
来设置频次
2)UserRateThrottle
限制认证用户,使用User id 来区分。
使用DEFAULT_THROTTLE_RATES['user']
来设置频次
3)ScopedRateThrottle
限制用户对于每一个视图的访问频次,使用ip或user id。
例如:
class ContactListView(APIView): throttle_scope = 'contacts' ... class ContactDetailView(APIView): throttle_scope = 'contacts' ... class UploadView(APIView): throttle_scope = 'uploads' ... REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.ScopedRateThrottle', ), 'DEFAULT_THROTTLE_RATES': { 'contacts': '1000/day', 'uploads': '20/day' } }
全局配置中设置访问频率
'DEFAULT_THROTTLE_RATES': { 'anon': '3/minute', 'user': '10/minute' }
from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.generics import RetrieveAPIView from rest_framework.throttling import UserRateThrottle class StudentAPIView(RetrieveAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated] throttle_classes = (UserRateThrottle,)
对于列表数据可能须要根据字段进行过滤,咱们能够经过添加django-fitlter扩展来加强支持。
pip install django-filter
在配置文件中增长过滤后端的设置:
INSTALLED_APPS = [ ... 'django_filters', # 须要注册应用, ] REST_FRAMEWORK = { ... 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
在视图中添加filter_fields属性,指定能够过滤的字段
class StudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer filter_fields = ('age', 'sex') # 127.0.0.1:8000/four/students/?sex=1
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助咱们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,若是包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端能够传递的ordering参数的可选字段值须要在ordering_fields中指明。
示例:
class StudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_backends = [OrderingFilter] ordering_fields = ('id', 'age') # 127.0.0.1:8000/books/?ordering=-age # -id 表示针对id字段进行倒序排序 # id 表示针对id字段进行升序排序
若是须要在过滤之后再次进行排序,则须要二者结合!
from rest_framework.generics import ListAPIView from students.models import Student from .serializers import StudentModelSerializer from django_filters.rest_framework import DjangoFilterBackend class Student3ListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer filter_fields = ('age', 'sex') # 由于局部配置会覆盖全局配置,因此须要从新把过滤组件核心类再次声明, # 不然过滤功能会失效 filter_backends = [OrderingFilter,DjangoFilterBackend] ordering_fields = ('id', 'age')
REST framework提供了分页的支持。
咱们能够在配置文件中设置全局的分页方式,如:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 # 每页数目 }
也可经过自定义Pagination类,来为视图添加不一样分页行为。在视图中经过pagination_clas
属性来指明。
class LargeResultsSetPagination(PageNumberPagination): page_size = 1000 page_size_query_param = 'page_size' max_page_size = 10000 class BookDetailView(RetrieveAPIView): queryset = BookInfo.objects.all() serializer_class = BookInfoSerializer pagination_class = LargeResultsSetPagination
注意:若是在视图内关闭分页功能,只需在视图内设置
pagination_class = None
1) PageNumberPagination
前端访问网址形式:
GET http://127.0.0.1:8000/students/?page=4
能够在子类中定义的属性:
# 声明分页的配置类 from rest_framework.pagination import PageNumberPagination class StandardPageNumberPagination(PageNumberPagination): # 默认每一页显示的数据量 page_size = 2 # 容许客户端经过get参数来控制每一页的数据量 page_size_query_param = "size" max_page_size = 10 # 自定义页码的参数名 page_query_param = "p" class StudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer pagination_class = StandardPageNumberPagination # 127.0.0.1/four/students/?p=1&size=5
2)LimitOffsetPagination
前端访问网址形式:
GET http://127.0.0.1/four/students/?limit=100&offset=400
能够在子类中定义的属性:
PAGE_SIZE
设置一直from rest_framework.pagination import LimitOffsetPagination class StandardLimitOffsetPagination(LimitOffsetPagination): # 默认每一页查询的数据量,相似上面的page_size default_limit = 2 limit_query_param = "size" offset_query_param = "start" class StudentAPIView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentModelSerializer # 调用页码分页类 # pagination_class = StandardPageNumberPagination # 调用查询偏移分页类 pagination_class = StandardLimitOffsetPagination
REST framework提供了异常处理,咱们能够自定义异常处理函数。
from rest_framework.views import exception_handler def custom_exception_handler(exc, context): # 先调用REST framework默认的异常处理方法得到标准错误响应对象 response = exception_handler(exc, context) # 在此处补充自定义的异常处理 if response is None: response.data['status_code'] = response.status_code return response
在配置文件中声明自定义的异常处理
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' }
若是未声明,会采用默认的方式,以下
rest_frame/settings.py
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler' }
例如:
补充上处理关于数据库的异常
from rest_framework.views import exception_handler as drf_exception_handler from rest_framework import status from django.db import DatabaseError def exception_handler(exc, context): response = drf_exception_handler(exc, context) if response is None: view = context['view'] if isinstance(exc, DatabaseError): print('[%s]: %s' % (view, exc)) response = Response({'detail': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) return response
也就是说,不少的没有在上面列出来的异常,就须要咱们在自定义异常中本身处理了。
REST framework能够自动帮助咱们生成接口文档。
接口文档以网页的方式呈现。
自动接口文档能生成的是继承自APIView
及其子类的视图。
REST framewrok生成接口文档须要coreapi
库的支持。
pip install coreapi
在总路由中添加接口文档路径。
文档路由对应的视图配置为rest_framework.documentation.include_docs_urls
,
参数title
为接口文档网站的标题。
from rest_framework.documentation import include_docs_urls urlpatterns = [ ... path('docs/', include_docs_urls(title='站点页面标题')) ]
1) 单一方法的视图,可直接使用类视图的文档字符串,如
class BookListView(generics.ListAPIView): """ 返回全部图书信息. """
2)包含多个方法的视图,在类视图的文档字符串中,分开方法定义,如
class BookListCreateView(generics.ListCreateAPIView): """ get: 返回全部图书信息. post: 新建图书. """
3)对于视图集ViewSet,仍在类视图的文档字符串中封开定义,可是应使用action名称区分,如
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet): """ list: 返回图书列表数据 retrieve: 返回图书详情数据 latest: 返回最新的图书数据 read: 修改图书的阅读量 """
浏览器访问 127.0.0.1:8000/docs/,便可看到自动生成的接口文档。
1) 视图集ViewSet中的retrieve名称,在接口文档网站中叫作read
2)参数的Description须要在模型类或序列化器类的字段中以help_text选项定义,如:
class Student(models.Model): ... age = models.IntegerField(default=0, verbose_name='年龄', help_text='年龄') ...
或
class StudentSerializer(serializers.ModelSerializer): class Meta: model = Student fields = "__all__" extra_kwargs = { 'age': { 'required': True, 'help_text': '年龄' } }
xadmin是Django的第三方扩展,比使用Django的admin站点更强大也更方便。
文档:https://xadmin.readthedocs.io/en/latest/index.html
经过以下命令安装xadmin的最新版
pip install https://codeload.github.com/sshwsfc/xadmin/zip/django2
在配置文件中注册以下应用
INSTALLED_APPS = [ ... 'xadmin', 'crispy_forms', 'reversion', ... ] # 修改使用中文界面 LANGUAGE_CODE = 'zh-Hans' # 修改时区 TIME_ZONE = 'Asia/Shanghai'
xadmin有创建本身的数据库模型类,须要进行数据库迁移
python manage.py makemigrations python manage.py migrate
在总路由中添加xadmin的路由信息
import xadmin xadmin.autodiscover() # version模块自动注册须要版本控制的 Model from xadmin.plugins import xversion xversion.register_models() urlpatterns = [ path(r'xadmin/', xadmin.site.urls), ]
若是以前没有建立超级用户,须要建立,若是有了,则能够直接使用以前的。
python manage.py createsuperuser
admin.ModelAdmin
,而是直接继承object
便可。例如:在子应用中建立adminx.py文件。
import xadmin from xadmin import views class BaseSetting(object): """xadmin的基本配置""" enable_themes = True # 开启主题切换功能 use_bootswatch = True xadmin.site.register(views.BaseAdminView, BaseSetting) class GlobalSettings(object): """xadmin的全局配置""" site_title = "路飞学城" # 设置站点标题 site_footer = "路飞学城有限公司" # 设置站点的页脚 menu_style = "accordion" # 设置菜单折叠 xadmin.site.register(views.CommAdminView, GlobalSettings)
xadmin可使用的页面样式控制基本与Django原生的admin一直。
list_display 控制列表展现的字段
list_display = ['id', 'btitle', 'bread', 'bcomment']
search_fields 控制能够经过搜索框搜索的字段名称,xadmin使用的是模糊查询
search_fields = ['id','btitle']
list_filter 能够进行过滤操做的列,对于分类、性别、状态
list_filter = ['is_delete']
ordering 默认排序的字段
show_detail_fields 在列表页提供快速显示详情信息
list_editable 在列表页能够快速直接编辑的字段
refresh_times 指定列表页的定时刷新
refresh_times = [5, 10,30,60] # 设置容许后端管理人员按多长时间(秒)刷新页面
list_export 控制列表页导出数据的可选格式
list_export = ('xls', 'xml', 'json') list_export设置为None来禁用数据导出功能 list_export_fields = ('id', 'btitle', 'bpub_date')
show_bookmarks 控制是否显示书签功能
show_bookmarks = True
data_charts 控制显示图表的样式
data_charts = { "order_amount": { 'title': '图书发布日期表', "x-field": "bpub_date", "y-field": ('btitle',), "order": ('id',) }, # 支持生成多个不一样的图表 # "order_amount": { # 'title': '图书发布日期表', # "x-field": "bpub_date", # "y-field": ('btitle',), # "order": ('id',) # }, }
model_icon 控制菜单的图标【图标的设置能够参考bootstrap的图标css名称】
class BookInfoAdmin(object): model_icon = 'fa fa-gift' xadmin.site.register(models.BookInfo, BookInfodmin)
readonly_fields 在编辑页面的只读字段
exclude 在编辑页面隐藏的字段