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
# -*- 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)
#!/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
#!/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
#! /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
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' ]
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')), ]
__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'), ]
# -*- 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
# -*- 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='创建成功')
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')), ]
#! /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()), ]
# -*- 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)
#!/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" }]
# -*- 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)
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', ]
# -*- 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)
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') # 返回
# -*- 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)
# -*- 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
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}
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')), ]
#! /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()), ]
# -*- 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)
#!/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
# -*- 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)
作者:学无止境
出处:https://www.cnblogs.com/xiaonq
生活不只是眼前的苟且,还有诗和远方。