drf 序列化组件
准备:
配置:settings.py
INSTALLED_APPS = [ 'rest_framework', ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'dg_proj', 'USER': 'root', 'PASSWORD': '123', } } LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') REST_FRAMEWORK = { # 全局配置异常模块 'EXCEPTION_HANDLER': 'api.exception.exception_handler', }
任何__init__文件
import pymysql
pymysql.install_as_MySQLdb()
主路由
from django.views.static import serve from django.conf import settings urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^api/', include('api.urls')), url(r'^media/(?P<path>.*)', serve, {'document_root':settings.MEDIA_ROOT}), ]
子路由
from django.conf.urls import url from . import views urlpatterns = [ url(r'^books/$',views.Book.as_view()), url(r'^books/(?P<pk>.*)/$',views.Book.as_view()), ]
model 类 多表设计
# 基表 class BaseModel(models.Model): is_delete = models.BooleanField(default=False) create_time = models.DateTimeField(auto_now_add=True) # 作为基表的model不能在数据库形成对应的表,设置abstract=True class Meta: abstract = True class Book(BaseModel): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=5, decimal_places=2) img = models.ImageField(upload_to='img', default='img/default.jpg') publish = models.ForeignKey( to='Publish', db_constraint=False, # 断关联 related_name='books', # 反向查询字段:publish_obj.books 就能访问所有出版的书 on_delete=models.DO_NOTHING, # 设置连表操作关系 ) authors = models.ManyToManyField( to='Author', db_constraint=False, related_name='books' ) @property def publish_name(self): return self.publish.name @property def author_list(self): return self.authors.values('name', 'age', 'detail__mobile').all() class Meta: db_table = 'book' verbose_name = '书籍' verbose_name_plural = verbose_name def __str__(self): return self.name class Publish(BaseModel): name = models.CharField(max_length=64) address = models.CharField(max_length=64) class Meta: db_table = 'publish' verbose_name = '出版社' verbose_name_plural = verbose_name def __str__(self): return self.name class Author(BaseModel): name = models.CharField(max_length=64) age = models.IntegerField() class Meta: db_table = 'author' verbose_name = '作者' verbose_name_plural = verbose_name def __str__(self): return self.name class AuthorDetail(BaseModel): mobile = models.CharField(max_length=11) author = models.OneToOneField( to='Author', db_constraint=False, related_name='detail', on_delete=models.CASCADE, ) class Meta: db_table = 'author_detail' verbose_name = '作者详情' verbose_name_plural = verbose_name def __str__(self): return '%s的详情' % self.author.name
admin.py 中注册
from . import models admin.site.register(models.Author) admin.site.register(models.AuthorDetail) admin.site.register(models.Book) admin.site.register(models.Publish)
序列化
序列化层:api/serializers.py
from rest_framework.serializers import ModelSerializer,SerializerMethodField from rest_framework.exceptions import ValidationError from . import models # 可以单独作为Publish接口的序列化类,也可以作为Book序列化外键publish辅助的序列化组件 class PublishModelSerializer(ModelSerializer): class Meta: model = models.Publish fields = ('name', 'address') class BookModelSerializer(ModelSerializer): # 自定义连表深度,子序列化方式 该方式不能参与反序列化,使用在序列化反序列化共存时 publish = PublishModelSerializer() class Meta: # 序列化类关联的model类 model = models.Book # 参与序列化的字段 fields = ('name','price','img','author_list','publish')
视图层:api/views.py
from . import serializers
class Book(APIView): def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: try: book_obj = models.Book.objects.get(pk=pk, is_delete=False) book_data = serializers.BookModelSerializer(book_obj).data except: return Response({ 'status': 1, 'msg': '书籍不存在' }) else: book_query = models.Book.objects.filter(is_delete=False).all() book_data = serializers.BookModelSerializer(book_query,many=True).data return Response({ 'status': 0, 'msg': 'ok', 'results':book_data })
反序列化
路由层:api/urls.py
urlpatterns = [ url(r'^books/$',views.Book.as_view()), url(r'^books/(?P<pk>.*)/$',views.Book.as_view()), ]
序列化层:api/serializers.py
class BookModelDeserializer(ModelSerializer): class Meta: model = models.Book fields = {'name','price','publish','authors'} # extra_kwargs 用来完成反序列化字段 系统校验规则 extra_kwargs = { 'name': { 'required': True, 'min_length': 1, 'error_message': { 'required': '必填项', 'min_length': '太短' } } } # 局部钩子 def validate_name(self,value): # 书名不能含g 字符 if 'g' in value.lower(): raise ValidationError('该g书不能出版') return value # 全局钩子 def validate(self, attrs): publish = attrs.get('publish') name = attrs.get('name') if models.Book.objects.filter(name=nam e,publish=publish): raise ValidationError({'book':'该书已存在'}) return attrs
settings.py
REST_FRAMEWORK = { # 全局配置异常模块 'EXCEPTION_HANDLER': 'api.exception.exception_handler', }
exception.py异常处理文件
from rest_framework.views import exception_handler as drf_exception_handler from rest_framework.views import Response from rest_framework import status def exception_handler(exc, context): # drf的exception_handler做基础处理 response = drf_exception_handler(exc, context) # 为空,自定义二次处理 if response is None: print('%s - %s - %s' % (context['view'], context['request'].method, exc)) return Response({ 'detail': '服务器错误' }, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True) return response
视图层:api/views.py
class Book(APIView): def post(self, request, *args, **kwargs): request_data = request.data book_ser = serializers.BookModelDeserializer(data=request_data) # raise_exception=True:当校验失败,终止当前视图方法,抛出异常返回给前台 book_ser.is_valid(raise_exception=True) book_obj = book_ser.save() return Response({ 'status':0, 'msg':'ok', 'results':serializers.BookModelDeserializer(book_obj).data })
序列化与反序列化整合(重点)
fields中设置所有序列化与反序列化字段, extra_kwargs划分只序列化或只反序列化字段
write_only:只反序列化
read_only:只序列化
自定义字段默认只序列化(read_only)
设置反序列化所需的 系统、局部钩子、全局钩子 等校验规则
class V2BookModelSerializer(ModelSerializer): class Meta: model = models.Book fields = {'name','price','img','author_list','publish_name', 'publish', 'authors'} extra_kwargs = { 'name':{ 'required': True, 'min_length': 1, 'error_messages': { 'required':'必填项', 'min_length': '太短', } }, 'publish':{ 'write_only':True }, 'authors': { 'write_only': True }, 'img': { 'read_only': True, }, 'author_list': { 'read_only': True, }, 'publish_name': { 'read_only': True, } } def validate_name(self,value): if 'g' in value.lower(): raise ValidationError('该g书不能出版') return value def validate(self, attrs): publish = attrs.get('publish') name = attrs.get('name') if models.Book.objects.filter(name=name,publish=publish): raise ValidationError({'book':'该书已存在'}) return attrs
视图层:api/views.py
class V2Book(APIView):
# 单查:有pk 群查: 无pk def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: try: book_obj = models.Book.objects.get(pk=pk,is_delete=False) book_data = serializers.V2BookModelSerializer(book_obj).data except: return Response({ 'status':1, 'msg':'书籍不存在' }) else: book_query = models.Book.objects.filter(is_delete=False).all() book_data = serializers.V2BookModelSerializer(book_query,many=True).data return Response({ 'status':0, 'msg':'ok', 'results':book_data }) 单增:传的数据是与model对应的字典
群增:传的数据是 装多个 model对应字典 的列表 def post(self, request, *args, **kwargs): request_data = request.data if isinstance(request_data, dict): many = False elif isinstance(request_data,list): many = True else: return Response({ 'status':1, 'msg':'数据有误' }) book_ser = serializers.V2BookModelSerializer(data=request_data,many=many) book_ser.is_valid(raise_exception=True) book_result = book_ser.save() return Response({ 'status': 0, 'msg': 'ok', 'results':serializers.V2BookModelSerializer(book_result,many=many).data }) def delete(self,request,*args,**kwargs):
# 单删 有pk 群删 无pks pk = kwargs.get('pk') if pk: pks = [pk] else: pks = request.data.get('pks') if models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True): return Response({ 'status':0, 'msg':'删除成功' }) return Response({ 'status':1, 'msg':'删除失败' })
dayehui