需求:1,一个表内数据的增删改查
2,指定用户的表内数据增删改查
3,获取表内按时间排序最后一个对象
restframework 中的 ModelViewSet 只能解决需求一,如果我每个表中的数据关联一个用户表,每次获取数据都要筛选获取某个用户的所有数据,那么就不能用了,所以要自己定制视图功能,满足2,3需求
一。models类
解释:每个用户有唯一一个token,并且有多个备忘录的数据
class Users(models.Model): # 用户表
user_type_choice = (
(1, '普通用户'),
(2, 'VIP'),
(3, 'SVIP'),
)
userType = models.IntegerField(choices=user_type_choice, default=1)
open_id = models.CharField(max_length=255, unique=True, verbose_name='用户名')
nickName = models.CharField(max_length=64, null=True, verbose_name='暱称')
createTime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updateTime = models.DateTimeField(auto_now=True, verbose_name='更新时间')
is_active = models.BooleanField(default=True, verbose_name='激活状态')
class Meta:
verbose_name = '用户表'
verbose_name_plural = verbose_name
class UserToken(models.Model): # token表
user = models.OneToOneField('Users', on_delete=models.CASCADE)
token = models.CharField(max_length=64, verbose_name='用户的token')
session_key = models.CharField(max_length=64)
createTime = models.DateTimeField(auto_now_add=True)
editTime = models.DateTimeField(auto_now=True)
class Memory(models.Model):
content = models.TextField()
createTime = models.DateTimeField(auto_now_add=True)
editTime = models.DateTimeField(auto_now=True)
user = models.ForeignKey('Users', on_delete=models.CASCADE, default='1')
class Meta:
verbose_name = '备忘录'
verbose_name_plural = verbose_name
二。序列化类
from rest_framework import serializers
from .. import models
class MemorySerializer(serializers.ModelSerializer):
class Meta:
model = models.Memory
fields = '__all__'
三。认证类
解释:通过获取请求头的认证 token ,去 token 表中去认证,返回认证后对应的 user 对象(因为 token 表和 user 表是一一对应的)
from rest_framework.authentication import BaseAuthentication
from ..models import UserToken
from rest_framework import exceptions
def md5(user):
import hashlib
import time
ctime = str(time.time())
m = hashlib.md5(bytes(user, encoding='utf-8'))
m.update(bytes(ctime, encoding='utf-8'))
return m.hexdigest()
class Authtication(BaseAuthentication):
def authenticate(self, request):
token = request._request.META.get('HTTP_AUTHORIZATION') #前端通过请求头发送,所以通过请求头获取
token_obj = UserToken.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed("用户认证失败")
return token_obj.user, token
def authenticate_header(self, request):
pass
四。url映射
解释:本来是两个,因为想增加一个按时间查询最近的数据,所以增加了一个
urlpatterns = [
url('^api/v1/memorys/$', views.Memorys.as_view({'get':'list', 'post':'create'}), name='memorys'),
url('^api/v1/memorys/last/$', views.Memorys.as_view({'get':'retrieve_last'}), name='memorys1'),
url('^api/v1/memorys/(?P<pk>\d+)/$', views.Memorys.as_view({'get':'retrieve', 'delete':'destroy', 'put':'update', 'patch':'partial_update'}), name='memorys2'),
]
五。视图类
解释:
1. 这里继承并修改了增删改查的类,其中 request.user 对象是认证时候返回的,获取id,然后筛选 queryset,得到的 queryset 只包含认证后的用户, 然后把筛选后的 queryset 赋值给 self.queryset, 之后执行父类的 list 函数就行了。所以我们的任务是修改 self.queryset ,让它只包含当前用户的数据。
2. createView 类是要增加的 QueryDict 中没有用户id,所以要添加的话会出现错误。但是现在 QueryDict 是不能修改的,所以通过 request.data._mutable = True 让它变的可以修改,因为是个字典,所以用 request.data['user'] = request.user.id 直接赋值就好了,之后就调用父类的增加方法来增加。这里的任务主要是修改 QueryDict, 让它包含用户id。
3. 第二个需求在 RetrieveView 类中,通过 instance = queryset.filter(user_id=userid).latest('editTime') 获取最后一个数据,然后让它序列化,返回就行了,这里不需要调用父类,因为没有多少操作。
class ListView(ListModelMixin):
def list(self, request, *args, **kwargs):
try:
# 这里改变的是self.queryset,让他按照我们的意思去筛选
userid = request.user.id
queryset = self.filter_queryset(self.get_queryset())
self.queryset = queryset.filter(user_id=userid)
response = super().list(request, *args, **kwargs)
return Response({'code':200, 'data': response.data, 'msg':'获取成功'})
except:
return Response({'code':500, 'msg':'获取失败'})
class createView(CreateModelMixin):
def create(self, request, *args, **kwargs):
try:
# 添加的数据里面要加入用户的id
request.data._mutable = True # 把 QueryDict 变为可以变的
request.data['user'] = request.user.id # 添加当前验证的用户id
response = super().create(request, *args, **kwargs)
return Response({'code':200, 'data': response.data, 'msg':'创建成功'})
except Exception as e:
print(e)
return Response({'code':500, 'msg':'创建失败', 'data':str(e)})
class RetrieveView(RetrieveModelMixin):
def retrieve(self, request, *args, **kwargs):
try:
# 这里改变的是self.queryset,让他按照我们的意思去筛选
userid = request.user.id
queryset = self.filter_queryset(self.get_queryset())
self.queryset = queryset.filter(user_id=userid)
response = super().retrieve(request, *args, **kwargs)
return Response({'code':200, 'data': response.data, 'msg':'获取成功'})
except Exception as e:
print(e)
return Response({'code':500, 'msg':'获取失败', 'data':str(e)})
def retrieve_last(self, request, *args, **kwargs):
try:
# 这里改变的是self.queryset,让他按照我们的意思去筛选
userid = request.user.id
queryset = self.filter_queryset(self.get_queryset())
instance = queryset.filter(user_id=userid).latest('editTime')
serializer = self.get_serializer(instance)
return Response({'code':200, 'data': serializer.data, 'msg':'获取成功'})
except Exception as e:
print(e)
return Response({'code': 500, 'msg': '获取失败', 'data': str(e)})
class UpdateView(UpdateModelMixin):
def update(self, request, *args, **kwargs):
try:
# 这里改变的是self.queryset,让他按照我们的意思去筛选
userid = request.user.id
queryset = self.filter_queryset(self.get_queryset())
self.queryset = queryset.filter(user_id=userid)
response = super().update(request, *args, **kwargs)
return Response({'code':200, 'data': response.data, 'msg':'修改成功'})
except Exception as e:
print(e)
return Response({'code':500, 'msg':'修改失败', 'data':str(e)})
class DestroyView(DestroyModelMixin):
def destroy(self, request, *args, **kwargs):
try:
# 这里改变的是self.queryset,让他按照我们的意思去筛选
userid = request.user.id
queryset = self.filter_queryset(self.get_queryset())
self.queryset = queryset.filter(user_id=userid)
response = super().destroy(request, *args, **kwargs)
return Response({'code':200, 'data': response.data, 'msg': '删除成功'})
except Exception as e:
print(e)
return Response({'code':500, 'msg':'删除失败', 'data':str(e)})
class myViewSet(ListView,
createView,
RetrieveView,
UpdateView,
DestroyView,
GenericViewSet):
pass
六。使用
解释:在视图函数中,继承我们定制的类,然后只添加这行代码,就可以实现开头那三个需求了
from .utils.myAppViewSet import myViewSet
class Memorys(myViewSet):
"""
备忘录
"""
queryset = models.Memory.objects.all().order_by("-editTime")
serializer_class = myAppSerializer.MemorySerializer