普通的开发方式(前后端放在一起写)
前后端分离(Ajax)
后端为前端提供URL(API/接口的开发)
注: 返回HttpResponse(render和redirect就用不上)
举例:第一个简单的接口(不依赖任何工具)
通过字符串映射object对象的方法或者属性
在我们做接口自动化的时候,需要通过不同的请求方式,调用不同的函数
from rest_framework.views import APIView
我们来看一段伪代码,MyClassView继承了APIView就有了APIView的功能
class APIView(View):
pass
class MyClassView(APIView):
pass
from django.db import models
# Create your models here.
class UserInfo(models.Model):
"""用户表"""
user_type_choices = (
(1, "普通用户"),
(2, "VIP"),
(3, "SVIP")
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=64)
class UserToken(models.Model):
"""token表"""
user = models.OneToOneField(to="UserInfo")
token = models.CharField(max_length=64)
#创建md5函数 继承token模型的user对象
def md5(user):
#导入哈希加密
import hashlib
#导入时间
import time
#变量名ctime 接收现在的时间转为字符str类型
ctime = str(time.time())
#将user对象转为字节并用哈希md5加密 变为16进制字符
m = hashlib.md5(bytes(user, encoding="utf-8"))
#修改并加入时间戳
m.update(bytes(ctime, encoding="utf-8"))
#并返回
return m.hexdigest()
import hashlib
import time
#创建token
def createToken(user):
md5 = hashlib.md5()
#修改账户名字节并加入时间戳 和utf-8(时间戳)
md5.update(bytes(user + str(time.time()), encoding='utf-8'))
#返回摘要,作为十六进制数据字符串值
token = md5.hexdigest()
#返回给token
return token
#设置登录类
class AuthView(APIView):
# 提交我们用 内置源码的post请求
def post(self,request,*args,**kwargs):
# 设置状态码
ret = {"state_code": 1000, "msg": None}
#判断异常
try:
#原生_request改写request方法 获取前端表单里面的用户名
username = request._request.POST.get("username")
#获取前端表单里面的密码
password = request._request.POST.get("password")
# 用变量名obj 接收数据库里的信息并进行 前端表单与数据库的匹配
obj = models.UserInfo.object.filter(username=username,password=password).first()
#然后进行判断 如果匹配的内容不对
if not obj:
# 就发送状态码 1001
ret["state_code"] = 1001
# 用户名或者 密码错误
ret["msg"] = "用户名或者密码错误"
# 否则为登陆用户创建一个token
token = md5(username)
# 存到数据库 存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=obj, defaults={"token": token})
# 发送状态码
ret["token"] = token
#告知请求成功
ret["msg"] = "请求成功"
#判断异常
except Exception as e:
# 发送状态码
ret["state_code"] = 1002
# 请求异常
ret["msg"] = "请求异常"
#返回JsonResponse
return JsonResponse(ret)
from rest_framework.authentication import BaseAuthentication
from myapp import models
from rest_framework import exceptions
#创建一个我的认证类 继承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)
# 如果pass 就调用原有的方法
class MyAuthtication_None(BaseAuthentication):
def authenticate(self, request):
pass
#创建 我的Authtication
class MyAuthtication(BaseAuthentication):
#使用authenticate方法
def authenticate(self, request):
#获取token
token = request._request.GET.get('token')
#进行判断 如果不是token
if not token:
#返回元组验证失败
raise AuthenticationFailed('未登录')
#否则
else:
#在数据库UserToken表中进行比对 从第一个开始
usertoken = UserToken.objects.filter(token=token).first()
#如果是usertoken
if usertoken:
#就返回用户的token
return (usertoken.user, token)
#否则验证失败
else:
raise AuthenticationFailed('验证失败')
authentication_classes = []
如果不在settings配置全局设置 就要单独写这个进行验证 所以 我们要先在view中导入
from myapp.myutils.throttle import MyAuthtication
#将登录类里写入 进行认证
authentication_classes = [MyAuthtication]
from django.conf.urls import url
from django.contrib import admin
from myapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/v1/auth/$', views.AuthView.as_view()),
]
def authenticate(self, request):
token = request._request.GET.get("token")
在class类里面的(APIView)在pycharm按住ctrl点击APIView,然后向下翻找到
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
#进这里 #点击这个
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
try:
#进这里 #点击这个
self.initial(request, *args, **kwargs)
# 代表 认证组件
self.perform_authentication(request)
# 代表 权限组件
self.check_permissions(request)
# 代表 限流组件
self.check_throttles(request)
# 创建一个ORDER_DICT字典 输入一些信息
ORDER_DICT = {
1: {
"name": "张三",
"age": 18,
"gender": "男",
"orders": [{
"name": "娃娃",
"price": 1000
}]
},
2: {
"name": "李四",
"age": 20,
"gender": "女",
"orders": [{
"name": "你猜",
"price": 1200
}]
},
}
# 创建OrderView类 继承APIView
class OrderView(APIView):
"""
订单相关业务
"""
# 设置get请求
def get(self, request, *args, **kwargs):
# 状态码
ret = {"state_code": 1000, "msg": None, "data": None}
# 判断异常
try:
# 如果正确 就返回字典的数据
ret['data'] = ORDER_DICT
# 错误就返回状态码
except Exception as e:
pass
return JsonResponse(ret)
from django.conf.urls import url
from django.contrib import admin
from myapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 认证接口
url(r'^api/v1/auth/$', views.AuthView.as_view()),
# 订单接口
url(r'^api/v1/order/$', views.OrderView.as_view()),
]
# 在rest_framework.permissions 导入BasePermission方法
from rest_framework.permissions import BasePermission
# 创建SVIPPermission类 继承BasePermission方法
class SVIPPermission(BasePermission):
# 状态码
message = "无权访问"
# 重写 has_permission方法
def has_permission(self, request, view):
# 如果 用户 user_type 类型 不等于3
if request.user.user_type != 3:
# 就无法访问
return False
# 否则可以访问
return True
“”"
Allows access only to admin users.
“”"
# 导入的这个负责 认证
# 在 我的应用中从 我的组件包中的 auth 导入MyAuthtication类
from myapp.myutils.auth import MyAuthtication
# 导入的这个负责 权限
# 在 我的应用中从 我的组件包中的 permission 导入SVIPPermission类
from myapp.myutils.permission import SVIPPermission
class OrderView(APIView):
"""
订单相关业务
"""
authentication_classes = []
permission_classes = []
http://127.0.0.1:8000/api/v1/order/?token= 后面放你从文本复制的token
首先 在我的应用组件包创建限流 throttle.py文件 在里面设置我们的限流方法
# 从rest_framework.throttling 导入BaseThrottle方法
from rest_framework.throttling import BaseThrottle
# 导入时间
import time
# 设置一个空字典
HISTORY_DICT = {}
# 写MyThrottle类继承 BaseThrottle方法
class MyThrottle(BaseThrottle):
# 初始化self.history
def __init__(self):
self.history = None
# 重写allow_request方法
def allow_request(self, request, view):
# 获取 (META["REMOTE_ADDR"])当前用户的ip
ip_addr = request._request.META["REMOTE_ADDR"]
# 获取当前时间
ctime = time.time()
# 如果 用户当前的ip 不在空字典中
if ip_addr not in HISTORY_DICT:
# 那么就把当前ip赋予一个 现在的时间
HISTORY_DICT[ip_addr] = [ctime, ]
return True
# 如果这条ip在空字典中
history = HISTORY_DICT[ip_addr]
# 初始化的self.history
self.history = history
# 在空字典的ip 找到最后一个ip 是最早的时间那个 小于现在时间的60秒
while history and history[-1] < ctime - 60:
# 就删除最后一个
history.pop()
# 如果ip记录 小于3次
if len(history) < 3:
# 就添加ip 并赋予现在的时间
history.insert(0, ctime)
return True
# 如果访问返回True表示可以继续往下走,False被限制访问
return False
def wait(self):
# 这里是应该返回 剩余的 等待时间
# 要先拿到历史记录
# 当前时间
ctime = time.time()
return 60 - (ctime - self.history[-1])
# 在我的组件包导入 MyThrottle方法
from myapp.myutils.throttle import MyThrottle
class StudentView(APIView):
authentication_classes = [MyAuthtication]
permission_classes = [SVIPPermission]
# 开启这个代表自己设置的限流
throttle_classes = [MyThrottle]
def get(self, request, *args, **kwargs):
# 获取当前的ip
ip = request.META.get('REMOTE_ADDR')
# 并返回当前的ip
return JsonResponse({'ip': ip})
http://127.0.0.1:8000/api/v1/thor/?token=写入你当前获取的token
# 从rest_framework.throttling 导入SimpleRateThrottle方法
from rest_framework.throttling import SimpleRateThrottle
# 如果我们要使用 内置的限流类
# SimpleRateThrottle 内置的 写好的 限流组件
class MyThrottle2(SimpleRateThrottle):
scope = "myscope"
# 缓存配置
def get_cache_key(self, request, view):
return self.get_ident(request)
# 订单登录
class UserThrottle(SimpleRateThrottle):
scope = "user_scope"
def get_cache_key(self, request, view):
return request.user.username
# QueryParameterVersioning点击这个里面会有个这种方法
from rest_framework.versioning import QueryParameterVersioning
REST_FRAMEWORK = {
"DEFAULT_VERSION": "v1",# 默认版本
"ALLOWED_VERSIONS": ["v1", "v2"],# 被允许访问的版本
}
# 从rest_framework.versioning 导入 URLPathVersioning
from rest_framework.versioning import URLPathVersioning
# 设计一个类
class UsersView(APIView):
versioning_class = URLPathVersioning # 调入版本这个方法
def get(self, request, *args, **kwargs):
# 获取版本
v = request.version
u1 = request.versioning_scheme.reverse(viewname="user",request=request)
print(u1)
return HttpResponse(v)
点击这个URLPathVersioning看源码
from rest_framework.versioning import URLPathVersioning
from django.conf.urls import url
from .views import UsersView
# http://127.0.0.1:8000/api/v1/users/ # 推荐
# http://127.0.0.1:8000/api/users/?verison=v1 第一种获取版本的方式 也有公司这种
urlpatterns = [
# url(r'^users/$', UsersView.as_view())
# 并修改成这种形似
url(r'^(?P[v1|v2]+)/users/' , UsersView.as_view())
]
url(r'^(?P[v1|v2]+)/users/' , views.UsersView.as_view(),name='user')
http://127.0.0.1:8000/api/v1/users/
url(r'^(?P[v1|v2]+)/roles/$' , views.RolesView.as_view()),
class RolesView(APIView): # 创建类 继承APIView
def get(self,request,*args,**kwargs): # 发起get请求
roles = models.Role.objects.all().values('id','title') # 获取Role模型里面的id和title字段
roles = list(roles) # 将 获取的数据转换成列表
import json # 导入json
ret = json.dumps(roles) # 将queryset数据转换成 json数据
return HttpResponse(ret) # 利用HttpResponse 页面展示出来
from rest_framework import serializers
class RolesSerializer(serializers,Serializer):
# 变量名要和数据的字段一致
title = serializers.CharField()
class RolesView(APIView):
def get(self, request, *args, **kwargs):
roles = models.Role.objects.all()
ser = RolesSerializer(instance=roles, many=True) # 调用RolesSerializer类 instance=roles实例获取到的数据 many=True
import json
return HttpResponse(json.dumps(ser.data)) # 数据都在data中
url(r'^(?P[v1|v2]+)/userinfo/$' , views.UserInfoView.as_view())
class UserInfoSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(users, many=True)
import json
return HttpResponse(json.dumps(ser.data))
class UserInfoSerializer(serializers.Serializer):
user_type = serializers.IntegerField()
class UserInfoSerializer(serializers.Serializer):
xxxx = serializers.IntegerField(source='user_type') # 将user_type字段显示
oooo = serializers.CharField(source='get_user_type_display') # 获取user_type字段的中文
username = serializers.CharField()
password = serializers.CharField()
from django.db import models
# Create your models here.
class UserGroup(models.Model):
"""用户组模型"""
title = models.CharField(max_length=32, verbose_name="用户组名")
class Role(models.Model):
"""角色模型"""
title = models.CharField(max_length=32, verbose_name="角色名")
class UserInfo(models.Model):
user_type_choices = (
(1, "普通用户"),
(2, "VIP"),
(3, "SVIP")
)
user_type = models.IntegerField(choices=user_type_choices, verbose_name="用户类型")
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=256)
# 外键关系的显示 一对多的外键关系的显示
group = models.ForeignKey(UserGroup, verbose_name="所属用户组")
# 多对多关系的序列化
roles = models.ManyToManyField(Role)
class UserToken(models.Model):
user = models.OneToOneField(UserInfo)
token = models.CharField(max_length=256)
class UserInfoSerializer(serializers.Serializer):
# 获取一对多group表下的id 和 title
gp = serializers.CharField(source="group.id")
gp2 = serializers.CharField(source="group.title")
class UserInfoSerializer(serializers.Serializer):
xxxx = serializers.IntegerField(source='user_type')
oooo = serializers.CharField(source='get_user_type_display')
username = serializers.CharField()
password = serializers.CharField()
gp = serializers.CharField(source="group.id")
gp2 = serializers.CharField(source="group.title")
rls = serializers.SerializerMethodField() # 自定义显示
def get_rls(self, row): # row当前行的对象
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({
'id': item.id,
'title': item.title
})
return ret
class UserInfoSerializer2(serializers.ModelSerializer):
user_type = serializers.CharField(source='get_user_type_display')
group = serializers.CharField(source="group.title")
rls = serializers.SerializerMethodField() # 自定义显示
def get_rls(self, row): # row当前行的对象
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({
'id': item.id,
'title': item.title
})
return ret
class Meta:
model= models.UserInfo #"username","password"是UserInfo表里的 "user_type",'group','rls' 是上面获取的字段
fields = ("username","password","user_type",'group','rls')
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
# 1、要从数据库里面 取出数据 罗列出所有用户名和密码
users = models.UserInfo.objects.all()
# 2、进行序列化 (序列化的组件)
ser = UserInfoSerializer2(instance=users, many=True)
import json
return HttpResponse(json.dumps(ser.data))
# 深度控制 解决了 正常 1对多 多对多
class UserInfoSerializer3(serializers.ModelSerializer):
user_type = serializers.CharField(source='get_user_type_display')
class Meta:
model = models.UserInfo
fields = "__all__"
# 主要这个就是深度控制
depth = 1 # 深度控制,数字越大 取层数越多 但是 效率越低
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
# 1、要从数据库里面 取出数据 罗列出所有用户名和密码
users = models.UserInfo.objects.all()
# 2、进行序列化 (序列化的组件)
ser = UserInfoSerializer3(instance=users, many=True)
import json
return HttpResponse(json.dumps(ser.data))
"""
深度控制 1句话 封装度越高(1句话) 能实现的功能就越固定 灵活性 定制性就差
"""
url(r'^(?P[v1|v2]+)/group/(?P\d+)/$' , views.GroupfoView.as_view(),name='gp')
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserGroup
fields = "__all__"
class GroupfoView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
obj = models.UserGroup.objects.filter(pk=pk).first()
import json
ser = GroupSerializer(instance=obj, many=False)
ret = json.dumps(ser.data)
return HttpResponse(ret)
class UserInfoView(APIView):
def get(self, request, *args, **kwargs):
...
ser = UserInfoSerializer(users, many=True,context={'request': request})
...
class UserInfoSerializer(serializers.ModelSerializer):
# 帮我们反向生成URL,相当于我们给了group一个id,它帮我们反向生成一个url
group = serializers.HyperlinkedIdentityField(view_name='gp')
class Meta:
model = models.UserInfo
fields = "__all__"
depth = 0
url(r'^(?P[v1|v2]+)/usergroup/$' , views.UserGroupView.as_view(), name='ugp'),
class UserGroupView(APIView):
def post(self, request, *args, **kwargs):
print(request.data)
return HttpResponse("提交数据")