WEB后端服务第20天-Django第十天

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。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值