Book接口

Book系列连表接口

from django.shortcuts import render

# Create your views here.
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from app01.models import Book
# from app01.ser import BookSerializers
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
# class TestView(APIView):
#     def get(self,request):
#         1/0
#         return Response({'msg':'个人中心'})
#
# class BookViewSet(ModelViewSet):
#     authentication_classes = [BasicAuthentication,]
#     queryset = Book.objects.all()
#     serializer_class = BookSerializers
    # @action(methods=['get'], detail=False)
    # def login(self, request):
    #     Book.objects.update_or_create()
    #     return Response({'msg':'登陆成功'})
    # @action(methods=['put'], detail=True)
    # def get_new_5(self, request,pk):
    #     return Response({'msg':'获取5条数据成功'})

from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly



from app01.response import APIResponse
from app01 import models
from app01 import ser as serializers
class PublishAPIView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            publish_obj = models.Publish.objects.filter(pk=pk).first()
            if not publish_obj:
                return APIResponse(1, 'pk error', http_status=400)
            publish_data = serializers.PublishModelSerializer(publish_obj).data
            return APIResponse(results=publish_data)

        publish_query = models.Publish.objects.all()
        return APIResponse(0, 'ok', data=serializers.PublishModelSerializer(publish_query, many=True).data)


class BookAPIView(APIView):
    # 单查、群查
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            if not book_obj:
                return APIResponse(1, 'pk error', http_status=400)
            book_data = serializers.BookModelSerializer(book_obj).data
            print(book_data)
            return APIResponse(data=book_data)

        book_query = models.Book.objects.filter(is_delete=False).all()

        return APIResponse(0, 'ok', data=serializers.BookModelSerializer(book_query, many=True).data)

    # 单删、群删
    def delete(self, request, *args, **kwargs):
        """
        单删:前台数据为pk,接口为 /books/(pk)/
        群删:前台数据为pks,接口为 /books/
        """
        pk = kwargs.get('pk')
        # 将单删群删逻辑整合
        if pk:  # /books/(pk)/的接口就不考虑群删,就固定为单删
            pks = [pk]
        else:
            pks = request.data.get('pks')
        # 前台数据有误(主要是群删没有提供pks)
        if not pks:
            return APIResponse(1, 'delete error', http_status=400)
        # 只要有操作受影响行,就是删除成功,反之失败
        rows = models.Book.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
        if rows:
            return APIResponse(0, 'delete ok')
        return APIResponse(1, 'delete failed')

    # 单增、群增
    def post(self, request, *args, **kwargs):
        """
        单增:前台提交字典,接口 /books/
        群增:前台提交列表套字典,接口 /books/
        """
        request_data = request.data
        if isinstance(request_data, dict):  # 单增
            book_ser = serializers.BookModelSerializer(data=request_data)
            if book_ser.is_valid():
                book_obj = book_ser.save()
                return APIResponse(data=serializers.BookModelSerializer(book_obj).data)
return APIResponse(1, msg=book_ser.errors)
elif isinstance(request_data, list) and len(request_data) != 0 :  # 群增
            book_ser = serializers.BookModelSerializer(data=request_data, many=True)
            book_ser.is_valid(raise_exception=True)
            book_obj_list = book_ser.save()
return APIResponse(data=serializers.BookModelSerializer(book_obj_list, many=True).data)
else:
return APIResponse(1, 'data error', http_status=400)

# 单整体改、群整体改
defput(self, request, *args, **kwargs):
"""
        单整体改:前台提交字典,接口 /books/(pk)/
        群整体改:前台提交列表套字典,接口 /books/,注每一个字典都可以通过pk
        """
        pk = kwargs.get('pk')
        request_data = request.data
if pk: # 单改
try:
                book_obj = models.Book.objects.get(pk=pk)
except:
return APIResponse(1, 'pk error')

# 修改和新增,都需要通过数据,数据依旧给data,修改与新增不同点,instance要被赋值为被修改对象
            book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
return APIResponse(data=serializers.BookModelSerializer(book_obj).data)
else:  # 群改
ifnot isinstance(request_data, list) or len(request_data) == 0:
return APIResponse(1, 'data error', http_status=400)

# [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
# 要考虑pk对应的对象是否被删,以及pk没有对应的对象
# 假设pk3被删,pk100没有 => [obj1] + [{...}]

# 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作
            obj_list = []
            data_list = []
for dic in request_data:
# request_data可能是list,单内部不一定是dict
try:
                    pk = dic.pop('pk')
try:
                        obj = models.Book.objects.get(pk=pk, is_delete=False)
                        obj_list.append(obj)
                        data_list.append(dic)
except:
pass
except:
return APIResponse(1, 'data error', http_status=400)

            book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True)
            book_ser.is_valid(raise_exception=True)
            book_obj_list = book_ser.save()
return APIResponse(data=serializers.BookModelSerializer(book_obj_list, many=True).data)

# 单局部改、群局部改
defpatch(self, request, *args, **kwargs):
"""
        单整体改:前台提交字典,接口 /books/(pk)/
        群整体改:前台提交列表套字典,接口 /books/,注每一个字典都可以通过pk
        """
        pk = kwargs.get('pk')
        request_data = request.data
if pk:
try:
                book_obj = models.Book.objects.get(pk=pk)
except:
return APIResponse(1, 'pk error')
# 局部修改就是在整体修改基础上设置partial=True,将所有参与反序列化字段设置为required=False
            book_ser = serializers.BookModelSerializer(instance=book_obj, data=request_data, partial=True)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
return APIResponse(data=serializers.BookModelSerializer(book_obj).data)

else:  # 群改
ifnot isinstance(request_data, list) or len(request_data) == 0:
return APIResponse(1, 'data error', http_status=400)

# [{pk:1,...}, {pk:3,...}, {pk:100,...}] => [obj1, obj3, obj100] + [{...}, {...}, {...}]
# 要考虑pk对应的对象是否被删,以及pk没有对应的对象
# 假设pk3被删,pk100没有 => [obj1] + [{...}]

# 注:一定不要在循环体中对循环对象进行增删(影响对象长度)的操作
            obj_list = []
            data_list = []
for dic in request_data:
# request_data可能是list,单内部不一定是dict
try:
                    pk = dic.pop('pk')
try:
                        obj = models.Book.objects.get(pk=pk, is_delete=False)
                        obj_list.append(obj)
                        data_list.append(dic)
except:
pass
except:
return APIResponse(1, 'data error', http_status=400)

            book_ser = serializers.BookModelSerializer(instance=obj_list, data=data_list, many=True, partial=True)
            book_ser.is_valid(raise_exception=True)
            book_obj_list = book_ser.save()
return APIResponse(data=serializers.BookModelSerializer(book_obj_list, many=True).data)

classAuthorAPIView(APIView):
defget(self,request,*args,**kwargs):
        authors=models.Author.objects.all()
        author_ser=serializers.AuthorModelSerializer(authors,many=True)
return APIResponse(data=author_ser.data)
defput(self,reuqest,*args,**kwargs):
pass
defpost(self,request,*args,**kwargs):
        author_ser=serializers.AuthorModelSerializer(data=request.data)
        author_ser.is_valid(raise_exception=True)
        author_ser.save()
return APIResponse()
defdelete(self,request,*args,**kwargs):
pass
views.py
from rest_framework import serializers
from app01 import models
class BookListSerializer(serializers.ListSerializer):
    # 1、create方法父级ListSerializer已经提供了
    # def create(self, validated_data):
    #     # 通过self.child来访问绑定的ModelSerializer
    #     print(self.child)
    #     raise Exception('我不提供')

    # 2、父级ListSerializer没有通过update方法的实现体,需要自己重写
    def update(self, instance, validated_data):
        # print(instance)
        # print(validated_data)
        return [
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
        ]



class BookModelSerializer(serializers.ModelSerializer):
    # 通过BookModelSerializer.Meta.list_serializer_class来访问绑定的ListSerializer
    class Meta:
        # 关联ListSerializer完成群增群改
        list_serializer_class = BookListSerializer

        model = models.Book
        # fields = ('name', 'price', 'publish', 'authors')
        # fields = ('name', 'price', 'publish_name', 'author_list')

        # 了解
        # fields = '__all__'
        # exclude = ('id', )
        # depth = 1

        # 序列化与反序列化整合
        fields = ('name', 'price', 'publish_name', 'author_list', 'publish', 'authors')
        extra_kwargs = {
            'publish': {
                'write_only': True
            },
            'authors': {
                'write_only': True
            }
        }




# 前提:如果只有查需求的接口,自定义深度还可以用子序列化方式完成
class PublishModelSerializer(serializers.ModelSerializer):
    # 子序列化都是提供给外键(正向方向)完成深度查询的,外键数据是唯一:many=False;不唯一:many=True
    # 注:只能参与序列化,且反序列化不能写(反序列化外键字段会抛异常)
    books = BookModelSerializer(many=True)
    class Meta:
        model = models.Publish
        fields = ('name', 'address', 'books')

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Author
        fields=('name','sex','mobile','mobile_in')
        extra_kwargs={
            'mobile':{
                'read_only': True
            },
        }

    mobile_in=serializers.CharField(write_only=True)
    # def validate_mobile_in(self, data):
    #     print(data)
    #     return data


    def create(self, validated_data):
        print(validated_data)
        mobile=validated_data.pop('mobile_in')
        author=models.Author.objects.create(**validated_data)
        authordetail=models.AuthorDetail.objects.create(mobile=mobile,author=author)
        return author
ser.py
from django.db import models



# 一、基表
# Model类的内部配置Meta类要设置abstract=True,这样的Model类就是用来作为基表

# 多表:Book,Publish,Author,AuthorDetail
class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    create_time = models.DateTimeField(auto_now_add=True)
    class Meta:
        # 基表必须设置abstract,基表就是给普通Model类继承使用的,设置了abstract就不会完成数据库迁移完成建表
        abstract = True

class Book(BaseModel):
    name = models.CharField(max_length=16)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING)
    # 重点:多对多外键实际在关系表中,ORM默认关系表中两个外键都是级联
    # ManyToManyField字段不提供设置on_delete,如果想设置关系表级联,只能手动定义关系表
    authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
        
    # 自定义连表深度,不需要反序列化,因为自定义插拔属性不参与反序列化
    @property
    def publish_name(self):
        return self.publish.name
    @property
    def author_list(self):
        temp_author_list = []
        for author in self.authors.all():
            temp_author_list.append({
                'name': author.name,
                'sex': author.get_sex_display(),
                'mobile': author.detail.mobile
            })
        return temp_author_list


class Publish(BaseModel):
    name = models.CharField(max_length=16)
    address = models.CharField(max_length=64)

class Author(BaseModel):
    name = models.CharField(max_length=16)
    sex = models.IntegerField(choices=[(0, ''),(1, '')], default=0)

class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11)
    # 有作者可以没有详情,删除作者,详情一定会被级联删除
    # 外键字段为正向查询字段,related_name是反向查询字段
    author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)

# 二、表断关联
# 1、表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
# 2、断关联后不会影响数据库查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
# 3、断关联一定要通过逻辑保证表之间数据的安全
# 4、断关联
# 5、级联关系
#       作者没了,详情也没:on_delete=models.CASCADE
#       出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING
#       部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL
#       部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT


# 三、ORM外键设计
# 1、一对多:外键放在多的一方
# 2、多对多:外键放在常用的一方
# 3、一对一:外键放在不常用的一方
# 4、外键字段为正向查询字段,related_name是反向查询字段


# from django.contrib.auth.models import AbstractUser, User
# class MyUser(AbstractUser):
#     pass
models.py
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False
setting.py
path(r'publishes/', views.PublishAPIView.as_view()),
re_path(r'^publishes/(?P<pk>\d+)/$', views.PublishAPIView.as_view()),

path(r'books/', views.BookAPIView.as_view()),
re_path(r'^books/(?P<pk>\d+)/$', views.BookAPIView.as_view()),
urls.py

RBAC-基于角色的访问控制

一 什么是RBAC

RBAC  是基于角色的访问控制(Role-Based Access Control )在 RBAC  中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

应用:
# RBAC - Role-Based Access Control
# Django的 Auth组件 采用的认证规则就是RBAC

# 1)像专门做人员权限管理的系统(CRM系统)都是公司内部使用,所以数据量都在10w一下,一般效率要求也不是很高
# 2)用户量极大的常规项目,会分两种用户:前台用户(三大认证) 和 后台用户(BRAC来管理)
# 结论:没有特殊要求的Django项目可以直接采用Auth组件的权限六表,不需要自定义六个表,也不需要断开表关系,单可能需要自定义User表


前后台权限控制:
# 1)后台用户对各表操作,是后台项目完成的,我们可以直接借助admin后台项目(Django自带的)
# 2)后期也可以用xadmin框架来做后台用户权限管理

# 3)前台用户的权限管理如何处理
#   定义了一堆数据接口的视图类,不同的登录用户是否能访问这些视图类,能就代表有权限,不能就代表无权限
#   前台用户权限用drf框架的 三大认证

二 Django的内置RBAC(六表)

权限三表

权限三表

权限六表

权限六表

三 实操

from django.db import models

from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
    mobile = models.CharField(max_length=11, unique=True)

    def __str__(self):
        return self.username


class Book(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name


class Car(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name
models.py
from . import models

from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin

# 自定义User表后,admin界面管理User类
class UserAdmin(DjangoUserAdmin):
    # 添加用户课操作字段
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('username', 'password1', 'password2', 'is_staff', 'mobile', 'groups', 'user_permissions'),
        }),
    )
    # 展示用户呈现的字段
    list_display = ('username', 'mobile', 'is_staff', 'is_active', 'is_superuser')


admin.site.register(models.User, UserAdmin)
admin.site.register(models.Book)
admin.site.register(models.Car)
admin.py

这样就可以登陆到admin后台进行操作了

drfdemo

from django.contrib import admin
from django.urls import path

from app01 import views
from rest_framework.routers import DefaultRouter


router = DefaultRouter()  # 可以处理视图的路由器
router.register('books', views.BooksViewSet)  # 向路由器中注册视图集

  # 将路由器中的所以路由信息追到到django的路由列表中
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
    path('admin/', admin.site.urls),

    # path('tset/', csrf_exempt(views.test)),


    path('books1/', views.Books.as_view()),  #在这个地方应该写个函数内存地址


    path('booksapiview/', views.BooksAPIView.as_view()),  #在这个地方应该写个函数内存地址

]
#这是什么意思?两个列表相加
# router.urls  列表
urlpatterns += router.urls
urls.py
from django.db import models

# Create your models here.
class Book(models.Model):
    nid=models.AutoField(primary_key=True)
    name=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=5,decimal_places=2)
    author=models.CharField(max_length=32)
models.py
from rest_framework.serializers import ModelSerializer
from app01.models import  Book
class BookModelSerializer(ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"
ser.py
from django.shortcuts import render,HttpResponse

# Create your views here.



from rest_framework.viewsets import ModelViewSet
from .models import Book
from .ser import BookModelSerializer

from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request

class BooksViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer


class Books(View):
    #如果有个需求,只能接受get请求
    http_method_names = ['get',]
    def get(self,request):
        print(self.request)
        return HttpResponse('ok')

class BooksAPIView(APIView):

    def get(self,request):
        # request 已经不是原生django的request了,是drf自己定义的request对象
        # print(request._request)
        # print(request.data)
        print(request.method)
        print(request.query_params)  #get请求,地址中的参数
        # 原来在
        print(request.GET)
        return HttpResponse('ok')

    def post(self,request):

        print(request.data) # urlencoded方式有数据,json格式也有,formdata也有数据
        print(type(request.POST)) # 原生的POST
        print(request._request.POST)

        from django.http.request import QueryDict


        return HttpResponse('ok')
views.py

drf_serializer

class MyResponse():
    def __init__(self):
        self.status=100
        self.msg='成功'
    @property
    def get_dict(self):
        return self.__dict__


if __name__ == '__main__':
    res=MyResponse()
    res.status=101
    res.msg='查询失败'
    # res.data={'name':'lqz'}
    print(res.get_dict)
utils.py
# from rest_framework.serializers import Serializer  # 就是一个类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
# 需要继承 Serializer
from app01.models import Book

def check_author(data):
    if data.startswith('sb'):
        raise ValidationError('作者名字不能以sb开头')
    else:
        return data


class BookSerializer(serializers.Serializer):
    id=serializers.CharField(read_only=True)
    name=serializers.CharField(max_length=16,min_length=4)
    # price=serializers.DecimalField()
    price=serializers.CharField(write_only=True,required=True)
    author=serializers.CharField(validators=[check_author])  # validators=[] 列表中写函数内存地址
    publish=serializers.CharField()

    def validate_price(self, data):   # validate_字段名  接收一个参数
        #如果价格小于10,就校验不通过
        # print(type(data))
        # print(data)
        if float(data)>10:
            return data
        else:
            #校验失败,抛异常
            raise ValidationError('价格太低')
    def validate(self, validate_data):   # 全局钩子
        print(validate_data)
        author=validate_data.get('author')
        publish=validate_data.get('publish')
        if author == publish:
            raise ValidationError('作者名字跟出版社一样')
        else:
            return validate_data
    def update(self, instance, validated_data):
        #instance是book这个对象
        #validated_data是校验后的数据
        instance.name=validated_data.get('name')
        instance.price=validated_data.get('price')
        instance.author=validated_data.get('author')
        instance.publish=validated_data.get('publish')
        instance.save()  #book.save()   django 的orm提供的
        return instance
    def create(self, validated_data):
        instance=Book.objects.create(**validated_data)
        return instance
        # Book.objects.create(name=validated_data.get('name'))


class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book  # 对应上models.py中的模型
        fields='__all__'
        # fields=('name','price','id','author') # 只序列化指定的字段
        # exclude=('name',) #跟fields不能都写,写谁,就表示排除谁
        # read_only_fields=('price',)
        # write_only_fields=('id',) #弃用了,使用extra_kwargs
        extra_kwargs = {  # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
            'price': {'write_only': True},
        }





from rest_framework import serializers


class BookSerializer(serializers.Serializer):
    # book.publish
    # book.price
    # book.xxx--->book.title
    # book.authors.all

    xxx=serializers.CharField(source='title')
    price=serializers.CharField()
    pub_date=serializers.CharField(source='test')
    publish=serializers.CharField(source='publish.email')
    # book.publish.email  相当于
    # authors=serializers.CharField()
    authors=serializers.SerializerMethodField() #它需要有个配套方法,方法名叫get_字段名,返回值就是要显示的东西
    def get_authors(self,instance):
        # book对象
        authors=instance.authors.all()  # 取出所有作者
        ll=[]
        for author in authors:
            ll.append({'name':author.name,'age':author.age})
        return ll
ser.py
from django.shortcuts import render

# Create your views here.
from django.http import JsonResponse

from rest_framework.views import APIView
from app01.models import Book
from app01.ser import BookSerializer
from app01.ser import BookModelSerializer
from rest_framework.response import Response  #drf 提供的响应对象

# 导入自己写的response类
from app01.utils import MyResponse
class BookView(APIView):
    def get(self,request,pk):
        book=Book.objects.filter(id=pk).first()
        #用一个类,毫无疑问,一定要实例化
        #要序列化谁,就把谁传过来
        book_ser=BookSerializer(book)  # 调用类的__init__
        # book_ser.data   序列化对象.data就是序列化后的字典
        return Response(book_ser.data)
        # return JsonResponse(book_ser.data)

    def put(self,request,pk):
        response_msg={'status':100,'msg':'成功'}
        # 找到这个对象
        book = Book.objects.filter(id=pk).first()
        # 得到一个序列化类的对象
        # boo_ser=BookSerializer(book,request.data)
        boo_ser=BookSerializer(instance=book,data=request.data)

        # 要数据验证(回想form表单的验证)
        if boo_ser.is_valid():  # 返回True表示验证通过
            boo_ser.save()  # 报错
            response_msg['data']=boo_ser.data
        else:
            response_msg['status']=101
            response_msg['msg']='数据校验失败'
            response_msg['data']=boo_ser.errors

        return Response(response_msg)

    def delete(self,request,pk):
        response=MyResponse()
        ret=Book.objects.filter(pk=pk).delete()
        return Response(response.get_dict)

class BooksView(APIView):
    # def get(self,request):
    #     response_msg = {'status': 100, 'msg': '成功'}
    #     books=Book.objects.all()
    #     book_ser=BookSerializer(books,many=True)  #序列化多条,如果序列化一条,不需要写
    #     response_msg['data']=book_ser.data
    #     return Response(response_msg)

    def get(self,request):
        response=MyResponse()
        books=Book.objects.all()
        book_ser=BookSerializer(books,many=True)  #序列化多条,如果序列化一条,不需要写
        response.data=book_ser.data
        return Response(response.get_dict)

    # 新增
    def post(self,request):
        response_msg = {'status': 100, 'msg': '成功'}
        #修改才有instance,新增没有instance,只有data
        book_ser = BookSerializer(data=request.data)
        # book_ser = BookSerializer(request.data)  # 这个按位置传request.data会给instance,就报错了
        # 校验字段
        if book_ser.is_valid():
            book_ser.save()
            response_msg['data']=book_ser.data
        else:
            response_msg['status']=102
            response_msg['msg']='数据校验失败'
            response_msg['data']=book_ser.errors
        return Response(response_msg)


class BooksView2(APIView):
    def get(self,request):
        response=MyResponse()
        books=Book.objects.all()
        book=Book.objects.all().first()
        book_ser=BookModelSerializer(books,many=True)
        book_one_ser=BookModelSerializer(book)
        print(type(book_ser))
        print(type(book_one_ser))
        response.data=book_ser.data
        return Response(response.get_dict)




from rest_framework.views import APIView
from app02.models import Book
from app02.ser import BookSerializer
from rest_framework.response import Response  #drf 提供的响应对象

class APP02BookView(APIView):
    def get(self,request,pk):
        book=Book.objects.filter(id=pk).first()
        book_ser=BookSerializer(book)
        return Response(book_ser.data)
views.py
from django.db import models

# Create your models here.

class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish",on_delete=models.CASCADE,null=True)
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title
    def test(self):
        return 'lqz is big'

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    # def __str__(self):
    #     return self.name+'ccccc'

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name
models.py

drf_views

from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('test/', views.TestView.as_view()),
    path('test2/', views.TestView2.as_view()),
    path('books/', views.BookView.as_view()),
    re_path('books/(?P<pk>\d+)', views.BookDetailView.as_view()),

    # 使用GenericAPIView重写的
    path('books2/', views.Book2View.as_view()),
    re_path('books2/(?P<pk>\d+)', views.Book2DetailView.as_view()),

    # 使用GenericAPIView+5 个视图扩展类  重写的
    path('books3/', views.Book3View.as_view()),
    re_path('books3/(?P<pk>\d+)', views.Book3DetailView.as_view()),

    #
    path('books4/', views.Book4View.as_view()),
    re_path('books4/(?P<pk>\d+)', views.Book4DetailView.as_view()),

    # 使用ModelViewSet编写5个接口
    path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #当路径匹配,又是get请求,会执行Book5View的list方法
    re_path('books5/(?P<pk>\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),


    #继承ViewSetMixin的视图类,路由可以改写成这样
    path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),
]
urls.py
#这个变量REST_FRAMEWORK,里面都是drf的配置信息
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    ),

}
settings.py
from django.db import models

# Create your models here.


class Book(models.Model):
    name=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publish=models.CharField(max_length=32)


class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
models.py
from rest_framework import serializers
from app01.models import Book,Publish
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book
        fields='__all__'

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model=Publish
        fields='__all__'
ser.py
from django.shortcuts import render

# Create your views here.

from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import  APIView

from rest_framework import status
from rest_framework.renderers import JSONRenderer
class TestView(APIView):
    renderer_classes=[JSONRenderer,]
    def get(self,request):
        print(request)

        return Response({'name':'lqz'},status=status.HTTP_200_OK,headers={'token':'xxx'})

class TestView2(APIView):
    def get(self,request):
        print(request)

        return Response({'name':'2222'},status=status.HTTP_200_OK,headers={'token':'xxx'})

##################################视图相关
from rest_framework.generics import GenericAPIView
from app01.models import Book
from app01.ser import BookSerializer
# 基于APIView写的
class BookView(APIView):
    def get(self,request):
        book_list=Book.objects.all()
        book_ser=BookSerializer(book_list,many=True)

        return Response(book_ser.data)
    def post(self,request):
        book_ser = BookSerializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status':101,'msg':'校验失败'})


class BookDetailView(APIView):
    def get(self, request,pk):
        book = Book.objects.all().filter(pk=pk).first()
        book_ser = BookSerializer(book)
        return Response(book_ser.data)

    def put(self, request,pk):
        book = Book.objects.all().filter(pk=pk).first()
        book_ser = BookSerializer(instance=book,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

    def delete(self,request,pk):
        ret=Book.objects.filter(pk=pk).delete()
        return Response({'status': 100, 'msg': '删除成功'})

# 基于GenericAPIView写的
class Book2View(GenericAPIView):
    #queryset要传queryset对象,查询了所有的图书
    # serializer_class使用哪个序列化类来序列化这堆数据
    queryset=Book.objects
    # queryset=Book.objects.all()
    serializer_class = BookSerializer
    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':'校验失败'})


class Book2DetailView(GenericAPIView):
    queryset = Book.objects
    serializer_class = BookSerializer
    def get(self, request,pk):
        book = self.get_object()
        book_ser = self.get_serializer(book)
        return Response(book_ser.data)

    def put(self, request,pk):
        book = self.get_object()
        book_ser = self.get_serializer(instance=book,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

    def delete(self,request,pk):
        ret=self.get_object().delete()
        return Response({'status': 100, 'msg': '删除成功'})


## 基于GenericAPIView写的Publish的5个接口
from app01.models import Publish
from app01.ser import PublishSerializer
class Publish2View(GenericAPIView):
    #queryset要传queryset对象,查询了所有的图书
    # serializer_class使用哪个序列化类来序列化这堆数据
    queryset=Publish.objects
    # queryset=Book.objects.all()
    serializer_class = PublishSerializer
    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':'校验失败'})


class Publish2DetailView(GenericAPIView):
    queryset = Publish.objects
    serializer_class = PublishSerializer
    def get(self, request,pk):
        book = self.get_object()
        book_ser = self.get_serializer(book)
        return Response(book_ser.data)

    def put(self, request,pk):
        book = self.get_object()
        book_ser = self.get_serializer(instance=book,data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

    def delete(self,request,pk):
        ret=self.get_object().delete()
        return Response({'status': 100, 'msg': '删除成功'})

# CURD:create update,delet,retrieve

# 5 个视图扩展类
from rest_framework.mixins import  ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin

class Book3View(GenericAPIView,ListModelMixin,CreateModelMixin):

    queryset=Book.objects
    serializer_class = BookSerializer
    def get(self,request):
        return self.list(request)

    def post(self,request):
        return self.create(request)

class Book3DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
    queryset = Book.objects
    serializer_class = BookSerializer
    def get(self, request,pk):
        return self.retrieve(request,pk)

    def put(self, request,pk):
        return self.update(request,pk)

    def delete(self,request,pk):
        return self.destroy(request,pk)



#GenericAPIView的视图子类 9个
from rest_framework.generics import CreateAPIView,ListAPIView,UpdateAPIView,RetrieveAPIView,DestroyAPIView,ListCreateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView,RetrieveUpdateAPIView

# class Book4View(ListAPIView,CreateAPIView):  #获取所有,新增一个
class Book4View(ListCreateAPIView):  #获取所有,新增一个
    queryset = Book.objects
    serializer_class = BookSerializer

# class Book4DetailView(UpdateAPIView,RetrieveAPIView,DestroyAPIView):
class Book4DetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects
    serializer_class = BookSerializer



# 使用ModelViewSet编写5个接口
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
class Book5View(ModelViewSet):  #5个接口都有,但是路由有点问题
    queryset = Book.objects
    serializer_class = BookSerializer



class Book5View(ReadOnlyModelViewSet):  #2个接口,获取一条,和获取所有两个
    queryset = Book.objects
    serializer_class = BookSerializer


from rest_framework.viewsets import ViewSetMixin

class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前


    def get_all_book(self,request):
        print("xxxx")
        book_list = Book.objects.all()
        book_ser = BookSerializer(book_list, many=True)
        return Response(book_ser.data)
views.py

drf_router_auth

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}
settings.py
from django.contrib import admin
from django.urls import path,re_path
from app01 import views

# 第一步:导入routers模块
from rest_framework import routers
# 第二步:有两个类,实例化得到对象
# routers.DefaultRouter 生成的路由更多
# routers.SimpleRouter
router=routers.SimpleRouter()
# 第三步:注册
# router.register('前缀','继承自ModelViewSet视图类','别名')
router.register('books',views.BookViewSet) # 不要加斜杠了

# 第四步
# router.urls # 自动生成的路由,加入到原路由中
# print(router.urls)
# urlpatterns+=router.urls
'''
[
<URLPattern '^books/$' [name='book-list']>, 
<URLPattern '^books/(?P<pk>[^/.]+)/$'[name='book-detail']>
]

'''
urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.LoginView.as_view()),
    path('test/', views.TestView.as_view()),
    # path('books/', views.BookViewSet.as_view({'get':'list','post':'create'})),
    # re_path('books/(?P<pk>\d+)', views.BookViewSet.as_view({'get':'retrieve','put':'update','delete':'destroy'})),

]

urlpatterns+=router.urls



'''
SimpleRouter
<URLPattern '^books/$' [name='book-list']>, 
<URLPattern '^books/(?P<pk>[^/.]+)/$'[name='book-detail']>


DefaultRouter
^books/$ [name='book-list']
^books/(?P<pk>[^/.]+)/$ [name='book-detail']  这两条跟simple一样

^$ [name='api-root']  根,根路径会显示出所有可以访问的地址
^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']


^books\.(?P<format>[a-z0-9]+)/?$ [name='book-list']  http://127.0.0.1:8000/books.json
^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail']  http://127.0.0.1:8000/books/1.json


'''
urls.py
from django.shortcuts import render

# Create your views here.
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import  Response
from rest_framework.decorators import action  # 装饰器

from app01.models import Book
from app01.ser import BookSerializer
from rest_framework.request import Request
from rest_framework.authentication import BaseAuthentication

from rest_framework.exceptions import AuthenticationFailed
from app01.app_auth import MyAuthentication
from rest_framework.views import APIView
from rest_framework.response import Response
import uuid
from app01 import models

class BookViewSet(ModelViewSet):
    # authentication_classes=[MyAuthentication]
    queryset =Book.objects.all()
    serializer_class = BookSerializer
    # methods第一个参数,传一个列表,列表中放请求方式,
    # ^books/get_1/$ [name='book-get-1'] 当向这个地址发送get请求,会执行下面的函数
    # detail:布尔类型 如果是True
    #^books/(?P<pk>[^/.]+)/get_1/$ [name='book-get-1']
    @action(methods=['GET','POST'],detail=True)
    def get_1(self,request,pk):
        print(request.user.username)
        print(pk)
        book=self.get_queryset()[:2]  # 从0开始截取一条
        ser=self.get_serializer(book,many=True)
        return Response(ser.data)




from rest_framework.authentication import BasicAuthentication
class TestView(APIView):
    def get(self,request):
        print(request.user.username)
        return Response({'msg':'我是测试'})


class LoginView(APIView):
    authentication_classes = []
    def post(self,request):
        username=request.data.get('username')
        password=request.data.get('password')
        user=models.User.objects.filter(username=username,password=password).first()
        if user:
            # 登陆成功,生成一个随机字符串
            token=uuid.uuid4()
            # 存到UserToken表中
            # models.UserToken.objects.create(token=token,user=user)# 用它每次登陆都会记录一条,不好,如有有记录
            # update_or_create有就更新,没有就新增
            models.UserToken.objects.update_or_create(defaults={'token':token},user=user)
            return Response({'status':100,'msg':'登陆成功','token':token})
        else:
            return Response({'status': 101, 'msg': '用户名或密码错误'})
views.py
from rest_framework import serializers
from app01.models import Book
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book
        fields='__all__'
ser.py
from django.db import models

# Create your models here.
class Book(models.Model):
    name=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publish=models.CharField(max_length=32)


class User(models.Model):
    username=models.CharField(max_length=32)
    password=models.CharField(max_length=32)
    user_type=models.IntegerField(choices=((1,'超级用户'),(2,'普通用户'),(3,'二笔用户')))

class UserToken(models.Model):
    token=models.CharField(max_length=64)
    user=models.OneToOneField(to=User,on_delete=models.CASCADE)  #一对一关联到User表
models.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 认证逻辑,如果认证通过,返回两个值
        #如果认证失败,抛出AuthenticationFailed异常
        token=request.GET.get('token')
        if  token:
            user_token=UserToken.objects.filter(token=token).first()
            # 认证通过
            if user_token:
                return user_token.user,token
            else:
                raise AuthenticationFailed('认证失败')
        else:
            raise AuthenticationFailed('请求地址中需要携带token')
app_auth.py

drf_others

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.LoginView.as_view()),
    path('test/', views.TestView.as_view()),
    path('test2/', views.TestView2.as_view()),
    path('test3/', views.TestView3.as_view()),
    path('test4/', views.TestView4.as_view()),
    path('test5/', views.TestView5.as_view()),
    path('test6/', views.TestView6.as_view()),
    path('books/', views.BookView.as_view()),
    path('books2/', views.Book2View.as_view()),
    path('test7/', views.TestView7.as_view()),
]
urls.py
REST_FRAMEWORK = {
    # "DEFAULT_AUTHENTICATION_CLASSES": ["app01.app_auth.MyAuthentication", ],
    # 'DEFAULT_PERMISSION_CLASSES': [
    #     'app01.app_auth.UserPermission',
    # ],
    # 'DEFAULT_THROTTLE_CLASSES': (
    #     'rest_framework.throttling.AnonRateThrottle',
    # ),

    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'user': '10/m',
        'anon': '5/m',
    },
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'EXCEPTION_HANDLER': 'app01.app_auth.my_exception_handler',

}
settings.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 认证逻辑,如果认证通过,返回两个值
        #如果认证失败,抛出AuthenticationFailed异常
        token=request.GET.get('token')
        if  token:
            user_token=UserToken.objects.filter(token=token).first()
            # 认证通过
            if user_token:
                return user_token.user,token
            else:
                raise AuthenticationFailed('认证失败')
        else:
            raise AuthenticationFailed('请求地址中需要携带token')



from rest_framework.permissions import BasePermission

class UserPermission(BasePermission):
    def  has_permission(self, request, view):
        # 不是超级用户,不能访问
        # 由于认证已经过了,request内就有user对象了,当前登录用户
        user=request.user  # 当前登录用户
        # 如果该字段用了choice,通过get_字段名_display()就能取出choice后面的中文
        print(user.get_user_type_display())
        if user.user_type==1:
            return True
        else:
            return False





# 自定义异常处理的方法
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)


#自己封装Response对象

from rest_framework.response import Response

# return APIResponse(100,'成功',data)

class APIResponse(Response):
    def __init__(self,code=100,msg='成功',data=None,status=None,headers=None,**kwargs):
        dic = {'code': code, 'msg': msg}
        if  data:
            dic = {'code': code, 'msg': msg,'data':data}
        dic.update(kwargs)
        super().__init__(data=dic, status=status,headers=headers)
app_auth.py
from django.db import models

# Create your models here.
from django.db import models

# Create your models here.
class Book(models.Model):
    name=models.CharField(max_length=32)
    price=models.DecimalField(max_digits=5,decimal_places=2)
    publish=models.CharField(max_length=32)


class User(models.Model):
    username=models.CharField(max_length=32)
    password=models.CharField(max_length=32)
    user_type=models.IntegerField(choices=((1,'超级用户'),(2,'普通用户'),(3,'二笔用户')))

class UserToken(models.Model):
    token=models.CharField(max_length=64)
    user=models.OneToOneField(to=User,on_delete=models.CASCADE)  #一对一关联到User表
models.py
from rest_framework import serializers
from app01.models import Book
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model=Book
        fields='__all__'
ser.py

drf_books_ser

 

 

from rest_framework import serializers
from api import models


#写一个类,继ListSerializer,重写update
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    #     print(validated_data)
    #     return super().create(validated_data)
    def update(self, instance, validated_data):
        print(instance)
        print(validated_data)
        # 保存数据
        # self.child:是BookModelSerializer对象
        # ll=[]
        # for i,si_data in enumerate(validated_data):
        #     ret=self.child.update(instance[i],si_data)
        #     ll.append(ret)
        # return ll
        return [
            # self.child.update(对象,字典) for attrs in validated_data
            self.child.update(instance[i],attrs) for i,attrs in enumerate(validated_data)
        ]



#如果序列化的是数据库的表,尽量用ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
    # 一种方案(只序列化可以,反序列化有问题)
    # publish=serializers.CharField(source='publish.name')
    # 第二种方案,models中写方法

    class Meta:
        list_serializer_class=BookListSerializer
        model=models.Book
        # fields='__all__'
        # 用的少
        # depth=0
        sss=serializers.CharField(source='name')
        fields = ('id','name','price','authors','publish','publish_name','author_list','ssss')

        extra_kwargs={
            'publish':{'write_only':True},
            'publish_name':{'read_only':True},
            'authors':{'write_only':True},
            'author_list':{'read_only':True}
        }
ser.py
from django.urls import path,re_path
from api import views
urlpatterns = [
    path('books/', views.BookAPIView.as_view()),
    path('books2/', views.BookView.as_view()), #继承了ListApiView
    re_path('books/(?P<pk>\d+)', views.BookAPIView.as_view()),
]
urls.py
from django.shortcuts import render

# Create your views here.

from rest_framework.response import Response

from api import models
from  rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from api.ser import BookModelSerializer

class BookAPIView(APIView):
    def get(self,request,*args,**kwargs):
        #查询单个和查询所有,合到一起
        # 查所有
        book_list=models.Book.objects.all().filter(is_delete=False)
        book_list_ser=BookModelSerializer(book_list,many=True)
        return Response(data=book_list_ser.data)
        #查一个

    def post(self,request,*args,**kwargs):
        # 具备增单条,和增多条的功能
        if isinstance(request.data,dict):

            book_ser=BookModelSerializer(data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        elif isinstance(request.data,list):
            #现在book_ser是ListSerializer对象
            from rest_framework.serializers import ListSerializer
            book_ser = BookModelSerializer(data=request.data,many=True)  #增多条
            print('--------',type(book_ser))
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            # 新增---》ListSerializer--》create方法
            # def create(self, validated_data):
            #   self.child是BookModelSerializer对象
            #   print(type(self.child))
            #     return [
            #         self.child.create(attrs) for attrs in validated_data
            #     ]
            return Response(data=book_ser.data)

    def put(self,request,*args,**kwargs):
        # 改一个,改多个
        #改一个个
        if kwargs.get('pk',None):
            book=models.Book.objects.filter(pk=kwargs.get('pk')).first()
            book_ser = BookModelSerializer(instance=book,data=request.data,partial=True)  # 增多条
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        else:
            #改多个,
            # 前端传递数据格式[{id:1,name:xx,price:xx},{id:1,name:xx,price:xx}]
            # 处理传入的数据  对象列表[book1,book2]  修改的数据列表[{name:xx,price:xx},{name:xx,price:xx}]
            book_list=[]
            modify_data=[]
            for item in request.data:
                #{id:1,name:xx,price:xx}

                pk=item.pop('id')
                book=models.Book.objects.get(pk=pk)
                book_list.append(book)
                modify_data.append(item)
            # 第一种方案,for循环一个一个修改
            #把这个实现
            # for i,si_data in enumerate(modify_data):
            #     book_ser = BookModelSerializer(instance=book_list[i], data=si_data)
            #     book_ser.is_valid(raise_exception=True)
            #     book_ser.save()
            # return Response(data='成功')
            # 第二种方案,重写ListSerializer的update方法
            book_ser = BookModelSerializer(instance=book_list,data=modify_data,many=True)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()  #ListSerializer的update方法,自己写的update方法
            return Response(book_ser.data)
            # request.data
            #
            # book_ser=BookModelSerializer(data=request.data)

    def delete(self,request,*args,**kwargs):
        #单个删除和批量删除
        pk=kwargs.get('pk')
        pks=[]
        if pk:
            # 单条删除
            pks.append(pk)
        #不管单条删除还是多条删除,都用多条删除
        #多条删除
        # {'pks':[1,2,3]}
        else:
            pks=request.data.get('pks')
        #把is_delete设置成true
        # ret返回受影响的行数
        ret=models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True)
        if ret:
            return Response(data={'msg':'删除成功'})
        else:
            return Response(data={'msg': '没有要删除的数据'})







# 查所有,才需要分页
from rest_framework.generics import ListAPIView
# 内置三种分页方式
from  rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
'''
PageNumberPagination
    page_size:每页显示的条数
'''
class MyPageNumberPagination(PageNumberPagination):
    #http://127.0.0.1:8000/api/books2/?aaa=1&size=6
    page_size=3  #每页条数
    page_query_param='aaa' #查询第几页的key
    page_size_query_param='size' # 每一页显示的条数
    max_page_size=5    # 每页最大显示条数


# class MyLimitOffsetPagination(LimitOffsetPagination):
#     default_limit = 3   # 每页条数
#     limit_query_param = 'limit' # 往后拿几条
#     offset_query_param = 'offset' # 标杆
#     max_limit = 5   # 每页最大几条

class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 每一页查询的key
    page_size = 2   #每页显示的条数
    ordering = '-id'  #排序字段
# class BookView(ListAPIView):
#     # queryset = models.Book.objects.all().filter(is_delete=False)
#     queryset = models.Book.objects.all()
#     serializer_class = BookModelSerializer
#     #配置分页
#     pagination_class = MyCursorPagination

# 如果使用APIView分页
from utils.throttling import MyThrottle
class BookView(APIView):
    # throttle_classes = [MyThrottle,]
    def get(self,request,*args,**kwargs):
        book_list=models.Book.objects.all()
        # 实例化得到一个分页器对象
        page_cursor=MyPageNumberPagination()

        book_list=page_cursor.paginate_queryset(book_list,request,view=self)
        next_url =page_cursor.get_next_link()
        pr_url=page_cursor.get_previous_link()
        # print(next_url)
        # print(pr_url)
        book_ser=BookModelSerializer(book_list,many=True)
        return Response(data=book_ser.data)
views.py
from rest_framework.throttling import ScopedRateThrottle,SimpleRateThrottle


#继承SimpleRateThrottle
class MyThrottle(SimpleRateThrottle):
    scope='luffy'
    def get_cache_key(self, request, view):
        print(request.META.get('REMOTE_ADDR'))
        return request.META.get('REMOTE_ADDR')
throttling.py
REST_FRAMEWORK={
    'DEFAULT_THROTTLE_CLASSES': (
        'utils.throttling.MyThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'luffy': '3/m'  # key要跟类中的scop对应
    },
    'PAGE_SIZE': 2,
}
settings.py
from django.db import models




from django.contrib.auth.models import AbstractUser
class BaseModel(models.Model):
    is_delete=models.BooleanField(default=False)
    # auto_now_add=True 只要记录创建,不需要手动插入时间,自动把当前时间插入
    create_time=models.DateTimeField(auto_now_add=True)
    # auto_now=True,只要更新,就会把当前时间插入
    last_update_time=models.DateTimeField(auto_now=True)
    # import datetime
    # create_time=models.DateTimeField(default=datetime.datetime.now)
    class Meta:
        # 单个字段,有索引,有唯一
        # 多个字段,有联合索引,联合唯一
        abstract=True  # 抽象表,不再数据库建立出表




class Book(BaseModel):
    id=models.AutoField(primary_key=True)
    # verbose_name admin中显示中文
    name=models.CharField(max_length=32,verbose_name='书名',help_text='这里填书名')
    price=models.DecimalField(max_digits=5,decimal_places=2)
    # 一对多的关系一旦确立,关联字段写在多的一方
    #to_field 默认不写,关联到Publish主键
    #db_constraint=False  逻辑上的关联,实质上没有外键练习,增删不会受外键影响,但是orm查询不影响
    publish=models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)

    # 多对多,跟作者,关联字段写在 查询次数多的一方

    # 什么时候用自动,什么时候用手动?第三张表只有关联字段,用自动    第三张表有扩展字段,需要手动写
    # 不能写on_delete
    authors=models.ManyToManyField(to='Author',db_constraint=False)
    class Meta:
        verbose_name_plural='书表'  # admin中表名的显示

    def __str__(self):
        return self.name

    @property
    def publish_name(self):
        return self.publish.name
    # def author_list(self):
    def author_list(self):
        author_list=self.authors.all()
        # ll=[]
        # for author in author_list:
        #     ll.append({'name':author.name,'sex':author.get_sex_display()})
        # return ll
        return [ {'name':author.name,'sex':author.get_sex_display()}for author in author_list]

class Publish(BaseModel):
    name = models.CharField(max_length=32)
    addr=models.CharField(max_length=32)
    def __str__(self):
        return self.name


class Author(BaseModel):
    name=models.CharField(max_length=32)
    sex=models.IntegerField(choices=((1,''),(2,'')))
    # 一对一关系,写在查询频率高的一方
    #OneToOneField本质就是ForeignKey+unique,自己手写也可以
    authordetail=models.OneToOneField(to='AuthorDetail',db_constraint=False,on_delete=models.CASCADE)

class AuthorDetail(BaseModel):
    mobile=models.CharField(max_length=11)

# 二、表断关联
# 1、表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
# 2、断关联后不会影响数据库查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
# 3、断关联一定要通过逻辑保证表之间数据的安全,不要出现脏数据,代码控制
# 4、断关联
# 5、级联关系
#       作者没了,详情也没:on_delete=models.CASCADE
#       出版社没了,书还是那个出版社出版:on_delete=models.DO_NOTHING
#       部门没了,员工没有部门(空不能):null=True, on_delete=models.SET_NULL
#       部门没了,员工进入默认部门(默认值):default=0, on_delete=models.SET_DEFAULT
models.py
from django.contrib import admin

# Register your models here.


from api import models


admin.site.register(models.Book)
admin.site.register(models.Publish)
admin.site.register(models.Author)
admin.site.register(models.AuthorDetail)
admin.py

drf_token

# 配置头像相关
MEDIA_URL='/media/'
MEDIA_ROOT=os.path.join(BASE_DIR,'media')

#一定不要忘了
AUTH_USER_MODEL='api.user'


REST_FRAMEWORK={
    'DEFAULT_AUTHENTICATION_CLASSES':['rest_framework_jwt.authentication.JSONWebTokenAuthentication']
}

JWT_AUTH={
    'JWT_AUTH_HEADER_PREFIX': '',
}
settings.py
from django.contrib import admin
from django.urls import path


from rest_framework_jwt.views import ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken,obtain_jwt_token
# 基类:JSONWebTokenAPIView继承了APIView,
# ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken都继承了JSONWebTokenAPIView
'''
obtain_jwt_token = ObtainJSONWebToken.as_view()
refresh_jwt_token = RefreshJSONWebToken.as_view()
verify_jwt_token = VerifyJSONWebToken.as_view()
'''
from api import views
urlpatterns = [
    path('admin/', admin.site.urls),
    # path('login/', ObtainJSONWebToken.as_view()),
    path('login/', obtain_jwt_token),
    path('books/', views.BookView.as_view()),
]
urls.py
from rest_framework_jwt.authentication import BaseAuthentication,BaseJSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.authentication import get_authorization_header,jwt_get_username_from_payload
from rest_framework import exceptions
class MyToken(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        jwt_value=str(request.META.get('HTTP_AUTHORIZATION'))
        # 认证
        try:
            payload = jwt_decode_handler(jwt_value)

        except Exception:
            raise exceptions.AuthenticationFailed("认证失败")
        user=self.authenticate_credentials(payload)
        return user,None
auth.py
from django.db import models

from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    phone=models.CharField(max_length=11)
    icon=models.ImageField(upload_to='icon')  # ImageField依赖于pillow模块
models.py
from django.shortcuts import render


from rest_framework.views import APIView
from rest_framework.response import Response

from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from api.auth import MyToken
class BookView(APIView):
    authentication_classes = [MyToken,]
    def get(self,request):
        print(request.user.email)
        return Response('ok')
views.py

drf_...

# base64编码和解码
#md5固定长度,不可反解
#base63 变长,可反解

#编码(字符串,json格式字符串)
import base64
import json
dic={'name':'lqz','age':18,'sex':''}
dic_str=json.dumps(dic)

ret=base64.b64encode(dic_str.encode('utf-8'))
print(ret)

# 解码
# ret是带解码的串
ret2=base64.b64decode(ret)
print(ret2)
base64
from django.contrib import admin
from django.urls import path,include,re_path
from django.views.static import serve  # django内置给你的一个视图函数
from django.conf import settings  # 以后取配置文件,都用这个
# from drf_day12 import settings
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/',include('api.urls')),  # 路由分发
    path('app02/',include('app02.urls')),
    # 开放media文件
    re_path('media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),

]
urls.py
STATIC_URL = '/static/'

MEDIA_URL='/media/'
MEDIA_ROOT=os.path.join(BASE_DIR,'media')   #真正的文件夹路径

#指定使用的auth表是自己定义的

AUTH_USER_MODEL='api.user'   #app名.表名



# jwt的配置
import datetime
JWT_AUTH={
    'JWT_RESPONSE_PAYLOAD_HANDLER':'app02.utils.my_jwt_response_payload_handler',
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # 过期时间,手动配置
}


CACHES = {
 'default': {
  'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', #指定缓存使用的引擎
  'LOCATION': 'D:\django_cache',        #指定缓存的路径
  'TIMEOUT':300,              #缓存超时时间(默认为300秒,None表示永不过期)
  'OPTIONS':{
   'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
   'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
  }
 }
}
settings.py
from django.db import models

# Create your models here.
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    mobile=models.CharField(max_length=32,unique=True)  #唯一
    icon=models.ImageField(upload_to='icon',default='icon/default.png')  #需要配media文件夹,上传的文件就会放到media文件夹下的icon


class Book(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name


class Car(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name
models.py
from rest_framework import serializers
from api import models
from rest_framework.exceptions import ValidationError
class UserModelSerializer(serializers.ModelSerializer):
    re_password=serializers.CharField(max_length=16,min_length=4,required=True,write_only=True) # 因为re_password在表中没有,需要在这定义
    class Meta:
        model=models.User
        fields=['username','password','mobile','re_password','icon']
        extra_kwargs={
            'username':{'max_length':16},
            'password':{'write_only':True}
        }
    # 局部钩子
    def validate_mobile(self,data):
        if not len(data)==11:
            raise ValidationError('手机号不合法')
        return data
    # 全局钩子
    def validate(self, attrs):
        if not attrs.get('password')==attrs.get('re_password'):
            raise ValidationError('两次密码不一致')
        attrs.pop('re_password')# 剔除该字段,因为数据库没有这个字段
        return attrs
    def create(self, validated_data):
        # attrs.pop('re_password') 如果上面没有剔除,在这也可以
        # models.User.objects.create(**validated_data) 这个密码不会加密
        user=models.User.objects.create_user(**validated_data)
        return user


class UserReadOnlyModelSerializer(serializers.ModelSerializer):
   class Meta:
        model=models.User
        fields=['username','icon']

class UserImageModelSerializer(serializers.ModelSerializer):
   class Meta:
        model=models.User
        fields=['icon']
ser.py
from django.shortcuts import render

# Create your views here.
from rest_framework.viewsets import GenericViewSet
#ViewSetMixin:重写了as_view,路由配置变样了, generics.GenericAPIView:只需要配俩东西
from rest_framework.mixins import CreateModelMixin,RetrieveModelMixin,UpdateModelMixin

from api import ser
from api import models
class RegisterView(GenericViewSet,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin):
    queryset = models.User.objects.all()
    serializer_class =ser.UserModelSerializer

    # 假设get请求和post请求,用的序列化类不一样,如何处理?
    # 重写getget_serializer_class,返回啥,用的序列号类就是啥
    # 注册,用的序列化类是UserModelSerializer,查询一个用的序列化类是UserReadOnlyModelSerializer
    def get_serializer_class(self):
        print(self.action)  # create,retrieve
        if self.action=='create':
            return ser.UserModelSerializer
        elif self.action=='retrieve':
            return ser.UserReadOnlyModelSerializer
        elif self.action=='update':
            return  ser.UserImageModelSerializer
views.py
from rest_framework import serializers
from api import models
import re
from rest_framework.exceptions import ValidationError

from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
class LoginModelSerializer(serializers.ModelSerializer):
    username=serializers.CharField()  # 重新覆盖username字段,数据中它是unique,post,认为你保存数据,自己有校验没过
    class Meta:
        model=models.User
        fields=['username','password']

    def validate(self, attrs):

        print(self.context)

        # 在这写逻辑
        username=attrs.get('username') # 用户名有三种方式
        password=attrs.get('password')
        # 通过判断,username数据不同,查询字段不一样
        # 正则匹配,如果是手机号
        if re.match('^1[3-9][0-9]{9}$',username):
            user=models.User.objects.filter(mobile=username).first()
        elif re.match('^.+@.+$',username):# 邮箱
            user=models.User.objects.filter(email=username).first()
        else:
            user=models.User.objects.filter(username=username).first()
        if user: # 存在用户
            # 校验密码,因为是密文,要用check_password
            if user.check_password(password):
                # 签发token
                payload = jwt_payload_handler(user)  # 把user传入,得到payload
                token = jwt_encode_handler(payload)  # 把payload传入,得到token
                self.context['token']=token
                self.context['username']=user.username
                return attrs
            else:
                raise ValidationError('密码错误')
        else:
            raise ValidationError('用户不存在')



'''
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user) # 把user传入,得到payload
token = jwt_encode_handler(payload) # 把payload传入,得到token

'''
ser.py
from django.contrib import admin
from django.urls import path,include,re_path
from django.views.static import serve  # django内置给你的一个视图函数
from django.conf import settings  # 以后取配置文件,都用这个
# from drf_day12 import settings
from rest_framework_jwt.views import obtain_jwt_token
from app02 import views
urlpatterns = [
    path('login/', obtain_jwt_token),
    path('order/', views.OrderAPIView.as_view()),
    path('userinfo/', views.UserInfoAPIView.as_view()),
    path('goods/', views.GoodsInfoAPIView.as_view()),
    path('login2/', views.Login2View.as_view({'post':'login'})),

    # 缓存
    path('test/', views.test_cache),
    path('test2/', views.test_cache2)

]
urls.py
def my_jwt_response_payload_handler(token, user=None, request=None): # 返回什么,前端就能看到什么样子
    return {
        'token': token,
        'msg':'登录成功',
        'status':100,
        'username':user.username

    }
from rest_framework.authentication import BaseAuthentication  # 基于它
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication # 基于它
from rest_framework.exceptions import AuthenticationFailed
# from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.utils import jwt_decode_handler # 跟上面是一个
import jwt

from api import models
# class MyJwtAuthentication(BaseAuthentication):
#     def authenticate(self, request):
#         jwt_value=request.META.get('HTTP_AUTHORIZATION')
#         if jwt_value:
#             try:
#             #jwt提供了通过三段token,取出payload的方法,并且有校验功能
#                 payload=jwt_decode_handler(jwt_value)
#             except jwt.ExpiredSignature:
#                 raise AuthenticationFailed('签名过期')
#             except jwt.InvalidTokenError:
#                 raise AuthenticationFailed('用户非法')
#             except Exception as e:
#                 # 所有异常都会走到这
#                 raise AuthenticationFailed(str(e))
#             # 因为payload就是用户信息的字典
#             print(payload)
#             # return payload, jwt_value
#             # 需要得到user对象,
#             # 第一种,去数据库查
#             # user=models.User.objects.get(pk=payload.get('user_id'))
#             # 第二种不查库
#             user=models.User(id=payload.get('user_id'),username=payload.get('username'))
#             return user,jwt_value
#         # 没有值,直接抛异常
#         raise AuthenticationFailed('您没有携带认证信息')


class MyJwtAuthentication(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        jwt_value=request.META.get('HTTP_AUTHORIZATION')
        if jwt_value:
            try:
            #jwt提供了通过三段token,取出payload的方法,并且有校验功能
                payload=jwt_decode_handler(jwt_value)
            except jwt.ExpiredSignature:
                raise AuthenticationFailed('签名过期')
            except jwt.InvalidTokenError:
                raise AuthenticationFailed('用户非法')
            except Exception as e:
                # 所有异常都会走到这
                raise AuthenticationFailed(str(e))
            user=self.authenticate_credentials(payload)
            return user,jwt_value
        # 没有值,直接抛异常
        raise AuthenticationFailed('您没有携带认证信息')
utils.py
from django.shortcuts import render

# Create your views here.
from rest_framework.views import APIView

from rest_framework.response import Response
# 使用jwt提供的认证类,局部使用
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

# 内置权限类

# 可以通过认证类:JSONWebTokenAuthentication和权限类IsAuthenticated,来控制用户登录以后才能访问某些接口
# 如果用户不登录就可以访问,只需要把权限类IsAuthenticated去掉就可以了
from rest_framework.permissions import IsAuthenticated
class OrderAPIView(APIView):
    authentication_classes = [JSONWebTokenAuthentication,]
    # 权限控制
    permission_classes = [IsAuthenticated,]
    def get(self,request,*args,**kwargs):
        return Response('这是订单信息')


class UserInfoAPIView(APIView):
    authentication_classes = [JSONWebTokenAuthentication,]
    # 权限控制
    # permission_classes = [IsAuthenticated,]
    def get(self,request,*args,**kwargs):
        return Response('UserInfoAPIView')




#
from rest_framework_jwt.utils import jwt_response_payload_handler
from app02.utils import MyJwtAuthentication
class GoodsInfoAPIView(APIView):
    authentication_classes = [MyJwtAuthentication,]

    def get(self,request,*args,**kwargs):
        print(request.user)
        return Response('商品信息')


# 手动签发token,完成多方式登录
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin, ViewSet

from app02 import ser
# class Login2View(ViewSetMixin,APIView):
class Login2View(ViewSet):  # 跟上面完全一样
    # 这是登录接口
    # def post(self):  # 不写post了,直接写login?
    #     pass

    def login(self, request, *args, **kwargs):

        # 1 需要 有个序列化的类
        login_ser = ser.LoginModelSerializer(data=request.data,context={'request':request})
        # 2 生成序列化类对象
        # 3 调用序列号对象的is_validad
        login_ser.is_valid(raise_exception=True)
        token=login_ser.context.get('token')
        # 4 return
        return Response({'status':100,'msg':'登录成功','token':token,'username':login_ser.context.get('username')})


    # 逻辑在视图类中写

    # def login(self, request, *args, **kwargs):
    #     username=request.data.get('username') # 用户名有三种方式
    #     password=request.data.get('password')
    #     import re
    #     from api import models
    #     from rest_framework_jwt.utils import jwt_encode_handler, jwt_payload_handler
    #     # 通过判断,username数据不同,查询字段不一样
    #     # 正则匹配,如果是手机号
    #     if re.match('^1[3-9][0-9]{9}$',username):
    #         user=models.User.objects.filter(mobile=username).first()
    #     elif re.match('^.+@.+$',username):# 邮箱
    #         user=models.User.objects.filter(email=username).first()
    #     else:
    #         user=models.User.objects.filter(username=username).first()
    #     if user: # 存在用户
    #         # 校验密码,因为是密文,要用check_password
    #         if user.check_password(password):
    #             # 签发token
    #             payload = jwt_payload_handler(user)  # 把user传入,得到payload
    #             token = jwt_encode_handler(payload)  # 把payload传入,得到token
    #            return Response()


# 单页面缓存
from django.views.decorators.cache import cache_page



class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age


from django.core.cache import cache
# @cache_page(5)  # 缓存5s钟
def test_cache(request):
    p=Person('lqz',18)
    cache.set('name',p)
    import time
    ctime=time.time()
    return render(request,'index.html',context={'ctime':ctime})


def test_cache2(request):

    p=cache.get('name')
    print(type(p))
    print(p.name)
    import time
    ctime = time.time()
    return render(request, 'index.html', context={'ctime': ctime})
views.py

 

posted @ 2020-10-03 01:34  silencio。  阅读(167)  评论(0编辑  收藏  举报