参考链接:
1.https://blog.csdn.net/qq_41500222/article/details/87895643
2.https://zhuanlan.zhihu.com/p/54293336
后端为前端提供URL(API接口)
返回json数据
对象有几种方法用来操作自己的属性或方法:
getattr(object, name),
hasattr(object, name),
setattr(object, name, value),
delattr(object, name)
1、有时我们要访问某个变量或是方法时并不知道到底有没有这个变量或方法,
所以就要做些判断。判断是否存在字符串对应的变量及方法。
2、我们知道访问变量时是不能加引号的,否则会被当成字符串处理。
如果要通过字符串找到对应的变量,
反射就是用于解决上面两个问题而产生的,所谓反射,
按我的理解就是反过来告诉我字符串是什么,是变量或方法
# 1. getattr()函数是Python自省的核心函数,具体使用大体如下:class A: def __init__(self):
self.name = 'zhangjing'#self.age='24'def method(self):
print"method print"
Instance = A()
print getattr(Instance , 'name, 'not find') #如果Instance 对象中有属性name则打印self.name的值,否则打印'not find'
print getattr(Instance , 'age', 'not find') #如果Instance 对象中有属性age则打印self.age的值,否则打印'not find'
print getattr(a, 'method', 'default') #如果有方法method,否则打印其地址,否则打印default
print getattr(a, 'method', 'default')() #如果有方法method,运行函数并打印None否则打印default
# 2. hasattr(object, name)
# 说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的)
# 3. setattr(object, name, value)
# 这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串可能会列出一个现有的属性或一个新的属性。这个函数将值赋给属性的。该对象允许它提供。例如,setattr(x,“foobar”,123)相当于x.foobar = 123。
4. delattr(object, name)
# 与setattr()相关的一组函数。参数是由一个对象(记住python中一切皆是对象)和一个字符串组成的。string参数必须是对象属性名之一。该函数删除该obj的一个由string指定的属性。delattr(x, 'foobar')=del x.foobar
Django中的视图函数分为 FBV和CBV其中CBV就是基于反射判断并执行对应方法接受返回值来实现的。
首先导入from rest_framework.views import APIView
APIView类
对于rest_framework的全局设置, 可以写在setting.py中的REST_FRAMEWORK = {}, 这个字典中
这些属性既可以写在继承的视图类下面,也可以设置全局的, 它会在项目中的setting.py 文件中读取
写认证类需要继承rest_framework中的认证基类
from rest_framework.authentication import BasicAuthentication
,且必须实现authenticate
方法
例如登录认证:
#创建一个我的认证类 继承BaseAuthentication方法
class MyAuthtication(BaseAuthentication):
# 设置内置authenticate重写authenticate这个方法
def authenticate(self, request):
# 将用户输入的token用变量接收
token = request._request.GET.get("token")
# 然后在数据库进行匹配
token_obj = models.UserToken.objects.filter(token=token).first()
# 如果认证失败
if not token_obj:
#就返回失败
raise exceptions.AuthenticationFailed("用户认证失败")
# 在 rest framework内部 会将这两个字段赋值给request,以供后续操作使用
#正确就返回用户和token
return (token_obj.user, token)
编写权限类需要继承rest_framework中的from rest_framework.permissions import BasePermission
权限基类, 需要实现has_permission
方法。
class MyPermission(BasePermission):
# 这是一个判断用户权限的权限类
message = '该章节为vip章节'
def has_permission(self, request, view):
section_id = int(view.kwargs.get('id')) if 'id' in view.kwargs else None
if not section_id:
return True
# section是小说章节的model
section = models.Section.objects.filter(id=section_id).first()
if not section:
return True
# 用户的type属性1代表普通用户,2代表VIP;
# 章节的is_vip属性1代表普通章节,2代表vip章节
if request._request.user.type != 1 or section.is_vip != 2:
return True
# print(request._request.user.type)
# print(type(request._request.user.type))
return False
简单的节流可以使用rest_framework中的
from rest_framework.throttling import SimpleRateThrottle
但是需要设置scope
属性, 可以设置在节流类中,也可以设置在setting中。
例:
REST_FRAMEWORK = {
···
'DEFAULT_THROTTLE_RATES': {'unlogin': '20/m'},
}
# s:秒,m:分,h:时,d:天
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
import time
# 自定义节流类
class VisitThrottle(BaseThrottle):
RECORD_VISITS = {}
def __init__(self):
self.history = []
def allow_request(self, request, view):
ip_addr = request._request.META.get('REMOTE_ADDR')
key = ip_addr
currenttime = time.time()
if key not in self.RECORD_VISITS.keys():
self.RECORD_VISITS[key] = [currenttime,]
return True
visit_history = self.RECORD_VISITS.get(key)
self.history = visit_history
while visit_history and visit_history[-1] < currenttime - 60:
visit_history.pop()
if len(visit_history) < 5:
visit_history.insert(0, currenttime)
return True
else:
return False
# return True
def wait(self):
first_time = self.history[-1]
return 60 - (time.time() - first_time)
# 自带的节流类
class MySimpleRateThrottle(SimpleRateThrottle):
scope = 'unlogin'
def get_cache_key(self, request, view):
# 更具IP或者用户表示获取用户的访问记录
return self.get_ident(request)
raise NotImplementedError('.get_cache_key() must be overridden')
from rest_framework.versioning import URLPathVersioning
导入可直接使用,也可以配置在setting中,在全局使用版本控制
REST_FRAMEWORK = {
# 全局使用版本控制时配置
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
# 以下三个配置可以自定义, 但url中 param关键字必须与 VERSION_PARAM 相同
'ALLOWED_VERSIONS': ['v1', 'v2', 'v3'],
'VERSION_PARAM': 'version',
'DEFAULT_VERSION': 'v1',
}
url中的写法:
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 版本控制在url中的使用
url(r'^api/(?P[v1|v2]+)/' , include('api_v1.urls')),
]
post请求时可能会接受到字典类型的数据,或者json类型的数据
取post请求的数据时,request.POST不一定能取到数据,request.body一定能取到。
解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己想要的数据类型的过程.
request.data
# 可以获取解析之后的数据
序列化有两大功能:请求数据的验证,
- 对queryset的序列化
- 创建URL
from rest_framework import serializers
导入
编写序列化类继承serializers.Serializer与继承serializers.ModelSerializer的区别在于继承serializers.ModelSerializer
不需要指定每个需要返回的字段。
下面列举两个例子。
继承serializers.Serializer
from rest_framework import serializers
class UserInfoSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
继承serializers.ModelSerializer
from rest_framework import serializers
from . import models
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
# 需要序列化的模型类
model = models.UserInfo
fields = ["username", "password"]
UserInfoSerializer在views中的使用
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.all()
ser = UserInfoSerializer(instance=roles, many=True)
import json
return HttpResponse(json.dumps(ser.data))
分页共有PageNumberPagination, LimitOffsetPagination, CursorPagination,访问时需要传入的参数不相同
class MyPageNumberPagination(PageNumberPagination):
#每页显示多少个
page_size = 3
#默认每页显示3个,可以通过传入pager1/?page=2&size=4,改变默认每页显示的个数
page_size_query_param = "size"
#最大页数不超过10
max_page_size = 10
#获取页码数的
page_query_param = "page"
class MyLimitOffsetPagination(LimitOffsetPagination):
#默认显示的个数
default_limit = 2
#当前的位置
offset_query_param = "offset"
#通过limit改变默认显示的个数
limit_query_param = "limit"
#一页最多显示的个数
max_limit = 10
#自定义分页类3 (加密分页)
class MyCursorPagination(CursorPagination):
cursor_query_param = "cursor"
page_size = 2 #每页显示2个数据
ordering = 'id' #排序
page_size_query_param = None
max_page_size = None
在视图中的使用
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
#获取所有数据
roles = models.Role.objects.all()
#创建分页对象
pg = 分页类的类名()
#获取分页的数据
page_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
#对数据进行序列化
ser = PagerSerialiser(instance=page_roles,many=True)
return Response(ser.data)