需求: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