Django REST framework
模型
字段类型
#BooleanField
# CharField(max_length=none[, **options])
# DateField DateTimeField([auto_now=False, auto_now_add=False, **options]) ##自动更新 自动创建
# DecimalField(max_digits=None,decimal_places=None[, **options]) 小数点
# BinaryField
#ImageField([upload_to=None, height_field=None, width_field=None, max_length=100, **options]) 需要安装pillow模块
#EmailField([maxlength=75, **options])
#FileField(upload_to=None[, max_length=100, **options]) 默认的form widget 是 FileInput
#FloatField
#IntegerField #整数
#IPAddressField
#GenericIPAddressField
#NullBooleanField
#PositiveIntegerField 正证书
#SlugField url常用 只能包含字母,数字,下划线和连字符的字符串
#TextField 大文本
#TimeField
#URLField
#FilePathField(path=None[, match=None, recursive=False, max_length=100, options])
## ProcessedImageField 使用imagekit模块
模型filed选项
#editable #error_messages #help_text
#primary_key radio_admin unique
#unique_for_date #unique_for_month
#unique_for_year
#validators
#db_index=True 创建索引
#verbose_name string类型。更人性化的列名。
## 获取drf模板源码交流学习 联系作者wechat yihongwxh
序列器
决定输入输出结构
常规示例写法
id = serializers.IntegerField(label='ID', read_only=True)
一般验证
使用模型序列器,extra_kwargs 来给字段加验证
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
#read_only_fields = ( 'date',)
# fields = '__all__' 输出所有模型
# exclude = ('image',) 排除模型
fields = ('q','a',"link","myfile","choice","myimg")
extra_kwargs = {#额外参数 指定最大最小值
'q': { 'required': True,'label':u"问题"}, #可使用的额外参数 label='阅读量', max_value=2147483647, min_value=0, required=True
'a': { 'required': True,'max_length':5,'help_text': u'帮助介绍'}, #read_only=True max_length=20
}
## 获取drf模板源码交流学习 联系作者wechat yihongwxh
单独某个字段验证
def validate_q(self, attrs): ##validate+字段名进行序列验证
if 's' not in attrs:
raise serializers.ValidationError(u'必须包含s')
return attrs
多字段验证
def validate(self, attrs): # 给多个字段增加校验
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('阅读量小于评论量')
return attrs
常规序列器与模型序列器
自动生成字段 validators 包含create()和update()方法
视图
默认视图APIVIEW
class BookView(APIView): ##需要自定义get,post,patch,delete方法
def get(self, request):
query_set = Book.objects.all()
book_ser = BookSerializer(query_set, many=True)
return Response(book_ser.data)
def post(self, request):
query_set = request.data
book_ser = BookSerializer(data=query_set)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.validated_data)
else:
return Response(book_ser.errors)
## 获取drf模板源码交流学习 联系作者wechat yihongwxh
封装过的GenericAPIView
# 默认使用queryset serializer_class
# 包含5个mixin 封装了get,post,patch,delete方法 对应ListModelMixin, CreateModelMixin,GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
# 5个mixin封装成2个apiview ListCreateAPIView RetrieveUpdateDestroyAPIView
使用viewsetmixin带action路由传参封装成modelviewset
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
使用action进行自定义路由
@action(methods=['get','post'],detail=False) ##自定义方法
# action是drf提供的路由和视图方法绑定关系的装饰器
# 参数2: detail 当前是否方法是否属于详情页视图,False,系统不会自动增加pk在生成的路由地址中 True 则系统会自动增加pk在生成的路由地址
def query(self,request): # 其接口 http://127.0.0.1:8000/task/query/
# 获取阅读量最多的5条数据
para= request.query_params ## request.data post put 参数
books = Task.objects.filter(q__contains =para['q']) # 多条查询使用Q #table.object.filter(Q(title__startswith='key1') | Q(title__startswith='key2'))
serializer = TaskSerializer(instance=books,many=True)
return Response(serializer.data)
queryset查询语句
##filter内容
# Blog.objects.filter(title__contains ="django")
#.objects.filter(id__in = [3,6,9])
#.objects.filter(id__range =(30,45))
#.objects.exclude(id=3)
#.objects.filter(create_time__year = 2018)
#objects.filter(create_time__month=3)
#.objects.dates('create_time', 'year','DESC') 返回时间
##__gt gte lt lte startswith endswith
获取请求数据
#request.query_params 存放的是我们get请求的参数
#request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求
##默认django方法request.POST.get() request.GET.get("pid")
##请求方法判断 request.method
响应
# Response(content, status=status.HTTP_404_NOT_FOUND)
# 状态码的种类....
自定义排序搜索过滤器
class TaskView(ModelViewSet):
filter_class = MyFilter
ordering_fields = ('q', 'choice') ##?ordering=price,name 查询 按照 price 排序后 在按 name 排序的结果 支持升序和降序 加-号即可
search_fields = ('q', 'a', 'link') # 模糊搜索 加入对应字段即可
##需要在全局setting.py导入
INSTALLED_APPS = [
'django_filters',
]
##排序搜索器导入setting.py 全局配置
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 20,
'DEFAULT_FILTER_BACKENDS':[
'rest_framework.filters.OrderingFilter',
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter'
],
}
路由
一般APIview写法
urlpatterns = [
url(r'^book$', BookView.as_view({"get": "list", "post": "create"})),
url(r'^book/(?P<pk>d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
]
###默认使用参数pk传递 指定get patch update delete 对应函数名
modelviewset路由自动注册
router = DefaultRouter()
router.register(r"book", BookView)
##自动注册5个方法,
权限设置RBAC
修改全局设置
##修改全局setting
AUTHENTICATION_BACKENDS = [
'account.backend.Mybackend',
'django.contrib.auth.backends.ModelBackend',
]
AUTH_USER_MODEL = 'account.MyUser'
注册admin跟user role permission模型
#admin.py 注册
admin.site.register(MyUser, UserAdmin)
#backend.py 示例
class Mybackend(ModelBackend):
def authenticate(self, username=None, password=None):
if username and password:
user = get_user_model().objects.filter(username=username).first()
if user and user.check_password(password):
return user
##创建3个模型 user role permission 分别嵌套
roles = models.ManyToManyField("Role", verbose_name="角色", blank=True)
服务端token生成
##登录验证返回token
##登录视图
class LoginView(APIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key})
#登录序列器
class LoginSerializer(serializers.Serializer):
username = serializers.CharField(required=True, error_messages={'blank': u'用户名不能为空'})
password = serializers.CharField(
style={'input_type': 'password'}, required=True, error_messages={'blank': u'密码不能为空'})
def validate(self, attrs):
username, password= attrs['username'], attrs['password']
user = authenticate(username=username, password=password)
if not user:
raise ValidationError(u'用户名或者密码错误')
attrs['user'] = user
return attrs
## 获取drf模板源码交流学习 联系作者wechat yihongwxh
前端传token
## header中传入 Authorization: Token 5e8341bfc3bda41f169ef6ee15613bca47619a44
封装的permission检查方法
perms_map = (('*', '*', '会员'), ('list', '*', '普通用户'), ##*表示能没有权限限制
('create', 'VIP', '会员'), ('update', 'VIP', '会员'),
('destroy', 'VIP','会员'),('query', "*", "查询"),)
### 传入perms_map list create update distory 以及自定义方法对应的权限方法 作为第二个参数传入
permission_classes = [RbacPermission, ]
一般权限
class RbacPermission(BasePermission): ##一般权限
def get_current_method(self, request, view):
"""
获取当前请求的方法(当前请求的是post/get 还是 viewset 的 action)
:param request:
:param view:
:return:
"""
return hasattr(view, 'action') and getattr(view,'action') or request._request.method.lower()
@classmethod ##不需要实例化直接调用
def get_permission_from_role(cls, request):
try:
perms = request.user.roles.values('permissions__name', ).distinct() ##后面的权限方法都写在method中
return [p['permissions__name'] for p in perms] ##写入到权限方法中去
except AttributeError:
return []
def get_current_perms(self, request, view):
"""
获取当前需要验证的权限
:return:
"""
_method = self.get_current_method(request, view)
perms_map = view.perms_map
# name_or_perm_obj 可能是权限名称,也可能是基于BasePermission的权限扩展实例
try:
action, name_or_perm_obj, label = [(action, name_or_perm_obj, label)
for action, name_or_perm_obj, label in perms_map
if action == _method][0]
except IndexError:
return True
print name_or_perm_obj
return name_or_perm_obj
def has_permission(self, request, view):
if request.user.is_superuser:
return True
if not hasattr(view, 'perms_map'): ##搜集所需权限列表
return True
name_or_perm_obj = self.get_current_perms(request, view)
if isinstance(name_or_perm_obj, BasePermission):
return name_or_perm_obj.has_permission(request, view) ##权限对象检查
return self.has_name_in_perms(name_or_perm_obj, request) ##字段检查
def has_name_in_perms(self, perm_name, request): ##检查用户有没有这个权限
perms = self.get_permission_from_role(request)
return perm_name == '*' or perm_name in perms
对象权限
class ObjPermission(BasePermission): ###通过用户id来检查
def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
return True
elif request.user.id == obj.uid_id:
return True
全局配置选项
MEDIA_URL = '/media/' ##媒体文件上传路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
LANGUAGE_CODE = 'zh-hans' #语言
文档写作
class TaskView(ModelViewSet):
''' ##markdown 使用说明'''
@swagger_auto_schema(method='get',operation_description='查询单个详细参数')
## swagger路由配置及后端登录接口
url(r'^swagger(?P<format>.json|.yaml)$', schema_view.without_ui(cache_timeout=0),
name='schema-json'),
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
url(r'^api/', include('rest_framework.urls', namespace='rest_framework_docs')),
插件
drf-ysag
django_filters
imagekit
常用导入头
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
##视图类
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView,ListCreateAPIView,RetrieveUpdateDestroyAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin,RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.viewsets import ViewSetMixin
from rest_framework.viewsets import ModelViewSet
import django_filters ##过滤器
from rest_framework.decorators import action
from rest_framework import routers, serializers
from rest_framework.response import Response ##响应
from django.conf import settings
from rest_framework import routers, serializers, viewsets
from django.contrib.auth import authenticate ##认证
from rest_framework.authtoken.models import Token ##token导入
from rest_framework.exceptions import ValidationError ##序列化出错返回
##路由
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter