DRF案例

heart / 2024-04-22 / 原文

1 反序列化更新,instance 就传要修改的对象,保证修改完成

def update(self, instance, validated_data):
    publish_id = validated_data.pop('publish')
    author_id = validated_data.pop('author')
    for k in validated_data:
        setattr(instance, k, validated_data[k])
    instance.publish_id = publish_id
    instance.author.set(author_id)
    return instance

2 反序列化保存和更新,字段如下,实现更新和保存

publish_id=serializers.IntegerField(write_only=True) 
authors_l=serializers.ListField(write_only=True)
class BookSerializer(serializers.Serializer):
    publish_id = serializers.IntegerField(write_only=True)
    authors_l = serializers.ListField(write_only=True)

    def create(self, validated_data):
        publish_id = validated_data.pop('publish_id')
        author = validated_data.pop('authors_l')
        book = Book.objects.create(**validated_data, publish_id=publish_id)
        book.author.add(*author)
        return book

    def update(self, instance, validated_data):
        print(validated_data)
        publish_id = validated_data.pop('publish_id')
        author_id = validated_data.pop('authors_l')
        for k in validated_data:
            setattr(instance, k, validated_data[k])
        instance.publish_id = publish_id
        instance.author.set(author_id)
        return instance
def update(self, instance, validated_data):
    print(validated_data) # {'book_name': 'Mona1', 'book_price': 441, 'publish_author': [1, [2, 3]]}
    publish_id = validated_data.get('publish_author')[0]
    author_id = validated_data.get('publish_author')[1]
    validated_data.pop('publish_author')
    for k in validated_data:
        setattr(instance, k, validated_data[k])
        instance.publish_id = publish_id
        instance.author.set(author_id)
        return instance

3 book,publish,author,author_detail

-把所有表的5个接口都写好
-不写author_detail,把author_detail统一放在author中

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "drftaskbook",
        "USER": "root",
        "PASSWORD": "123456",
        "HOST": "127.0.0.1",
        "PORT": 3307,
        "CHARSET": "utf8mb4",
    }
}

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

INSTALLED_APPS = [
    'book',
    'rest_framework',
]

views.py

from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Book, Publish, Authors
from .serializer import BookSerializer, PublishSerializer, AuthorsSerializer


# 所有
class BookView(APIView):
    # 查询多条
    def get(self, request):
        obj = Book.objects.all()
        if not obj:
            return Response({'code': 404, "msg": f"没有图书存在"})
        else:
            serializer = BookSerializer(instance=obj, many=True)
            return Response({'code': 200, "msg": "查询所有图书成功", "results": serializer.data})

    # 新增一条
    def post(self, request):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, "msg": "新增图书成功"})
        else:
            return Response({'code': 404, "msg": serializer.errors})


# 单个
class BookDetailView(APIView):
    # 查询单个
    def get(self, request, pk):
        obj = Book.objects.filter(pk=pk).first()
        if not obj:
            return Response({'code': 404, "msg": f"图书不存在"})
        else:
            serializer = BookSerializer(instance=obj)
            return Response({'code': 200, "msg": f"查询id为{pk}的图书成功", "results": serializer.data})

    # 删除单个
    def post(self, request, pk):
        obj = Book.objects.filter(pk=pk).first()
        if not obj:
            return Response({'code': 404, "msg": f"图书不存在"})
        else:
            obj.delete()
            return Response({'code': 200, "msg": f"删除id为{pk}的图书成功"})

    # 修改单个
    def put(self, request, pk):
        obj = Book.objects.filter(pk=pk).first()
        serializer = BookSerializer(instance=obj, data=request.data)
        if not obj:
            return Response({'code': 404, "msg": f"图书不存在"})
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, "msg": f"修改id为{pk}的图书成功", "result": serializer.data})
        else:
            return Response({'code': 200, "msg": serializer.errors})


class PublishView(APIView):
    # 查询所有出版社
    def get(self, request):
        obj = Publish.objects.all()
        serializer = PublishSerializer(instance=obj, many=True)
        if not obj:
            return Response({'code': 404, "msg": f"没有出版社存在"})
        else:
            return Response({'code': 200, "msg": "查询所有出版社成功", "results": serializer.data})

    # 添加出版社
    def post(self, request):
        serializer = PublishSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, "msg": "新增出版社成功", "result": serializer.data})
        else:
            return Response({'code': 200, "msg": serializer.errors})


class PublishDetailView(APIView):
    # 查询单个出版社
    def get(self, request, pk):
        obj = Publish.objects.filter(pk=pk).first()
        if not obj:
            return Response({'code': 404, 'msg': f"id为{pk}的出版社不存在"})
        serializer = PublishSerializer(instance=obj)
        return Response({'code': 200, "msg": f"查询id为{pk}的出版社成功", "results": serializer.data})

    # 删除单个出版社
    def post(self, request, pk):
        obj = Publish.objects.filter(pk=pk).first()
        if not obj:
            return Response({'code': 404, 'msg': f"id为{pk}的出版社不存在"})
        else:
            obj.delete()
            return Response({'code': 200, 'msg': f"删除id为{pk}的出版社成功"})

    # 修改单个出版社
    def put(self, request, pk):
        obj = Publish.objects.filter(pk=pk).first()
        serializer = PublishSerializer(instance=obj, data=request.data)
        if not obj:
            return Response({'code': 404, 'msg': f"id为{pk}的出版社不存在"})
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': f"修改id为{pk}的出版社成功", 'result': serializer.data})
        else:
            return Response({'code': 404, 'msg': serializer.errors})


class AuthorsView(APIView):
    # 查询所有作者
    def get(self, request):
        obj = Authors.objects.all()
        serializer = AuthorsSerializer(instance=obj, many=True)
        if not obj:
            return Response({'code': 404, "msg": f"没有作者存在"})
        else:
            return Response({'code': 200, "msg": "查询所有作者成功", "results": serializer.data})

    # 添加作者
    def post(self, request):
        serializer = AuthorsSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, "msg": "新增作者成功", "result": serializer.data})
        else:
            return Response({'code': 200, "msg": serializer.errors})


class AuthorsDetailView(APIView):
    # 查询单个作者
    def get(self, request, pk):
        obj = Authors.objects.filter(pk=pk).first()
        if not obj:
            return Response({'code': 404, 'msg': f"id为{pk}的作者不存在"})
        serializer = AuthorsSerializer(instance=obj)
        return Response({'code': 200, "msg": f"查询id为{pk}的作者成功", "results": serializer.data})

    # 删除单个作者
    def post(self, request, pk):
        obj = Authors.objects.filter(pk=pk).first()
        if not obj:
            return Response({'code': 404, 'msg': f"id为{pk}的作者不存在"})
        else:
            obj.delete()
            return Response({'code': 200, 'msg': f"删除id为{pk}的作者成功"})

    # 修改单个作者
    def put(self, request, pk):
        obj = Authors.objects.filter(pk=pk).first()
        serializer = AuthorsSerializer(instance=obj, data=request.data)
        if not obj:
            return Response({'code': 404, 'msg': f"id为{pk}的作者不存在"})
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': f"修改id为{pk}的作者成功", 'result': serializer.data})
        else:
            return Response({'code': 404, 'msg': serializer.errors})

serializer.py


models.py

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=32, db_index=True)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    time = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    publish = models.ForeignKey('Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField('Authors')


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)


class Authors(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='Authors_Detail', on_delete=models.CASCADE)


class Authors_Detail(models.Model):
    phone = models.CharField(max_length=11,null=True,blank=True)
    addr = models.CharField(max_length=32,null=True,blank=True)

urls.py

from django.contrib import admin
from django.urls import path, include
from book.views import BookView, BookDetailView, PublishView, PublishDetailView, AuthorsView, AuthorsDetailView

urlpatterns = [
    path('admin/', admin.site.urls),

    path('bookview/', BookView.as_view()),
    path('bookdetailview/<int:pk>', BookDetailView.as_view()),

    path('publishview/', PublishView.as_view()),
    path('publishdetailview/<int:pk>', PublishDetailView.as_view()),

    path('authorsview/', AuthorsView.as_view()),
    path('authorsdetailview/<int:pk>', AuthorsDetailView.as_view()),
]

4 拓展作业

-找一个混合的后台模板,集成到你项目中
-1 显示用户访问记录
-2 echars---》显示访问客户端类型  饼形图
	-https://echarts.apache.org/examples/zh/editor.html?c=pie-simple
-3 图书增删查改

5 登录注册修改密码接口

#1  创建用户表---》auth 的user表,扩写字段  加个  mobile
	-注册接口:手机号
    	-手机号
        -用户名:要么用手机号,要么随机生成
        -密码:设置默认密码(加密)
        
    -登陆接口:
    	-手机号+密码--》登陆成功
        
    -修改密码接口:
    	-原密码--》校验
        -更新
         ----------------------------
# 2 根据id获取用户详情
# 3 修改用户信息
# 4 查询所有用户
-----写到两个视图中--路由action--》序列化返序列化类可能不一样----  

views.py

from django.shortcuts import render
from rest_framework.viewsets import GenericViewSet
from .serializer import LoginSerializer, PassWordSerializer, RegisterSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Users


class User(GenericViewSet):
    queryset = Users.objects.all()
    serializer_class = LoginSerializer
    lookup_field = 'phone'

    def get_serializer_class(self):
        if self.action == 'edit_password':
            return PassWordSerializer
        if self.action == 'register':
            return RegisterSerializer
        else:
            return self.serializer_class

    @action(methods=['POST'], detail=False)
    def login(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            return Response({'code': 200, 'msg': '登录成功!'})
        else:
            return Response({'code': 404, 'msg': serializer.errors})

    @action(methods=['POST'], detail=False)
    def register(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': '注册成功!'})
        else:
            return Response({'code': 404, 'msg': serializer.errors})

    @action(methods=['POST'], detail=False)
    def edit_password(self, request):
        mobile = request.data.get('mobile')
        obj = Users.objects.filter(mobile=mobile).first()
        if not obj:
            return Response({'code': 404, 'msg': '手机号不存在!'})
        serializer = self.get_serializer(instance=obj, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': '修改成功!'})
        else:
            return Response({'code': 404, 'msg': serializer.errors})

urls.py

from django.contrib import admin
from django.urls import path,include
from app01.views import User
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('users',User,'users')

urlpatterns = [
    path('',include(router.urls))
]

models.py

from django.db import models
from django.contrib.auth.models import User, AbstractUser


class Users(AbstractUser):
    mobile = models.CharField(max_length=11)

serializer.py


第二版

views.py

import hashlib
import uuid

from django.shortcuts import render
from rest_framework.viewsets import GenericViewSet
from .serializer import LoginSerializer, PassWordSerializer, RegisterSerializer, DetailSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Users
from .authentication import LoginAuth


class User(GenericViewSet):
    queryset = Users.objects.all()
    serializer_class = LoginSerializer

    def get_serializer_class(self):
        if self.action == 'edit_password':
            return PassWordSerializer
        if self.action == 'register':
            return RegisterSerializer
        else:
            return self.serializer_class

    @action(methods=['POST'], detail=False)
    def login(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': '登录成功!'})
        else:
            return Response({'code': 404, 'msg': serializer.errors})

    @action(methods=['POST'], detail=False)
    def register(self, request):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': '注册成功!'})
        else:
            return Response({'code': 404, 'msg': serializer.errors})

    @action(methods=['PUT'], detail=False)
    def edit_password(self, request):
        mobile = request.data.get('mobile')
        obj = Users.objects.filter(mobile=mobile).first()
        if not obj:
            return Response({'code': 404, 'msg': '手机号不存在!'})
        serializer = self.get_serializer(instance=obj, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({'code': 200, 'msg': '修改成功!'})
        else:
            return Response({'code': 404, 'msg': serializer.errors})


# 2 根据id获取用户详情
# 3 修改用户信息
# 4 查询所有用户

from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin, ListModelMixin


class UserDetail(GenericViewSet, RetrieveModelMixin, UpdateModelMixin, ListModelMixin):
    queryset = Users.objects.all()
    serializer_class = DetailSerializer
    authentication_classes = [LoginAuth]

serializer.py


urls.py

from django.contrib import admin
from django.urls import path,include
from app01.views import User,UserDetail
from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('users',User,'users')
router.register('userdetail',UserDetail,'userdetail')

urlpatterns = [
    path('',include(router.urls))
]

models.py

from django.db import models
from django.contrib.auth.models import User, AbstractUser


class Users(AbstractUser):
    mobile = models.CharField(max_length=11)


class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to='Users', on_delete=models.CASCADE)

authentication.py


6 0417作业图书

# 1 图书的  查询单条,查询所有 
# 2 图书   新增,修改,删除
# 3 普通用户可以  查询单条,查询所有 
# 4 超级用户可以使用所有

# 5 所有接口,一天访问5次,按ip限制

# 6 图书查询所有接口
	-图书名 和 price范围过滤  
    	price_gt=10&price_lt=100
        
        
# 7 可以按价格和名字排序

# 8 查询所有接口,按 偏移分页


# 9 扩展---》继承BaseThrottle 实现频率限制

class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth]
    permission_classes = [BookPermission]

    def list(self, request, *args, **kwargs):
        qs = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(instance=qs, many=True)
        return Response({'code': 100, 'msg':'查询所有数据成功','result':serializer.data})
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'app01.throttling.CommonThrottle'
    ],
}

7 0418 jwt作业

# 1 编写全局异常处理定制统一返回格式
	-打印出错误详细信息(那个视图类报错了)
	-扩展:自定义异常类,前端收到更多错误状态码
    -扩展:研究全局异常处理源码执行流程
# 2 使用coreapi自动生成接口文档
	-postman导出导入接口
    -showdoc编写几个接口
    -扩展:搭建yapi
    -扩展:drf-yasg自动生成接口文档
    
# 3 快速体验jwt

# 4 拓展
	-登陆接口--》签发token
    	-头 header = {'typ': 'JWT', 'alg': 'HS256'}
        -荷载:{当前用户}
        -签名:md5+settings.SECRET_KEY
        -base64  adsfads.asfdasfd.asfda
    -认证:写个认证了
    	. 分成三段
        前两段 签名
        比较新的和第三段,比较成功--》使用荷载--》用户id--》拿到用户
        

异常类


views.py

from django.shortcuts import render
from rest_framework.viewsets import GenericViewSet
from django.contrib.auth.models import User
from .serializer import UserSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from django.contrib import auth
import hashlib
import json
import base64
from django.conf import settings
from .Authenticated import UserAuth
from rest_framework.mixins import ListModelMixin


class UserLoginView(GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    authentication_classes = [UserAuth]
    @action(methods=['POST'], detail=False)
    def login(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        user = auth.authenticate(request, username=username, password=password)
        if user:
            header = {'typ': 'JWT', 'alg': 'HS256'}
            auth.login(request, user)
            obj = User.objects.filter(username=username).first()
            payload = {
                key: getattr(obj, key)
                for key in ['id', 'username', 'is_superuser']
            }
            header_str = json.dumps(header)
            payload_str = json.dumps(payload)
            secret_key = settings.SECRET_KEY
            signature = header_str + payload_str + secret_key
            md5 = hashlib.md5()
            md5.update(signature.encode('utf-8'))
            res = md5.hexdigest()
            header_str_b64 = base64.b64encode(header_str.encode('utf-8'))
            payload_str_b64 = base64.b64encode(payload_str.encode('utf-8'))
            signature_b64 = base64.b64encode(res.encode('utf-8'))
            access_key = header_str_b64 + b'.' + payload_str_b64 + b'.' + signature_b64
        return Response({'code': 100, 'msg': '登录成功!', 'access_key': access_key})


class UserDetailView(GenericViewSet,ListModelMixin):
    def list(self, request, *args, **kwargs):
        return Response({'code': 200, 'msg': f'查询成功,当前用户是{request.user}'})

认证类