一:使用View+JsonResponse写获取所有数据的接口
models.py
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
views.py
from django.views import View
from .models import Book
from django.http import JsonResponse
class BookView(View):
def get(self, request):
book_list = Book.objects.all()
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return JsonResponse(res_list, safe=False, json_dumps_params={'ensure_ascii': False})
url.py
from django.urls import path
from app01.views import BookView
urlpatterns = [
path('books/', BookView.as_view()),
]
知识点总结:
- 1.queryset对象是不能够直接被序列化的
- 2.JsonResponse只能序列化列表,字典类型的数据
- 3.safe=False: 对不是字典类型的数据序列化的时候,要把safe设置为:False
- 4.json_dumps_params={‘ensure_ascii’: False}:能够让汉字正常显示在前端页面上
二:使用APIView+Response写获取所有数据的接口
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return Response(res_list)
总结:
- 1.Response:可以序列化字典,列表,字符串
- 2.一定要在settings.py文件中配置rest_farmework这个app
三:序列化组件的介绍及使用
drf提供了一种可以快速实现序列化的类:序列化类
序列化组件的基本使用:查询所有,查询单个
写一个序列化类
seralizers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
def create(self, validated_data):
res = Book.objects.create(**validated_data)
return res
def update(self, instance, validated_data):
"""
:param instance: 要修改的对象
:param validated_data: 校验过后的数据
"""
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save()
return instance
views.py
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import BookSerializer
from .models import Book
class BooksAPIView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
ser = BookSerializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response()
urls.py
from django.urls import path
from app01.views import BooksAPIView, BookDetailView
urlpatterns = [
path('books/', BooksAPIView.as_view()),
path('books/<int:pk>/', BookDetailView.as_view()),
]
总结:
- 1.视图类方法中的instance是queryset对象,表示要序列化的数据
- 2.many=True:表示序列化多条
- 3.序列化类有数据校验功能
- 4.前端传的数据,从request.data中获取
- 5.ser.save() 调用save会触发BookSerializer的save方法,判断了,如果instance有值执行update,没有值执行create
四:APIView源码分析
1.从视图类的as_view着手
path('books/', BooksAPIView.as_view()),
2.去自己定义的视图类中查找,发现没有as_view方法
3.那就去父类(APIView)中查找,as_view方法的返回值是:csrf_exempt(view),所以:所有的请求都没有csrf的校验了
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
return csrf_exempt(view)
4.请求来了,路由匹配成功会执行 View类的as_view方法内的view闭包函数(没有csrf认证)
5.真正执行的还是:APIView中的self.dispatch方法**[重点]**
def dispatch(self, request, *args, **kwargs):
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers
try:
self.initial(request, *args, **kwargs)
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
总结:
- 1.只要继承了APIView,都没有csrf的认证
- 2.视图类中使用的request对象,已经变成了drf提供的Request类的对象了
- 3.执行视图类的方法之前,执行了3大认证(认证,权限,频率)
- 4.在执行三大认证和视图类的方法过程中,只要报错,都会被捕获处理
五:Request类源码分析
1.原生的django的request对象的类:
django.core.handlers.wsgi.WSGIRequest
2.drf的request对象的类:
est_framework.request.Request
3.request不是以前的request,但是用起来还是和原先一样
request.method
request.path
request.GET
request.POST
4.Request源码分析
def __getattr__(self, attr):
"""
如果取的属性不存在,会去原生的django的request对象中去取
If an attribute does not exist on this instance, then we also attempt
to proxy it to the underlying HttpRequest object.
"""
try:
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
print(type(request._request))
总结:
- 1.新的request内有一个老的request,就是:request._request
- 2.data 是一个方法,被property装饰了,变成了属性
- 3.以后body中提交的数据,都从request.data中取,原先是从(request.POST)
- 4.-urlencoded,form-data:提交的数据在request.POST中
- 5.-json格式提交的数据,在requets.POST中没有,它在request.body中
- 6.以后无论哪种数据类型,都从request.data中取
- 7.取文件,还是从request.FILES中取
- 8.query_params:get请求提交的参数,等同于request._request.GET 或 request.GET
- 9.以后用的所有属性或方法,直接用就可以了(通过反射去原来的request中取的)
作业1:
1 继承apiview写5个接口
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return Response(res_list)
def post(self, request):
name = request.data.get('name')
price = request.data.get('price')
publish = request.data.get('publish')
if Book.objects.create(name=name, price=price, publish=publish):
res_list = [{'name': name, 'price': price, 'publish': publish}]
return Response(res_list)
class BookDetailView(APIView):
def get(self, request, pk):
book_list = Book.objects.filter(pk=pk).all()
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return Response(res_list)
def put(self, request, pk):
name = request.data.get('name')
price = request.data.get('price')
publish = request.data.get('publish')
Book.objects.filter(pk=pk).update(name=name, price=price, publish=publish)
book_list = Book.objects.filter(pk=pk).all()
res_list = []
for book in book_list:
res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return Response(res_list)
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response()
作业2:
2.写一个装饰器,装饰在视图函数,只要一装饰,以后的request就可以使用request.data,这个data无论是那种编码格式,都有数据。
import json
def outer(func_name):
def inner(request, *args, **kwargs):
try:
request.data = json.loads(request.body)
except:
request.data = request.POST
res = func_name(request, *args, **kwargs)
return res
return inner
@outer
def func(request):
print(request.data)
return JsonResponse({})
urls.py
path('func/', views.func),
|