WEB后端服务第20天-Django第10天
一、Django-RESTful入门
1.1 REST 概要
1.2 安装包
pip install djangorestframework markdwon django-filter
1.3 开始使用
1.3.1 创建api包,并在__init__.py中声明api_router对象
1.3.2 在api包下创建user.py脚本,并在脚本中声明序列化类和视图
1.3.3 在init.py脚本中,注册视图
1.3.4 主urls.py配置和settings.py配置
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
1.3.5 访问并尝试CURD操作
二、数据序列化
序列化: 将模型类对象转换成json格式字符串的数据,并返回给前端。可以序列化一个模型类对象, 也可以序列化多个模型类对象queryset(many=True)
反序列化: 将json数据转换成模型类对象,反 序列化还可以用来进一步验证信息和保存数据, 但验证的时候不一定保存数据入库,但是保存数据入库的时候一定要验证数据。
序列化和反序列化的功能本质上都属于序列化器的功能。
2.1 三种序列化类
-
Serializer
- 声明相关的字段
- 实现create(**validate_data)和update(instance, **validate_data)两个函数
-
ModelSerializer
声明class 的Meta类, 并指定相关的属性
- model
- fields 字段列表
-
HyperlinkedModelSerializer
2.2 序列化与反序列化
- 查询模型类的数据: 对象, queryset+many=True
from api.user import UserSerializer
from user.models import UserModel
s1 = UserSerializer(UserModel.objects.get(pk=1))
s2 = UserSerializer(UserModel.objects.all(), many=True)
# 将模型的对象转成dict或list
s1.data
s2.data
-
content = JSONReader().reader(serializer.data) 渲染成json数据的字符串
-
JSONParser().parse(io.BytesIO(content)) 对已渲染的json字符串进行反序列化
可以在views视图处理函数中使用, 对于POST请求对象,可以直接使用JSONParser()对象request请求对象进行反向解析
data = JSONParser().parse(request)
serializer = UserSerializer(data=data)
serializer.save() # 将数据保存到数据库中
【注意】序列化类创建时常用的参数:instance、data、context、partial、 many
2.3 关联关系的序列化
- serializers.StringRelatedField 获取关联模型类对象的__str__()返回的字符串
- serializers.PrimarykeyRelatedField 获取关联模型对象的pk主键id值
- serializers.SlugRelatedField(slug_field=‘关联模型的字段’)
- serializers.HyperlinkedRelatedField
如果关联的模型存在序列化类, 则内嵌关联模型的序列化类。
class ActiveGoodsSerializer(serializers.HyperlinkedModelSerializer):
goods = GoodsSerializer()
class Meta:
model = ActiveGoodsModel
fields = ('goods', 'rate')
class ActiveSerializer(serializers.HyperlinkedModelSerializer):
# activies = serializers.StringRelatedField(many=True)
activies = ActiveGoodsSerializer(many=True)
class Meta:
model = ActiveModel
fields = ('title', 'start_time', 'end_time', 'img1', 'activies')
三、请求与响应
3.1 请求对象 Request
继承HttpRequest, 扩展了一部分功能, 增加data属性,可以处理PUT/PATCH/POST方法的参数。
request.data # request.POST
3.2 响应对象Reponse
继承TempalteReponse, 在创建响应的对象,提供data属性
return Reponse(data)
rest_framework框架提供status模块, 提供响应的信息.
HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
四、API授权
4.1 默认授权认证
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
默认情况下,APIView中的相关接口方法是不验证权限(授权),对资源来说不是很安全。可以通过以下的方式增加验证。
class ExampleView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
content = {
'user': unicode(request.user), # `django.contrib.auth.User` 实例。
'auth': unicode(request.auth), # None
}
return Response(content)
可以指定TokenAuthentication
class TokenAuthentication(BaseAuthentication):
"""
Simple token based authentication.
Clients should authenticate by passing the token key in the "Authorization"
HTTP header, prepended with the string "Token ". For example:
Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a
"""
keyword = 'Token'
model = None
def get_model(self):
if self.model is not None:
return self.model
from rest_framework.authtoken.models import Token
return Token
"""
A custom token model may be used, but must have the following properties.
* key -- The string identifying the token
* user -- The user to which the token belongs
"""
def authenticate(self, request):
auth = get_authorization_header(request).split()
if not auth or auth[0].lower() != self.keyword.lower().encode():
return None
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Token string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = auth[1].decode()
except UnicodeError:
msg = _('Invalid token header. Token string should not contain invalid characters.')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
def authenticate_credentials(self, key):
model = self.get_model()
try:
token = model.objects.select_related('user').get(key=key)
except model.DoesNotExist:
raise exceptions.AuthenticationFailed(_('Invalid token.'))
if not token.user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
return (token.user, token)
def authenticate_header(self, request):
return self.keyword
4.2 自定义Token身份认证
from django.utils.translation import ugettext_lazy as _
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from rest_framework.authtoken.models import Token
from rest_framework import HTTP_HEADER_ENCODING
# 获取请求头里的token信息
def get_authorization_header(request):
auth = request.META.get('HTTP_AUTHORIZATION', b'')
if isinstance(auth, type('')):
auth = auth.encode(HTTP_HEADER_ENCODING)
return auth
# 自定义的ExpiringTokenAuthentication认证方式
class ExpiringTokenAuthentication(BaseAuthentication):
model = Token
def authenticate(self, request):
auth = get_authorization_header(request)
if not auth:
return None
try:
token = auth.decode()
except UnicodeError:
msg = _('验证token无效')
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(token)
五、Form表单类的用法
5.1 定义django.forms.Form类的子类
在app模块下,创建forms.py脚本,内容如下:
lass UserForm(forms.Form):
name = forms.CharField(max_length=10, min_length=3, required=True,
error_messages={'required': '账号参数必填',
'max_length': '最大长度为10个字符',
'min_length': '最小长度为3个字符'})
password = forms.BooleanField(required=True,error_messages={'required': '口令参数必填'})
phone = forms.BooleanField(required=True,error_messages={'required': '手机号参数必填'})
另外,forms模块还提供了ModelForm类,可以在内部声明Meta类,并在类中声明model指定模型类和验证的字段fields,详细查看文档。
5.2 表单验证
在 请求视图类的处理函数中
form = UserForm(request.POST)
if form.is_valid():
# 成功 , 验证之后的数据都在form.cleaned_data中
else:
errors = form.errors()
# 失败
扩展: DestroyModelMixin
删除视图扩展类,提供destroy(request, args, *kwargs)方法,可以快速实现删除一个存在的数据对象。
成功返回204,不存在返回404。