zoukankan      html  css  js  c++  java
  • drfday5——权限,频率,异常处理

    作业:

    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__'
    
    
  • 相关阅读:
    在Linux服务器上添加ip白名单允许ssh登录访问
    crontab + shell脚本实现文件重命名
    mysql数据库提示ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
    附加题2:中文编程的发展角度
    附加题1:实体店的未来存在形式
    第八周作业
    第七周作业
    第六周作业
    第五周作业
    第四周作业
  • 原文地址:https://www.cnblogs.com/cainiaoqianxun/p/13291282.html
Copyright © 2011-2022 走看看