反序列化类校验部分源码解析
视图类中的 ser.is_valid(),就会执行校验,校验通过返回True,不通过返回False
def is_valid(self, *, raise_exception=False):
if not hasattr(self, '_validated_data'):
try:
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
切记一定不要按住ctrl键点击
真正的执行顺序是,从上往下找,找不到,再往上
最终从Serializer类中找到了run_validation而不是Field中的run_validation
def run_validation(self, data=empty):
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
value = self.to_internal_value(data)
try:
self.run_validators(value)
value = self.validate(value)
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
def to_internal_value(self, data):
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
断言assert
name = 'lqz'
assert name=='lqz'
print('后续代码')
drf请求
Request能够解析的前端传入的编码格式
class BookView(APIView):
parser_classes = [JSONParser,]
django有套默认配置,每个项目有个配置
drf也有套默认,每个项目也有个配置----》就在django的配置文件中
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
],
}
只需要在视图类,配置3个即可
因为:先从视图类自身配置找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置找
Request类有哪些属性和方法(前面写过了)
1 新的request用起来,跟之前一模一样,因为新的取不到,会取老的__getattr__
2 request.data 无论什么编码,什么请求方式,只要是body中的数据,就从这里取,字典
3 request.query_params 就是原来的request._request.GET
4 上传的文件从request.FILES里面取
drf之响应
Response能够响应的编码格式
drf 是django的一个app 所以需要注册
drf 的响应,如果使用浏览器和postman访问同一个接口,返回格式是不一样的
drf做个判断 如果是浏览器 好看一些 如果是postman只要json数据
方式一 : 在视图类中写(局部配置)
两个响应类---》找--》drf的配置文件中找---》两个类
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,]
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer',
],
}
优先使用视图类中的配置,其次使用项目配置文件中的配置,最后使用内置的
Response的源码属性或方法
drf 的Response源码分析
from rest_framework.response import Response
视图类的方法返回时,return Response,走它的__init__,ini中可以传什么参数
def __init__(self,
data=None,
status=None,
template_name=None,
headers=None,
exception=False,
content_type=None)
data:之前咱们写的ser.data 可以是字典或列表,字符串---》序列化后返回给前端---》前端在响应体中看到的就说这个
status:http响应的状态码,默认是200 可以改
drf在status包下,把所有http响应状态码都写一遍 常量
from rest_framework.status import HTTP_200_OK
def get(self, request):
return Response('ddd', status=status.HTTP_200_OK)
template_name: 了解即可 修改响应模板的样子,BrowsableAPIRenderer定死的样子,后期公司可以自己定制
headers:响应头 http响应的响应头
原生django 如何向响应头中加东西
obj = HttpResponse('ddd')
obj['xxxc'] = 'yyy'
return obj
content_type:响应编码格式,一般不动
重点:data,status,headers
视图组件介绍及两个视图基类
drf 视图,视图类,学过APIView,drf的基类drf提供最顶层的类
传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequest对象;
视图方法可以返回REST framework的Response对象
任何APIException异常都会被捕获到,并且处理成合适的响应信息
在进行dipatch()分发前,会对请求进行身份认证、权限检查、流量控制
APIView
类属性:
renderer_classes
parser_classes
authentication_classes
throttle_classes
permission_classes
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.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=11)
基于APIView+ModelSerializer+Response写5个接口
视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
ser = BookSerializer(instance=books, many=True)
return Response(ser.data)
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'mag': '新增成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDetailView(APIView):
def get(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books)
return Response(ser.data)
def put(self, request, pk):
books = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=books, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'mag': '修改成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request, pk):
Book.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '删除成功'})
序列化类
两种定制字段方式 注释部分和表模型中配合使用
from rest_framework import serializers
from .models import Book, Publish, Author
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish': {'write_only': True},
'authors': {'write_only': True}, }
publish_detail = serializers.SerializerMethodField(read_only=True)
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'addr': obj.publish.addr}
author_list = serializers.SerializerMethodField(read_only=True)
def get_author_list(self, obj):
l = []
for author in obj.authors.all():
l.append({'name': author.name, 'phone': author.phone})
return l
def validate_name(self, name):
if name.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return name
路由
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
基于GenericAPIView+ModelSerializer+Response写5个视图接口
视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.response import Response
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
objs = self.get_queryset()
ser = BookSerializer(instance=objs, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'mag': '新增成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request,pk):
obj = self.get_object()
ser = self.get_serializer(instance=obj)
return Response(ser.data)
def put(self, request,pk):
obj = self.get_object()
ser = self.get_serializer(instance=obj, data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'mag': '修改成功', 'result': ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self, request,pk):
self.get_object().delete()
return Response({'code': 100, 'msg': '删除成功'})
序列化类
from rest_framework import serializers
from .models import Book, Publish, Author
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish': {'write_only': True},
'authors': {'write_only': True}, }
publish_detail = serializers.SerializerMethodField(read_only=True)
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'addr': obj.publish.addr}
author_list = serializers.SerializerMethodField(read_only=True)
def get_author_list(self, obj):
l = []
for author in obj.authors.all():
l.append({'name': author.name, 'phone': author.phone})
return l
def validate_name(self, name):
if name.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return name
路由
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
基于GenericAPIView+Response写5个接口总结
'''
# 属性
1 queryset:要序列化或反序列化的表模型数据
2 serializer_class:使用的序列化类
3 lookup_field :查询单条的路由分组分出来的字段名
4 filter_backends:过滤类的配置(了解)
5 pagination_class:分页类的配置(了解)
# 方法
1 get_queryset :获取要序列化的对象
2 get_object :获取单个对象
3 get_serializer :获取序列化类 ,跟它差不多的get_serializer_class,一般重写它,不调用它
4 filter_queryset :过滤有关系(了解)
'''
基于GenericAPIView+5个视图扩展类
视图类
from .models import Book
from .serializer import BookSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律