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__'

数据:

image-20200712210812597

效果:

1.GET获取所有图书

image-20200712211043538

2 . POST创建带有敏感词的数据:

image-202007122130475063. POST创建一本已存在的书籍

image-20200712213240514

4.正常创建

image-20200712213437512

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

image-20200712214126109

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

image-20200712221906294

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 数据:

作者详情:

image-20200713004227227

作者:

image-20200712223857651

出版社:

image-20200712223930804

图书:

image-20200712224015353

图书与作者对应关系:

image-20200712224100851

2.6 测试效果:

2.6.1 图书增删改查:

获取所有图书:

image-20200712224643280

获取指定主键的图书:

image-20200712224751359

修改指定主键的图书:

image-20200712225433618

新增书籍:

image-20200713002737758

删除指定主键的书籍:

image-20200713002924052

再次获取刚刚删除的书籍,已不存在:

image-20200713003318666

2.6.2 作者增删改查

获取所有作者:

image-20200713003823711

获取单个作者:

image-20200713003917516

修改

image-20200713004326713

删除:

image-20200713004509241

再次获取刚刚删除的作者,已不存在

image-20200713004620892

新增:

image-20200713004741331

2.6.3 作者详情增删改查

获取所有作者详情:

image-20200713005051652

获取单个作者详情:

image-20200713005226751

修改:

image-20200713005547203

删除:

image-20200713005709699

再次获取刚刚删除的作者详情以不存在:

image-20200713005913544

新增:

image-20200713005805048

2.6.4 出版社增删改查

获取所有出版社:

image-20200713010205723

获取单个

image-20200713010356812

修改:

image-20200713010624141

删除:

image-20200713010839673

再次获取刚刚删除的出版社,已不存在:

image-20200713010925601

新增:

image-20200713011055664

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__'

posted @ 2020-07-13 01:50  风起千寻  阅读(155)  评论(0编辑  收藏  举报