=================================================================基于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产生的