=================================================================基于CBV写5个接口(增,删,改,查单个,查所有)

1)模型表

 2)views.py

 1 from django.shortcuts import render
 2 from .models import Task
 3 import json
 4 from django.http import JsonResponse
 5 from django.views import View
 6 
 7 
 8 # Create your views here.
 9 
10 # CBV写5个接口
11 class TaskView(View):
12     # 查询所有
13     def get(self, request):
14         task_queryset = Task.objects.all()
15         print(task_queryset)
16         # 转成json格式给前端
17         # 把queryset对象转化成列表,然后再使用JsonResponse,
18         task_list = []
19         for task_obj in task_queryset:
20             # 将任务对象转换为字典并添加到列表中
21             task_list.append({
22                 # 如果是uuid形式 str(task_obj.task_id),模型表也要改为uuid形式
23                 'task_id': task_obj.task_id,
24                 'task_name': task_obj.task_name,
25                 'task_time': task_obj.task_time,
26                 'task_desc': task_obj.task_desc
27             })
28 
29             # 创建最终的响应数据字典
30         response_data = {
31             'code': 100,
32             'msg': '查询成功',
33             'results': task_list
34         }
35 
36         # 返回JsonResponse
37         return JsonResponse(response_data)
38 
39     # 新增,新增一个(只能使用urlencoded或form-data编码,使用json格式编码不行,因为json格式编码提交的数据不能从request.POST中取,要从body中取!)
40     def post(self, request):
41         task_id = request.POST.get('task_id')
42         print(task_id)
43         task_name = request.POST.get('task_name')
44         task_time = request.POST.get('task_time')
45         task_desc = request.POST.get('task_desc')
46         # 存到数据库中
47         task_obj = Task.objects.create(task_id=task_id, task_name=task_name, task_time=task_time, task_desc=task_desc)
48         # 返回新增的对象字典
49         return JsonResponse(
50             {'task_id': task_obj.task_id, 'task_name': task_obj.task_name, 'task_time': task_obj.task_time,
51              'task_desc': task_obj.task_desc})
52 
53 
54 class TaskDetailView(View):
55     # 获取单个数据
56     def get(self, request, pk):
57         task_obj = Task.objects.filter(id=pk).first()
58         return JsonResponse(
59             {'task_id': task_obj.task_id, 'task_name': task_obj.task_name, 'task_time': task_obj.task_time,
60              'task_desc': task_obj.task_desc})
61 
62     # 更新任务
63     def put(self, request, pk):
64         # 获取前端传递的数据
65         task_obj = Task.objects.filter(id=pk).first()
66         #  # 取出前端数据修改完保存,但是put提交到的数据request.POST取不到,在request.body里面还没有切割了是name=xxx&price=yyy这种形式,直接取不方便
67         # task_obj.task_name=request.POST.get('task_name')
68         # task_obj.task_time=request.POST.get('task_time')
69         # task_obj.task_desc=request.POST.get('task_desc')
70         # task_obj.save()
71 
72         # 需要前端使用json格式编码提交数据,自己保存
73         task_dict = json.loads(request.body.decode())
74         task_obj.task_id = task_dict.get('task_id')
75         task_obj.task_name = task_dict.get('task_name')
76         task_obj.task_time = task_dict.get('task_time')
77         task_obj.task_desc = task_dict.get('task_desc')
78         task_obj.save()
79         return JsonResponse(
80             {'task_id': task_obj.task_id, 'task_name': task_obj.task_name, 'task_time': task_obj.task_time,
81              'task_desc': task_obj.task_desc}, json_dumps_params={'ensure_ascii': False})
82 
83     # 删除任务
84     def delete(self, request, pk):
85         # 直接删除就好
86         Task.objects.filter(id=pk).delete()
87         return JsonResponse({'code': 100, 'msg': '删除成功'})

3)路由配置

 

 

=================================================================================基于APIView写5个接口

 (views.py)

from django.shortcuts import render

# Create your views here.

from django.http import JsonResponse
from django.shortcuts import render
from rest_framework.response import Response

# Create your views here.
# 继承APIView,支持3种编码格式:json, html, xml
from rest_framework.views import APIView
from app01.models import Book
# from app01.ser import BookSerializer


class BookView(APIView):
# 获取所有图书
def get(self, request):
      
# 新的request对象
# 补充知识点,其实type是一个函数,可以判断一个对象的类型
print(type(request)) # rest_framework.request.Request
# 老的request
print(type(request._request)) # class django.core.handlers.wsgi.WSGIRequest
      obj_list = Book.objects.all()
book_list = []
for obj in obj_list:
book_list.append({'name': obj.name, 'price': obj.price, 'publish': obj.publish})
return JsonResponse({'code': 100, 'msg': '查询成功', 'results': book_list})

# 新增
def post(self, request):
# 前端无论以什么编码格式--》提交到后端你的数据,都会被解析到 request.data 中,是个字典
# 如果是urlencoded或form-data编码--》不能直接这样写,要写成如下
Book.objects.create(name=request.data.get('name'), price=request.data.get('price'),
publish=request.data.get('publish'))
# 如果是json格式--》
# Book.objects.create(**request.data)
print(request.POST)
print(request.data)
# 本质原因是?
'''
APIView帮咱们呢---》看POST中有没有数据,如果有,直接赋值给data,如果没有,他去body中转成字典再给data
json格式:
POST没有东西 QueryDict
data有数据 dict
urlencoded或form-data
POST有东西 QueryDict
data有数据 QueryDict
'''
return JsonResponse({'code': 100, 'msg': '新增成功'})


class BookDetailView(APIView):
# 获取单个数据
def get(self, request, pk):
obj = Book.objects.filter(pk=pk).first()
return JsonResponse(
{'code': 100, 'msg': '查询成功', 'result': {'name': obj.name, 'price': obj.price, 'publish': obj.publish}})

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

def put(self, request, pk):
Book.objects.filter(pk=pk).update(**request.data)
return JsonResponse({'code': 100, 'msg': '修改成功'})

URLS.PY
from
django.contrib import admin from django.urls import path from app01.views import BookView, BookDetailView urlpatterns = [ path('admin/', admin.site.urls), # 查询所有任务 path('books/', BookView.as_view()), # 新增任务 path('books/create/', BookView.as_view()), # 获取单个任务详情 path('books/<int:pk>/', BookDetailView.as_view()), # 更新任务 path('books/<int:pk>/update/', BookDetailView.as_view()), # 删除任务 path('books/<int:pk>/delete/', BookDetailView.as_view()), ]

APIView总结:

1 只要继承了APIView,不需要处理csrf
2 以后前端提交的数据,无论什么编码,无论什么请求方式,数据都从 request.data 取,它是字典
	-可能是:QueryDict
    	-不是真正的字典,用起来,可能会有点小问题
    -可能是:dict


====================================================APIView处理流程
 1 # 1 APIView继承了 Django的View---》 class APIView(View)
 2 
 3 # 2 请求来了,路由匹配成功后---》执行流程
 4     2.1 路由配置 path('books/', BookView.as_view()),
 5     2.2 BookView.as_view()(request)-->BookView中没有as_view--》找父类APIView的as_view
 6         BookView-->APIView-->View
 7         
 8     2.3 APIView的as_view
 9         @classmethod # 绑定给类的方法,类来调用
10         def as_view(cls, **initkwargs):
11             # super代指父类--》父类是View--》之前读过--》self.dispatch()
12             # 这个view 还是原来View的as_view的执行结果--》as_view中有个view内部函数
13             view = super().as_view(**initkwargs)
14             # 只要继承了APIView,不需要处理csrf
15             '''
16             @csrf_exempt
17             def index(request):
18                 pass
19                等同于  index=csrf_exempt(index)
20                以后调用index,其实调用的 是csrf_exempt(index)()
21             '''
22             return csrf_exempt(view)
23      2.4 请求来了,真正执行的是:csrf_exempt(view)(request)-->去除了csrf的view(request)--》self.dispatch()
24      2.5 请求来了,真正执行的是 self.dispatch(request)--->self 是 视图类的对象
25          BookView的对象--》自己没有--》APIView中
26      2.6 现在要看 APIView的dispatch
27      def dispatch(self, request, *args, **kwargs):
28         # 1 包装了新的request对象---》现在这个requets对象,已经不是原来django的request对象了
29         request = self.initialize_request(request, *args, **kwargs)
30         try:
31             # 2 APIView的initial--》三件事:三大认证:认证,频率,权限
32             self.initial(request, *args, **kwargs)
33             # 3 就是执行跟请求方式同名的方法
34             if request.method.lower() in self.http_method_names:
35                 handler = getattr(self, request.method.lower(),
36                                   self.http_method_not_allowed)
37             else:
38                 handler = self.http_method_not_allowed
39 
40             response = handler(request, *args, **kwargs)
41             # 4 如果在三大认证或视图类的方法中出了异常,会被统一捕获处理
42         except Exception as exc:
43             response = self.handle_exception(exc)
44 
45         self.response = self.finalize_response(request, response, *args, **kwargs)
46         return self.response
47  # 执行流程总结
48     1 只要继承了APIView,就没有csrf限制了
49     2 只要继承了APIView,request就是新的request了,它有data
50     3 在执行跟请求方式同名的方法之前,执行了三大认证:认证,频率,权限
51     4 只要在三大认证或者视图类的方法中出了异常,都会被捕获,统一处理

其实就是APIView执行as_view,而as_view是APIView的as_view,而它有调用了父类的
,但是又去除了csrf的认证,最后还是执行self.dispatch

 PS:

  

Request对象
#1 APIView执行流程---》request对象---》变成了新的
    -多了 request.data
#2 新的Request具体是哪个类的对象
    rest_framework.request.Request 类的对象
#3 老的request是哪个类的对象
    django.core.handlers.wsgi.WSGIRequest
    
# 4 老的request可以
    -request.method
    -request.path
    -request.META.get('REMOTE_ADDR')
    -request.FILES.get()
    ...
# 5 新的request支持之前所有老request的操作
    -1 之前如何用,还是如何用
    -2 request.data-->请求体的数据--》方法包装成了数据属性
       @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()
            return self._full_data
    -3 request.query_params--->原来的request.GET--》贴合restful规范-》
        @property
        def query_params(self):
            return self._request.GET
    
    
    -4 request._request 就是老的request
    
    
# 6 源码分析---》为什么:之前如何用,还是如何用?没有继承关系
    from rest_framework.request import Request
    -__getattr__: .拦截方法,对象.属性,如果属性不存在,就会触发__getattr__执行
    -requst.method -->新的request没有--》会触发新的Request类中的 __getattr__
        def __getattr__(self, attr):
            try:
                # 根据字符串 _request 获取self中的属性
                # _request 就是原来老的request
                _request = self.__getattribute__("_request")
                # 通过反射,去老的request中,获取属性
                return getattr(_request, attr)
            except AttributeError:
                return self.__getattribute__(attr)
            
# 总结:记住的 新的request
    -1 之前如何用,还是如何用
    -2 request.data-->请求体的数据--》方法包装成了数据属性
    -3 request.query_params--->原来的request.GET--》贴合restful规范--4 request._request 就是老的request
    -5 魔法方法之 __getattr__

PS:魔法方法

# python 中有很多魔法方法,在类中,某种情况下触发,会自动执行
	-__str__:打印对象会调用
	-__init__:类() 会调用
	-__call__: 对象() 会调用
	-__new__:
	-__getattr__:对象.属性,如果属性不存在,会触发它的执行

=============================================================继承APIView+drf的序列化类写5个接口

 

序列化类的介绍 

#1 基于APIView写5个接口
	-做序列化的时候,方法很笨,手动做的
    -后期如果想多序列化某个或少序列化某个字段,比较麻烦
    
#2 借助于 drf 提供的序列化类
	1 帮助我们快速序列化
    2 帮助我们做反序列化之前的数据校验
    3 帮助我们做反序列化
    
# 3 序列化类使用之序列化
	3.1 写一个类,继承Serialier
    3.2 在类中写字段,字段就是要序列化的字段
    3.3 在视图函数中,序列化类,实例化得到对象,传入该传的参数
    	- 多条
        - 单条
    3.4 调用序列化类对象的 serializer.data 方法完成序列化

 

 VIEWS.py

  # 反序列化类
1
class BookView(APIView): 2 # 获取所有图书 3 def get(self, request): 4 books = Book.objects.all() 5 book_ser = BookSerializer(instance=books, many=True) # 序列化多条,用many=True,序列化一条不需要,instance必须传,book是需要序列化的对象 6 return Response({'status': 100, 'msg': '查询成功', 'results': book_ser.data}) 7 8 # 新增需要重写create方法 9 def post(self, request): 10 response_msg = {'status': 100, 'msg': '新增成功'} 11 # 修改有instance ,新增没有,只有data 12 book_ser = BookSerializer(data=request.data) 13 # 校验字段 14 if book_ser.is_valid(): 15 book_ser.save() # 保存失败,需要在序列化类中重写create方法 16 response_msg['data'] = book_ser.data 17 else: 18 response_msg['status'] = 101 19 response_msg['msg'] = '新增失败' 20 response_msg['data'] = book_ser.errors 21 return Response(response_msg) 22 23
    # 序列化类 24 class BookDetailView(APIView): 25 # 获取单个 26 def get(self, request, pk): 27 book = Book.objects.filter(pk=pk).first() 28 # 类实例化,调用类的__init__方法,想序列化谁,就把谁传进来,序列化单条,就不需要传many=True 29 book_ser = BookSerializer(instance=book) 30 return Response({'status': 100, 'msg': '查询单个', 'results': book_ser.data}) 31 32 # 删除 33 def delete(self, request, pk): 34 Book.objects.filter(pk=pk).delete() 35 return JsonResponse({'code': 100, 'msg': '删除成功'}) 36 37 # 修改,需要重写update方法 38 def put(self, request, pk): 39 response_msg = {'status': 100, 'msg': '修改成功'} 40 # 找到要修改的对象 41 book = Book.objects.filter(id=pk).first() 42 # 得到一个序列化类的对象,用request.data来修改book对象 43 book_ser = BookSerializer(instance=book, data=request.data) 44 # 判断序列化是否成功 45 if book_ser.is_valid(): 46 book_ser.save() # 直接book_ser.save()报错,update()must be implemented(重写父类方法),是序列化器的.save方法 47 response_msg['data'] = book_ser.data 48 49 else: 50 response_msg['status'] = 101 51 response_msg['msg'] = '修改失败' 52 response_msg['data'] = book_ser.errors 53 return Response(response_msg)

 

序列化器

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01.models import Book

from rest_framework import serializers


# 序列化的使用
class BookSerializer(serializers.Serializer):
    # 不想序列化谁,就把谁注释即可
    name = serializers.CharField(max_length=8, min_length=3)
    price = serializers.IntegerField(max_value=100, min_value=10)
    publish = serializers.CharField()

    # 新增重写create方法
    def create(self, validated_data):
        # validated_data:前端传入,所有校验通过的数据,字典形式
        instance = Book.objects.create(**validated_data)
        return instance

    def validate_name(self, name):
        if 'sb' in name:
            # 不合法,抛异常
            raise ValidationError('书名不能以sb开头')
        else:
            # 合法,返回原来的数据
            return name

    # 局部钩子:validate_字段名
    def validate_price(self, data):  # validate_字段名,必须接收一个参数
        # 如果价格低于10元,校验失败
        if float(data) > 10:
            return data
        else:
            # 抛出异常
            raise ValidationError("价格必须高于10元")

    # 全局钩子
    # def validate(self, validate_data):
    #     print(validate_data)
    #     name = validate_data.get('name')
    #     publish = validate_data.get('publish')
    #     if name == publish:
    #         raise ValidationError("书名和出版社不能相同")
    #
    #     return validate_data
    # 另外一种全局钩子,如果写多个,但只会以最后一个校验生效
    def validate(self, attrs):
        # attrs是前端传入,经过字段自己校验和局部钩子校验都通过的数据(字典)
        if attrs.get('name') == attrs.get('publish'):
            raise ValidationError("书名和出版社不能相同")
        else:
            return attrs

    # 修改,重写update方法
    def update(self, instance, validated_data):
        # 更新数据,instance是book对象
        instance.name = validated_data.get('name', instance.name)
        instance.price = validated_data.get('price', instance.price)
        instance.publish = validated_data.get('publish', instance.publish)
        instance.save()  # book.save() django的orm提供的
        return instance

 

 

 

PS:补充

print(type(reuqest.POST)),type是一个类,object也是一个类,两者的联系和区别

  type继承object,object是由type产生的

  

posted on 2024-04-11 17:52  认真的六六  阅读(23)  评论(0编辑  收藏  举报