Drf之模型序列化方式总结(四)

本文深入探讨了Django REST framework(DRF)中的序列化过程,包括普通序列化、基于Model的序列化、嵌套序列化及自定义序列化字段等核心概念。详细介绍了序列化与反序列化的基本原理,以及在连表操作、字段定制和数据深度控制方面的应用。

普通drf序列化

# models.py
class Students(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    gender = models.CharField(max_length=8)
    def __str__(self):
        return 'Student: %s' % self.name
    

# 自定义序列化类:为具体的类提供序列化
# my_serializer.py
from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
    # 1.如果没有source引入models的字段名,序列化字段名必须同models的字段名
    # 2.如果有source引入models的字段名,序列化字段名必须不同于models的字段名,目的是对外隐藏数据库的字段名
    id = serializers.IntegerField()
    stu_name = serializers.CharField(source='name')
    age = serializers.IntegerField()
    gender = serializers.CharField()
    

# views.py
from app import models
from app.my_serializer import StudentSerializer
class Students(APIView):
    def get(self, request, *args, **kwargs):
        stus = models.Students.objects.all()
        # 需要序列化多个对象,需要明确many=True
        stu_ser = StudentSerializer(stus, many=True)
        print(stus)
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': stu_ser.data
        })
    
    
# urls.py
from app import views
urlpatterns = [
    url(r'^students/', views.Students.as_view()),
]
# 数据的传输与文件存储均是采用字符串格式

# 序列化:将对象转换成字符串的过程,进而用来传输或存储
# 反序列化:将字符串转换为对象的过程,在程序中使用

orm无关联连表操作

# models.py
class User(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    # 1)db_constraint=False:断开外键关联,数据库操作效率提高
    # 2)避免脏数据的参数,要允许外键可为null
    # 3)on_delete=models.SET_NULL与2)协同在外键关联的数据删除掉会自动置空
    user_detail = models.OneToOneField(to='UserDetail', null=True, on_delete=models.SET_NULL, db_constraint=False)

class UserDetail(models.Model):
    phone_num = models.CharField(max_length=11)
    info = models.TextField()
    
# views.py
from app import models
def test(request):
    # models.UserDetail.objects.filter(id=1).delete()
    user = models.User.objects.first()  # type: models.User
    return HttpResponse(user.user_detail.phone_num)

函数作为模型对象序列化

# models.py
class User(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    user_detail = models.OneToOneField(to='UserDetail', null=True, on_delete=models.SET_NULL, db_constraint=False)
    # 在model中产生的全局空间名字,都可以被序列化
    def account(self):
        return self.user + ":" + self.pwd
    
class UserDetail(models.Model):
    phone_num = models.CharField(max_length=11)
    info = models.TextField()
    

两种嵌套的序列化方式(重要)

序列化方式1
# app/objson.py (序列化层)
class UserJson(serializers.Serializer):
    # 不序列化的字段不对外提供
    # id = serializers.IntegerField()
    name = serializers.CharField(source='user')
    password = serializers.CharField(source='pwd')
    # 对指定的名字序列化(名字可以为普通对象、函数对象、类对象)
    account = serializers.CharField()
   
    # 在同一层产生数据
    # user_phone = serializers.CharField(source='user_detail.phone_num')
    # user_info = serializers.CharField(source='user_detail.info')

   
    # 产生一个序列化的字段(detail) => 可以通过get_字段名(get_detail)完成ORM的连表操作,完成序列化
    detail = serializers.SerializerMethodField()  # 本质:改字段的值由方法提供
    def get_detail(self, obj):  # 该方法的命名规范必须是 get_字段名(self, obj)
        # obj就是序列化类的对象(models.User类的对象)
        # 对象就可以利用ORM完成连表操作
        phone_num = obj.user_detail.phone_num
        info = obj.user_detail.info
        # 这里想返回什么格式都可以,字典和列表都随意
        return {'phone': phone_num, 'info': info}
序列化方式2
class UserDetailJson(serializers.Serializer):
    phone_num = serializers.CharField()
    info = serializers.CharField()

class UserJson(serializers.Serializer):
    name = serializers.CharField(source='user')
    password = serializers.CharField(source='pwd')
    account = serializers.CharField()
    
    detail = serializers.SerializerMethodField()
    def get_detail(self, obj): #obj是当前类名
        # 拿到UserDetail类的连表对象
        detail_obj = obj.user_detail  #obj.字段名
        # 完成序列化
        detail_data = UserDetailJson(detail_obj).data   #把字段名对象丢入另外的表格式化
        # 返回序列化后的数据
        return detail_data

基于Model的序列化

数据层:models.py
class Book(models.Model):
    name = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 多对多存在第三张表,只需要断开关联即可
    author = models.ManyToManyField(to='Author', db_constraint=False)

class Author(models.Model):
	    name = models.CharField(max_length=20)
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.SET_NULL, null=True, db_constraint=False)

class AuthorDetail(models.Model):
    age = models.IntegerField()
    telephone = models.BigIntegerField()
    
# objson.py

序列化层:objson.py
"""
1) 用Meta的model来绑定序列化的类
2) fields = '__all__': 序列化所有字段
3) fields = ['字段1', ..., '字段2']:指定序列化的字段
4) exclude = ['字段1', ..., '字段2']:排除序列化的字段
5) depth = 1:跨表的深度
"""
from app import models
class AuthorDetailJson(serializers.ModelSerializer):
    class Meta:
        model = models.AuthorDetail
        exclude = ['id']

class AuthorJson(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        # fields = '__all__'
        exclude = ['id']

    # 如果名字是原来某字段的名字相同,会覆盖,否则就是新建:此处是覆盖
    detail = serializers.SerializerMethodField()
    def get_detail(self, obj):
        detail_data = AuthorDetailJson(obj.author_detail).data
        return detail_data

class BookJson(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        # 1.对所有字段序列化
        fields = '__all__'
        # 2.对指定字段序列化
        # fields = ['id', 'name', 'price']
        # 3.刨除指定字段序列化剩下的字段
        # exclude = ['id']
        # 4.连表操作的深度
        # depth = 1

    # 自定义深度
    # 如果名字是原来某字段的名字相同,会覆盖,否则就是新建:此处是新建
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        # 1.通过序列化方式
        author_list = obj.author.all()
        author_data = AuthorJson(author_list, many=True).data
        return author_data
        # 2.通过手撸ORM查询,自定义封装返回字段 *****
视图层views.py
class Books(APIView):
    def get(self, request):
        book_list = models.Book.objects.all()
        book_data = objson.BookJson(book_list, many=True).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_data
        })
路由层urls.py
url(r'^books/', views.Books.as_view()),
### DRF序列化使用指南 #### 什么是序列化? 在 Django REST Framework (DRF) 中,序列化是指将复杂的 Django 模型实例或其他数据结构转换为原生 Python 数据类型(如字典)。这些数据随后可以被轻松渲染成 JSON 或其他格式。反序列化则是指从客户端接收到的数据经过验证并转换回复杂的模型实例。 --- #### 基本概念 DRF 提供了两种主要的序列化器类:`Serializer` 和 `ModelSerializer`。 - **Serializer**: 是一种通用的序列化器,适用于任何类型的 Python 数据。 - **ModelSerializer**: 是基于 Django 模型的快捷方式,能够自动创建与模型字段对应的序列化字段。 通过这两个类,开发者可以在 API 开发中实现高效的数据处理和验证[^1]。 --- #### 示例代码 以下是几个常见的使用场景: ##### 场景一:基本序列化(`Serializer`) 当需要手动定义字段时,可以选择 `Serializer` 类。下面是一个简单的例子: ```python from rest_framework import serializers class BookSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) title = serializers.CharField(max_length=200) author = serializers.CharField(max_length=100) def create(self, validated_data): """ 创建新的书籍记录 """ return Book.objects.create(**validated_data) def update(self, instance, validated_data): """ 更新现有书籍记录 """ instance.title = validated_data.get('title', instance.title) instance.author = validated_data.get('author', instance.author) instance.save() return instance ``` 在这个示例中,`BookSerializer` 定义了一个用于表示书籍对象的序列化器,并提供了 `create` 和 `update` 方法来支持写操作[^1]。 --- ##### 场景二:基于模型序列化(`ModelSerializer`) 对于大多数情况,推荐使用 `ModelSerializer` 来减少重复工作量。它可以根据模型自动生成字段列表。 ```python from rest_framework import serializers from .models import Book class BookModelSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ['id', 'title', 'author'] ``` 这段代码实现了相同的功能,但更加简洁明了。`fields` 参数允许开发者显式声明要包含的字段[^1]。 --- ##### 场景三:全局验证逻辑 有时需要对整个请求体进行验证而不仅仅是单个字段。可以通过重载 `validate` 方法完成此目标。 ```python import re from rest_framework import serializers from rest_framework.exceptions import ValidationError class EventSerializer(serializers.Serializer): start_date = serializers.DateField() end_date = serializers.DateField() def validate(self, data): """ 验证结束日期是否晚于开始日期 """ if data['end_date'] <= data['start_date']: raise ValidationError("End date must be after the start date.") return data ``` 这里展示了如何编写一个自定义验证函数以确保输入数据的一致性和合法性[^3]。 --- #### 注意事项 虽然 Django 自带了一些基础的序列化工具有限制条件,比如无法执行完整的双向映射,但在实际项目中建议优先考虑 DRF 的解决方案[^2]。 --- ### 总结 以上介绍了三种不同层次上的 DRF 序列化应用案例——从最灵活的手动配置到高度集成化的自动化流程都有涉及。每种方案各有优劣,具体选用哪一种取决于当前业务需求和技术背景。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值