02: djangorestframework使用

1.1 djangorestframework登录、认证和权限

  1、认证与权限相关模块

      

# -*- coding: utf-8 -*-
from django.utils import six
from rest_framework.response import Response
from rest_framework.serializers import Serializer


class JsonResponse(Response):
    """
    An HttpResponse that allows its data to be rendered into
    arbitrary media types.
    """

    def __init__(self,
                 data=None,
                 code=None,
                 desc=None,
                 status=None,
                 template_name=None,
                 headers=None,
                 exception=False,
                 content_type='application/json; charset=utf-8'):
        """
        Alters the init arguments slightly.
        For example, drop 'template_name', and instead use 'data'.
        Setting 'renderer' and 'media_type' will typically be deferred,
        For example being set automatically by the `APIView`.
        """

        super(Response, self).__init__(None, status=status)

        if isinstance(data, Serializer):
            msg = ('You passed a Serializer instance as data, but '
                   'probably meant to pass serialized `.data` or '
                   '`.error`. representation.')
            raise AssertionError(msg)

        self.data = {"code": code, "desc": desc, "data": data}
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in six.iteritems(headers):
                self[name] = value
common\api_response.py 返回统一标准json数据
# -*- coding:utf-8 -*-
from __future__ import absolute_import

from rest_framework import status as http_status
from common.api_response import JsonResponse

__all__ = ['created_success']


def ajax_data(data=None,
              code=http_status.HTTP_200_OK,
              desc=None,
              status=http_status.HTTP_200_OK):

    return JsonResponse(data=data, code=code, desc=desc, status=status)


def success(data=None, desc=None):
    return ajax_data(data=data, desc=desc)


def error(data=None, desc=None):
    return ajax_data(
        data=data, code=http_status.HTTP_500_INTERNAL_SERVER_ERROR, desc=desc)


def created_success(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_201_CREATED,
        desc=desc,
        status=http_status.HTTP_201_CREATED)


def conflict(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_409_CONFLICT,
        desc=desc,
        status=http_status.HTTP_409_CONFLICT)


def accepted(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_202_ACCEPTED,
        desc=desc,
        status=http_status.HTTP_202_ACCEPTED)


def not_implemented(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_501_NOT_IMPLEMENTED,
        desc=desc,
        status=http_status.HTTP_501_NOT_IMPLEMENTED)


def unauthorized(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_401_UNAUTHORIZED,
        desc=desc,
        status=http_status.HTTP_401_UNAUTHORIZED)


def not_found(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_404_NOT_FOUND,
        desc=desc,
        status=http_status.HTTP_404_NOT_FOUND)


def bad_request(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_400_BAD_REQUEST,
        desc=desc,
        status=http_status.HTTP_400_BAD_REQUEST)
common\ajax.py 将所有返回封装成标准状态码格式
#!/usr/bin/python
# -*- coding: utf-8 -*-
from rest_framework.views import APIView
from common.auth.authentication import IsAuthenticated, IsOwnerOrReadOnly


class BaseViews(APIView):
    authentication_classes = (IsAuthenticated,)
    permission_classes = (IsOwnerOrReadOnly,)

    def __init__(self):
        super(BaseViews).__init__(BaseViews, self)
        self.user = None

    def perform_authentication(self, request):
        self.user = self.get_authenticators()[0].authenticate(request).user
common\auth\base_views.py 自定义认证和权限的基类
#!/usr/bin/python
# -*- coding: utf-8 -*-
from rest_framework import exceptions
from rest_framework import authentication
from rest_framework import permissions
from users.models import VueUserToken


class IsAuthenticated(authentication.BaseAuthentication):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def authenticate(self, request):
        auth = request.META.get('HTTP_AUTHORIZATION', None)
        if auth is None:
            raise exceptions.NotAuthenticated()
        token = VueUserToken.objects.filter(key=auth)
        try:
            request.user = token[0].user
        except IndexError:
            raise exceptions.NotAuthenticated('Invalid input Authenticated')
        return request

    def authenticate_header(self, request):
        msg = 'Invalid token.Please get token first'
        return exceptions.NotAuthenticated(msg)

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    是否有操作权限: 只有返回True才有操作权限,
    """

    def has_permission(self, request, view):

        if False:  # 这里暂且不进行权限验证
            raise exceptions.ParseError('您没有操作的权限')
        return True
common\auth\authentication.py 验证token是否合法,是否有请求操作权限
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import uuid
import hmac
from django.contrib.auth.models import User
from users.models import VueUserToken
from django.utils import timezone


def create_token():
    key = str(uuid.uuid1())
    h = hmac.new(b"123456", key.encode(encoding="utf-8"))
    return h.hexdigest()


def updata_token(user):
    userobj = User.objects.filter(username=user)
    if userobj:
        userobj = userobj[0]
    else:
        userobj = User.objects.create(username=user)
    tokenobj = VueUserToken.objects.filter(user=userobj)
    tokenid = create_token()
    if tokenobj:
        now = timezone.now()
        last_login_time = tokenobj[0].created
        interval = now - last_login_time
        if interval.seconds > 86400:
            tokenobj = tokenobj[0]
            tokenobj.key = tokenid
            tokenobj.save()
            return tokenobj.key
        return tokenobj[0].key
    else:
        tokenobj = VueUserToken.objects.create(user=userobj,key=tokenid)
        return tokenobj.key
common\auth\handle_token.py 用户身份验证通过后生成token

  2、创建users这个APP,并测试上面认证与权限的使用

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users',
    'rest_framework'
]
settings.py 注册app
from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', include('users.urls')),
]
urls.py 总url
__author__ = 'tom'
# -*-coding=utf8-*-
from django.conf.urls import url
from users import views

urlpatterns = [
    url(r'^v1/user/login/$', views.LoginViewSet.as_view(), name='user-login'),
    url(r'^v1/userinfo/$', views.UserInfoViewSet.as_view(), name='user-info'),
]
users/urls.py APP中url
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class VueUserToken(models.Model):
    user = models.OneToOneField(User, verbose_name='用户名',unique=True)
    key = models.CharField(max_length=255,null=True,blank=True)
    created = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Vue API Token'
        verbose_name_plural = verbose_name

    def __unicode__(self):
        return self.user.username
users/models.py 创建token表
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
import json
from common import ajax
from common.auth.base_views import BaseViews
from common.auth import handle_token


class LoginViewSet(APIView):
    """用户登录"""
    def __init__(self):
        super(LoginViewSet, self).__init__()

    def get(self,request):
        return HttpResponse('ok')

    def post(self, request, *args, **kwargs):
        user = request.data.get('username', '')
        pwd = request.data.get('password', '')
        username = authenticate(username=user, password=pwd)
        if username is None:
            return ajax.bad_request(desc='账号密码输入错误!')
        else:
            key = handle_token.updata_token(user)
            return ajax.success(data=str(key))


class UserInfoViewSet(BaseViews):
    '''获取用户信息'''
    def __init__(self):
        super(UserInfoViewSet, self).__init__()

    def get(self, request, *args, **kwargs):
        username = request.query_params.get('username')
        data = {'username':username}
        return ajax.success(desc='sucess',data=data)

    def post(self, request):
        usernamne = request.data.get('username')
        password = request.data.get('password')
        if usernamne is None or password is None:
            return ajax.bad_request(desc='抱歉,输入的信息不全')
        has_user = User.objects.filter(username=usernamne)
        if has_user:
            return ajax.bad_request(desc='用户名已经存在')
        user = User()
        user.set_password(password)                         #让密码更安全,设置密码,给密码加盐
        user.username = usernamne
        user.is_staff = True
        user.is_superuser = True
        user.save()
        return ajax.success(desc='创建成功')
users/views.py 登录、认证、权限使用举例

  3、测试接口 

      http://127.0.0.1:8000/users/v1/user/login/    # 用户登录接口

      http://127.0.0.1:8000/users/v1/userinfo/     # 创建用户信息(get)、创建用户(post)

      注:获取用户信息请求头必须携带token ( {"Authorization":"1192663f88632adc6595ced0b92d3efd}

      

1.2 djangorestframework 序列化

   参考博客:http://www.cnblogs.com/wupeiqi/articles/7805382.html

  1、序列化

      注:前端分页时只需出入(page_size,和page参数就能进行分页了)

        http://127.0.0.1:8000/app01/userinfo/page/?page_size=1&page=2
        page_size=1 :指定每页只显示一条数据
        page=2 :显示第二页的数据

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/',include('app01.urls')),
]
urls.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^userinfo/',views.UserInfoViewSet.as_view()),
]
app01/urls.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models


class UserInfo(models.Model):
    name = models.CharField(max_length=64,unique=True)
    ut = models.ForeignKey(to='UserType')
    gp = models.ManyToManyField(to='UserGroup')

class UserType(models.Model):
    type_name = models.CharField(max_length=64,unique=True)

class UserGroup(models.Model):
    group = models.CharField(max_length=64)
app01/models.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals
from rest_framework import serializers
from app01.models import UserInfo

__all__ = [
    'UserInfoSerializer',
]


# class UserInfoSerializer(serializers.ModelSerializer):
class UserInfoSerializer(serializers.Serializer):
    name = serializers.CharField()                        # 显示普通字段
    ut = serializers.CharField(source='ut.type_name')     # 显示一对多字段
    gp = serializers.SerializerMethodField()              # 自定义显示(显示多对多)
    xxx = serializers.CharField(source='name')           # 也可以自定义显示字段名称

    class Meta:
        model = UserInfo
        fields = ['name']
        # fields = '__all__'
        validators = []

    def get_gp(self,row):
        '''row: 传过来的正是 UserInfo表的对象'''
        gp_obj_list = row.gp.all()  # 获取用户所有组
        ret = []
        for item in gp_obj_list:
            ret.append({'id':item.id,'gp':item.group})
        return ret


ret = [{
    "name": "zhangsan",
    "ut": "超级管理员",
    "gp": [{
        "id": 1,
        "gp": "group01"
    }, {
        "id": 2,
        "gp": "group02"
    }],
    "xxx": "zhangsan"
}, {
    "name": "lisi",
    "ut": "超级管理员",
    "gp": [{
        "id": 1,
        "gp": "group01"
    }],
    "xxx": "lisi"
}, {
    "name": "wangwu",
    "ut": "普通管理员",
    "gp": [{
        "id": 2,
        "gp": "group02"
    }],
    "xxx": "wangwu"
}]
app01\serializers\userinfo_serializer.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
import json
from app01.serializers.userinfo_serializer import UserInfoSerializer
from models import UserInfo


class UserInfoViewSet(APIView):
    def get(self, request, *args, **kwargs):
        obj = UserInfo.objects.all()
        ser = UserInfoSerializer(instance=obj,many=True)
        ret = json.dumps(ser.data,ensure_ascii=False)
        print ret
        return HttpResponse(ret)
app01/views.py

  2、djangorestframework渲染器使用

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01',
    'rest_framework',
]
settings.py 中注册 rest_framework
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
import json
from app01.serializers.userinfo_serializer import UserInfoSerializer
from models import UserInfo


class UserInfoViewSet(APIView):
    def get(self, request, *args, **kwargs):
        obj = UserInfo.objects.all()
        ser = UserInfoSerializer(instance=obj,many=True)

        return Response(ser.data)
get请求时以Response返回

    

 1.3 djangorestframework 分页

  1、封装分页相关模块

#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals

from django.conf import settings
from rest_framework import status
from django.core.paginator import EmptyPage, Paginator, PageNotAnInteger

from common import ajax
from common.api_response import JsonResponse


def Paginators(objs, request, Serializer):
    """
    objs : 实体对象, queryset
    request : 请求对象
    Serializer : 对应实体对象的类
    page_size : 每页显示多少条数据
    page  : 显示第几页数据
    total_count :总共有多少条数据
    total :总页数
    """
    try:
        page_size = int(request.GET.get('page_size', settings.REST_FRAMEWORK['PAGE_SIZE']))
        page = int(request.GET.get('page', 1))
    except (TypeError, ValueError):
        return ajax.bad_request(desc='page and page_size must be integer!')

    paginator = Paginator(objs, page_size)    # paginator对象
    total_count = paginator.count
    total = paginator.num_pages    # 总页数
    try:
        objs = paginator.page(page)
    except PageNotAnInteger:
        objs = paginator.page(1)
    except EmptyPage:
        objs = paginator.page(paginator.num_pages)
    print 123455666
    print objs
    serializer = Serializer(objs, many=True)    # 序列化操作
    print '####################'
    print serializer
    print '$$$$$$$$$$$$$$$$$$$'
    return JsonResponse(
        data={
            'detail': serializer.data,
            'page': page,
            'page_size': page_size,
            'total': total,
            'total_count': total_count
        },
        code=status.HTTP_200_OK,
        desc='page success')    # 返回


def ApiPpaginator(objs_list, request):
    """
    objs : 实体对象, queryset
    request : 请求对象
    Serializer : 对应实体对象的类
    """
    try:
        page_size = int(request.GET.get('page_size', settings.REST_FRAMEWORK['PAGE_SIZE']))
        page = int(request.GET.get('page', 1))
    except (TypeError, ValueError):
        return ajax.bad_request(desc='page and page_size must be integer!')

    paginator = Paginator(objs_list, page_size)    # paginator对象
    total_count = paginator.count
    total = paginator.num_pages    # 总页数
    try:
        objs = paginator.page(page)
    except PageNotAnInteger:
        objs = paginator.page(1)
    except EmptyPage:
        objs = paginator.page(paginator.num_pages)

    return JsonResponse(
        data={
            'detail': objs.object_list,
            'page': page,
            'page_size': page_size,
            'total': total,
            'total_count': total_count
        },
        code=status.HTTP_200_OK,
        desc='page success')    # 返回
common\api_paginator.py
# -*- coding:utf-8 -*-
from __future__ import absolute_import

from rest_framework import status as http_status

from common.api_response import JsonResponse

__all__ = ['created_success']


def ajax_data(data=None,
              code=http_status.HTTP_200_OK,
              desc=None,
              status=http_status.HTTP_200_OK):

    return JsonResponse(data=data, code=code, desc=desc, status=status)


def success(data=None, desc=None):
    return ajax_data(data=data, desc=desc)


def error(data=None, desc=None):
    return ajax_data(
        data=data, code=http_status.HTTP_500_INTERNAL_SERVER_ERROR, desc=desc)


def created_success(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_201_CREATED,
        desc=desc,
        status=http_status.HTTP_201_CREATED)


def conflict(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_409_CONFLICT,
        desc=desc,
        status=http_status.HTTP_409_CONFLICT)


def accepted(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_202_ACCEPTED,
        desc=desc,
        status=http_status.HTTP_202_ACCEPTED)


def not_implemented(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_501_NOT_IMPLEMENTED,
        desc=desc,
        status=http_status.HTTP_501_NOT_IMPLEMENTED)


def unauthorized(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_401_UNAUTHORIZED,
        desc=desc,
        status=http_status.HTTP_401_UNAUTHORIZED)


def not_found(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_404_NOT_FOUND,
        desc=desc,
        status=http_status.HTTP_404_NOT_FOUND)


def bad_request(data=None, desc=None):
    return ajax_data(
        data=data,
        code=http_status.HTTP_400_BAD_REQUEST,
        desc=desc,
        status=http_status.HTTP_400_BAD_REQUEST)
common\ajax.py
# -*- coding: utf-8 -*-
from django.utils import six
from rest_framework.response import Response
from rest_framework.serializers import Serializer


class JsonResponse(Response):
    """
    An HttpResponse that allows its data to be rendered into
    arbitrary media types.
    """

    def __init__(self,
                 data=None,
                 code=None,
                 desc=None,
                 status=None,
                 template_name=None,
                 headers=None,
                 exception=False,
                 content_type='application/json; charset=utf-8'):
        """
        Alters the init arguments slightly.
        For example, drop 'template_name', and instead use 'data'.
        Setting 'renderer' and 'media_type' will typically be deferred,
        For example being set automatically by the `APIView`.
        """

        super(Response, self).__init__(None, status=status)

        if isinstance(data, Serializer):
            msg = ('You passed a Serializer instance as data, but '
                   'probably meant to pass serialized `.data` or '
                   '`.error`. representation.')
            raise AssertionError(msg)

        self.data = {"code": code, "desc": desc, "data": data}
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in six.iteritems(headers):
                self[name] = value
common\api_response.py

  2、分页使用

#! -*- coding:utf8 -*-

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'app01',
]

#  分页
REST_FRAMEWORK = {
    # 全局分页
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # 关闭api root页面展示
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'UNICODE_JSON': False,
    # 自定义异常处理
    'EXCEPTION_HANDLER': (
            'common.utils.custom_exception_handler'
        ),

    'PAGE_SIZE': 10}
settings.py
from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/',include('app01.urls')),
]
urls.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^userinfo/$',views.UserInfoViewSet.as_view()),
    url(r'^userinfo/page/$',views.UserPageViewSet.as_view()),
]
app01/urls.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models


class UserInfo(models.Model):
    name = models.CharField(max_length=64,unique=True)
    ut = models.ForeignKey(to='UserType')
    gp = models.ManyToManyField(to='UserGroup')

class UserType(models.Model):
    type_name = models.CharField(max_length=64,unique=True)

class UserGroup(models.Model):
    group = models.CharField(max_length=64)
app01/models.py
#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals
from rest_framework import serializers
from app01.models import UserInfo

__all__ = [
    'UserInfoSerializer',
]


# class UserInfoSerializer(serializers.ModelSerializer):
class UserInfoSerializer(serializers.Serializer):
    name = serializers.CharField()                        # 显示普通字段
    ut = serializers.CharField(source='ut.type_name')     # 显示一对多字段
    gp = serializers.SerializerMethodField()              # 自定义显示(显示多对多)
    xxx = serializers.CharField(source='name')           # 也可以自定义显示字段名称

    class Meta:
        model = UserInfo
        fields = ['name']
        # fields = '__all__'
        validators = []

    def get_gp(self,row):
        '''row: 传过来的正是 UserInfo表的对象'''
        gp_obj_list = row.gp.all()  # 获取用户所有组
        ret = []
        for item in gp_obj_list:
            ret.append({'id':item.id,'gp':item.group})
        return ret
app01\serializers\userinfo_serializer.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
import json
from app01.serializers.userinfo_serializer import UserInfoSerializer
from models import UserInfo
from common.api_paginator import Paginators


class UserInfoViewSet(APIView):
    def get(self, request, *args, **kwargs):
        obj = UserInfo.objects.all()
        ser = UserInfoSerializer(instance=obj,many=True)
        return Response(ser.data)


class UserPageViewSet(APIView):
    queryset = UserInfo.objects.all()
    serializer_class = UserInfoSerializer

    def get(self, request, *args, **kwargs):
        self.queryset = self.queryset.all()
        ret = Paginators(self.queryset, request, self.serializer_class)
        print json.dumps(ret.data)  # ret.data 返回的是最终查询的json数据
        return Paginators(self.queryset, request, self.serializer_class)
app01/views.py

 

posted @ 2018-12-15 17:46  不做大哥好多年  阅读(1069)  评论(0编辑  收藏  举报