drf-day5——权限,频率,异常处理
作业:
1 视图类继承GenericAPIView,get方法,post方法,用的序列化类不一样
# 1 路由ulrs.py:
from app01 import views
urlpatterns = [
path('books/', views.BookView.as_view()),
]
# 2 视图views.py
from app01.ser import GetBookSerializer, CreateBookSerializer
from rest_framework.exceptions import MethodNotAllowed
from rest_framework.response import Response
from app01.models import Book
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
queryset = Book.objects
def get_serializer_class(self):
if self.request.method == 'GET':
return GetBookSerializer
elif self.request.method == 'POST':
return CreateBookSerializer
else:
raise MethodNotAllowed(self.request.method)
def get(self, request):
book_list = self.get_queryset()
book_ser = self.get_serializer(book_list, many=True)
return Response(book_ser.data)
def post(self, request):
book_ser = self.get_serializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({'status': 101, 'msg': book_ser.errors})
# 3 序列化类
class CreateBookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=8, min_length=2)
price = serializers.DecimalField(max_digits=8, decimal_places=2)
publish = serializers.CharField(max_length=18, min_length=4)
def validate_name(self, data):
if 'xxx' in data or 'sb' in data:
raise ValidationError(f'创建的图书;{data},书名中有:xxx/sb 敏感词')
else:
return data
def validate(self, validate_data):
name = validate_data.get('name')
book = Book.objects.filter(name=name)
if book:
raise ValidationError(f'图书{name}已存在')
return validate_data
def create(self, validated_data):
print(type(validated_data.get('price')), validated_data.get('price'))
instance = Book.objects.create(**validated_data)
return instance
class GetBookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
数据:
效果:
1.GET获取所有图书
2 . POST创建带有敏感词的数据:
3. POST创建一本已存在的书籍
4.正常创建
2 图书一堆关联表的增删查改写完book表,author表,authordetail表,publish表,中间表
2.1 路由urls.py
from django.contrib import admin
from django.urls import path, re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 1 图书增删改查
re_path('^books/(?P<pk>\d+)',
views.BookView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
path('books/', views.BookView.as_view(actions={'post': 'create', 'get': 'list'})),
# 2 作者增删改查
re_path('^authors/(?P<pk>\d+)',
views.AuthorView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
path('authors/', views.AuthorView.as_view(actions={'post': 'create', 'get': 'list'})),
# 3 作者详情增删改查
re_path('^authordetails/(?P<pk>\d+)',
views.AuthorDetailView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
path('authordetails/', views.AuthorDetailView.as_view(actions={'post': 'create', 'get': 'list'})),
# 4 出版社表增删改查
re_path('^publishs/(?P<pk>\d+)',
views.PublishView.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
path('publishs/', views.PublishView.as_view(actions={'post': 'create', 'get': 'list'})),
]
2.2 模型表models.py
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)
authors = models.ManyToManyField(to='Author')
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, null=True)
class Author(models.Model):
name = models.CharField(max_length=16)
age = models.IntegerField()
detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
class AuthorDetail(models.Model):
phone = models.CharField(max_length=12)
addr = models.CharField(max_length=32)
class Publish(models.Model):
pub_name = models.CharField(max_length=32)
email = models.EmailField()
2.3 视图views.py
from rest_framework.response import Response
from app01.models import Book, Publish,Author,AuthorDetail
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from app01.ser import get_serializer_1
# Create your views here.
# 自定义响应
class MyResponse():
def __init__(self):
self.status = 100
self.msg = '成功'
@property
def get_dict(self):
return self.__dict__
response = MyResponse()
# 1 图书视图
class BookView(ModelViewSet):
queryset = Book.objects
def get_serializer_class(self):
return get_serializer_1('book')
def delete(self, request, pk=None):
response = MyResponse()
if not pk:
book_query = Book.objects.all()
for book in book_query:
book.authors.remove()
book_query.delete()
response.msg = '所有数据已删除'
return Response(response.get_dict)
else:
book = Book.objects.filter(pk=pk)
if not book:
response.status = 101
response.msg = f'不存在主键值为{pk}的书籍,无法删除 '
return Response(response.get_dict)
book.authors.remove()
book.delete()
response.msg = f'主键值为{pk}的书籍,已删除 '
return Response(response.get_dict)
# 2 作者视图
class AuthorView(ModelViewSet):
queryset = Author.objects
def get_serializer_class(self):
return get_serializer_1('author')
def delete(self, request, pk=None):
if not pk:
author_query = Author.objects.all()
for author in author_query:
author.book_set.all().delete()
author_query.delete()
response.msg = '所有数据已删除'
return Response(response.get_dict)
else:
author = Author.objects.filter(pk=pk)
if not author:
response.status = 101
response.msg = f'不存在主键值为{pk}的作者,无法删除 '
return Response(response.get_dict)
author.book_set.all().delete()
author.delete()
response.msg = f'主键值为{pk}的作者,已删除 '
return Response(response.get_dict)
# 3 作者详情视图
class AuthorDetailView(ModelViewSet):
queryset = AuthorDetail.objects
def get_serializer_class(self):
return get_serializer_1('authordetail')
def delete(self, request, pk=None):
if not pk:
author_detail_query = AuthorDetail.objects.all()
for detail in author_detail_query:
detail.author.delete()
author_detail_query.delete()
response.msg = '所有数据已删除'
return Response(response.get_dict)
else:
detail = AuthorDetail.objects.filter(pk=pk)
if not detail:
response.status = 101
response.msg = f'不存在主键值为{pk}的作者详情,无法删除 '
return Response(response.get_dict)
detail.author.delete()
detail.delete()
response.msg = f'主键值为{pk}的作者详情,已删除 '
return Response(response.get_dict)
# 3 出版社视图
class PublishView(ModelViewSet):
queryset = Publish.objects
def get_serializer_class(self):
return get_serializer_1('publish')
def delete(self, request, pk=None):
if not pk:
publish_query = Publish.objects.all()
for publish in publish_query:
publish.book_set.all().delete()
publish_query.delete()
response.msg = '所有数据已删除'
return Response(response.get_dict)
else:
publish = Publish.objects.filter(pk=pk)
if not publish:
response.status = 101
response.msg = f'不存在主键值为{pk}的出版社,无法删除 '
return Response(response.get_dict)
publish.book_set.all().delete()
publish.delete()
response.msg = f'主键值为{pk}的出版社,已删除 '
return Response(response.get_dict)
2.4 序列化 器文件ser.py
from rest_framework import serializers
from app01.models import Book, Publish, AuthorDetail, Author
from rest_framework.exceptions import ValidationError
# 1.书籍序列化类
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=32, min_length=2)
price = serializers.DecimalField(max_digits=8, decimal_places=2)
publish = serializers.CharField(source='publish.pub_name', read_only=True)
authors = serializers.SerializerMethodField(read_only=True)
authors_id = serializers.ListField(write_only=True)
publish_id = serializers.IntegerField(write_only=True)
def get_authors(self, instance):
authors = instance.authors.all()
l1 = []
for author in authors:
l1.append({'name': author.name, 'age': author.age})
return l1
def create(self, validated_data):
title = validated_data.get('title')
price = validated_data.get('price')
publish_id = validated_data.get('publish_id')
authors_id = validated_data.get('authors_id')
instance = Book.objects.create(title=title,
price=price,
publish_id=publish_id)
authors_id_list = [int(x) for x in authors_id]
for i in authors_id_list:
instance.authors.add(i)
return instance
def update(self, instance, validated_data):
instance.title = validated_data.get('title')
instance.price = validated_data.get('price')
instance.publish_id = validated_data.get('publish_id')
authors_id_list = validated_data.get('authors_id')
authors_id_list = [int(x) for x in authors_id_list]
instance.authors.set(authors_id_list)
instance.save()
return instance
def validate_authors_id(self, data):
exist_author = list(Author.objects.all().values('id'))
exist_author = [x.get('id') for x in exist_author]
if len(data) == 1:
data_1 = data
else:
data_1 = sorted(data)
print(f'存在的作者id:{exist_author}')
print(f'上传的作者id:{data_1}')
if not set(data_1) <= set(exist_author):
raise ValidationError('上传的主键没有对应的作者')
return data
def validate_publish_id(self, data):
exist_publish = Publish.objects.all().values('id')
exist_publish = [x.get('id') for x in exist_publish]
print(f'存在的出版社id:{exist_publish}')
print(f'上传的出版社id:{data}')
if data not in exist_publish:
raise ValidationError('上传的主键没有对应的出版社')
return data
# 2.作者序列化类
class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(max_length=16, min_length=2)
age = serializers.IntegerField()
detail = serializers.SerializerMethodField(read_only=True)
detail_id = serializers.IntegerField(write_only=True)
def get_detail(self, instance):
print(instance)
return {'电话': instance.detail.phone, '居住城市': instance.detail.addr}
def create(self, validated_data):
name = validated_data.get('name')
age = validated_data.get('age')
detail_id = validated_data.get('detail_id')
instance = Author.objects.create(name=name,
age=age,
detail_id=detail_id)
return instance
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
instance.age = validated_data.get('age')
instance.detail_id = validated_data.get('detail_id')
instance.save()
return instance
def validate_detail_id(self, data):
detail = AuthorDetail.objects.filter(pk=data)
if not detail:
raise ValidationError(f'上传的详情id【{data}】没有对应的详情')
else:
author = Author.objects.filter(detail=data).first()
if author:
raise ValidationError(f'上传的详情id【{data}】已存在作者【{author.name}】,请绑定别的作者详情')
return data
def validate_name(self, data):
author = Author.objects.filter(name=data)
if author:
raise ValidationError(f'作者【{data}】已存在')
return data
# 3.作者详情序列化类
class AuthorDetailSerializer(serializers.ModelSerializer):
class Meta:
model = AuthorDetail
fields = '__all__'
# 4.出版社序列化类
class PublishSerializer(serializers.ModelSerializer):
class Meta:
model = Publish
fields = '__all__'
# 根据不同的视图获取不同的序列化类方法
def get_serializer_1(query_class):
if query_class == 'book':
return BookSerializer
elif query_class == 'author':
return AuthorSerializer
elif query_class == 'publish':
return PublishSerializer
else:
return AuthorDetailSerializer
2.5 数据:
作者详情:
作者:
出版社:
图书:
图书与作者对应关系:
2.6 测试效果:
2.6.1 图书增删改查:
获取所有图书:
获取指定主键的图书:
修改指定主键的图书:
新增书籍:
删除指定主键的书籍:
再次获取刚刚删除的书籍,已不存在:
2.6.2 作者增删改查
获取所有作者:
获取单个作者:
修改:
删除:
再次获取刚刚删除的作者,已不存在
新增:
2.6.3 作者详情增删改查
获取所有作者详情:
获取单个作者详情:
修改:
删除:
再次获取刚刚删除的作者详情以不存在:
新增:
2.6.4 出版社增删改查
获取所有出版社:
获取单个:
修改:
删除:
再次获取刚刚删除的出版社,已不存在:
新增:
3 过滤,排序,认证,权限,频率,异常处理
# urls.py
from app01 import views
urlpatterns = [
path(r'login/', views.LoginView.as_view()),
path(r'test1/', views.TestView.as_view()),
path(r'test3/', views.TestView3.as_view()),
path(r'test4/', views.TestView4.as_view()),
path(r'test5/', views.TestView5.as_view()),
path(r'test6/', views.Book2View.as_view()),
]
# views.py
from django.shortcuts import render
from app01 import app_auth
from rest_framework.views import APIView
from rest_framework.response import Response
import uuid
from app01 import models
from rest_framework.permissions import IsAdminUser
from rest_framework.authentication import SessionAuthentication
from app01.app_auth import MyAuthentication
from app01.app_auth import UserPermission
# Create your views here.
class LoginView(APIView):
authentication_classes = []
permission_classes = []
def post(self, request):
print(1)
username = request.data.get('username')
password = request.data.get('password')
user = models.User.objects.filter(username=username, password=password)
if user:
user = user.first()
token = uuid.uuid4()
models.UserToken.objects.update_or_create(defaults={'token': token}, user=user)
return Response({'status': 100, 'msg': '登陆成功', 'token': token})
else:
return Response({'status': 101, 'msg': '用户名或密码错误'})
class TestView(APIView):
authentication_classes = [app_auth.MyAuthentication]
permission_classes = [app_auth.UserPermission]
def get(self, request, *args, **kwargs):
print('只有超级用户可以查看')
print('我是测试数据')
return Response('测试')
# 2 内置权限,超级管理员可以查看
class TestView3(APIView):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAdminUser]
def get(self, request):
return Response('2222,只有草鸡用户能够观看')
# 解析组件
from rest_framework.parsers import MultiPartParser
## 频率限制
from rest_framework.throttling import BaseThrottle, AnonRateThrottle, UserRateThrottle
# 3 全局未登录用户访问频率校验
class TestView4(APIView):
authentication_classes = [MyAuthentication]
permission_classes = [UserPermission]
throttle_classes = [AnonRateThrottle]
def get(self, request):
return Response('我是未登录的用户')
# 4 登陆用户每分钟访问10次,未登录用户访问五次
class TestView5(APIView):
# authentication_classes = [MyAuthentication]
# permission_classes = [UserPermission]
authentication_classes = [SessionAuthentication]
throttle_classes = [AnonRateThrottle, UserRateThrottle]
def get(self, request):
a = request.user
# if isinstance(a,)
from django.contrib.auth.models import AnonymousUser
print(a, type(a))
if not isinstance(a, AnonymousUser):
return Response('我是登录的用户')
else:
return Response('我是未登陆的用户')
# 排序组件的使用
from rest_framework.generics import ListAPIView
from rest_framework.filters import OrderingFilter
from app01.models import Book
from app01.ser import BookSerializer
class Book2View(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter]
ordering_fields = ('id', 'price')
# app_auth.py
from rest_framework import status
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
class MyAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.GET.get('token')
print(token)
if token:
user_token = UserToken.objects.filter(token=token).first()
print(user_token)
if user_token:
return user_token.user, token
else:
raise AuthenticationFailed('认证失败')
else:
raise AuthenticationFailed('请求中必须有token')
class UserPermission(BasePermission):
def has_permission(self, request, view):
user = request.user
if user.user_type == 1:
return True
else:
return False
from rest_framework.views import exception_handler
def my_exception_handle(exc, context):
response = exception_handler(exc, context)
# 两种情况,一个是None,drf没有处理
# response对象,django处理了,但是处理的不符合要求
print(type(exc))
if not response:
if isinstance(exc, ZeroDivisionError):
return Response(data={'status': 777, 'msg': '除以0的错误' + str(exc)}, status=status.HTTP_400_BAD_REQUEST)
return Response(data={'status': 999, 'msg': str(exc)})
else:
pass
# 全局异常处理
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
def my_exception_handler(exc, context):
response = exception_handler(exc, context)
# 两种情况,一个是None,drf没有处理
# response对象,django处理了,但是处理的不符合咱们的要求
# print(type(exc))
if not response:
if isinstance(exc, ZeroDivisionError):
return Response(data={'status': 777, 'msg': "除以0的错误" + str(exc)}, status=status.HTTP_400_BAD_REQUEST)
return Response(data={'status': 999, 'msg': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
else:
# return response
return Response(data={'status': 888, 'msg': response.data.get('detail')}, status=status.HTTP_400_BAD_REQUEST)
# 全局配置setting.py
"""
'EXCEPTION_HANDLER': 'app01.app_auth.my_exception_handler'"""
# ser.py
from rest_framework import serializers
from app01.models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'