django进一步序列化

博客围绕ORM展开,介绍了无关联连表操作、连表序列化,包含两种序列化方式,还涉及基于Model的序列化,涵盖数据层、序列化层、视图层和路由层。此外,阐述了单条数据的增删改查、数据校验、跨域问题以及认证源码流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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):
        # 拿到UserDetail类的连表对象
        detail_obj = obj.user_detail
        # 完成序列化
        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()),

 

单条数据的增删改查

# 前提:
# 1)序列化类中不能修改原字段的深度
# 2)通过 data=请求数据包 得到可以操作orm的序列化对象,instance来明确修改的对象,校验成功后还是走save()来更新
# 3)必须先校验,才能保存或更新
​
# 增
class Books(APIView):
    """
    {
        "name":"水浒传",
        "price":"88.88",
        "author":[1, 2, 3 ]
    }
    """
    def post(self, request):
        book_dic = request.data
        book_json = objson.BookJson(data=book_dic)
        # 数据的校验
        if book_json.is_valid():
            book_json.save()  # 不涉及跨表操作
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_json.data
        })
# 查改删
class Book(APIView):
    def get(self, request, id):
        book_obj = models.Book.objects.filter(pk=id).first()
        book_data = objson.BookJson(book_obj).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_data
        })
    def put(self, request, id):
        book_obj = models.Book.objects.filter(pk=id).first()
        # instance来明确修改的对象,校验成功后还是走save()来保存
        book_json = objson.BookJson(data=request.data, instance=book_obj)
        if book_json.is_valid():
            book_json.save()
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_json.data
        })
    def delete(self, request, id):
        models.Book.objects.filter(pk=id).delete()
        return Response({
            'status': 2,
            'msg': 'delete success',
        })

 

数据的校验

# views.py
class Books(APIView):
    def post(self, request):
        book_dic = request.data
        book_json = objson.BookJson(data=book_dic)
        # 数据的校验
        if book_json.is_valid():
            # book_json.save()  # 不涉及跨表操作
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': book_json.data
            })
        return Response({
            'status': 0,
            'msg': book_json.errors,
        })
​
    
# objson.py
class BookJson(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'
​
    # 认证
    name = serializers.CharField(
        max_length=5,
        min_length=1,
        error_messages={
            "max_length": "太长了",
            "min_length": "太短了",
        }
    )
​
    # 局部钩子
    def validate_name(self, value):
        from rest_framework.exceptions import ValidationError
        if 'sb' in value:
            raise ValidationError("出现了敏感词汇")
        return value
​
​
    # def validate_price(self, value):
    #     from rest_framework.exceptions import ValidationError
    #     if float(value) < 0:
    #         raise ValidationError("价格不合理")
    #     return
    
    
    
# 了解:如果多个字段直接协同校验,采用全局钩子
def validate(self, attrs):
    from rest_framework.exceptions import ValidationError
    pwd = attrs.get('pwd')
    re_pwd = attrs.get('re_pwd')
    if pwd == re_pwd:
        return attrs
    else:
        raise ValidationError('密码校验失败')

 

跨域问题

# 跨越:当有下列三种情况是,ajax请求数据,获得非本服务器本应用的数据完成自身的局部刷新,很可能不被请求的服务器的应用提供数据,该种情况就称之为 跨越问题  (CORS)
'''
1.协议不同:http 与 https间进行交互
2.端口不同:不同端口代表不同应用,直接进行交互
3.ip不同:ip地址不同,代表主机不同,不同服务器进行交互
'''
​
​
# 解决跨越
'''
安装django-cors-headers模块
​
在settings.py中配置
# 注册app
INSTALLED_APPS = [
    ...
    'corsheaders'
]
# 添加中间件
MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware'
]
# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
'''

 

认证源码流程

"""
1.views.Books.as_view()
2.view = super(APIView, cls).as_view(**initkwargs)  分发给dispatch
3.def dispatch(self, request, *args, **kwargs):  
4. 
request = self.initialize_request(request, *args, **kwargs) 封装request
self.initial(request, *args, **kwargs)  三大认证
5.self.perform_authentication(request) 转向Request类的user
6.request.py的Request的user  self._authenticate()
7.self.authenticators  self是drf的request对象
8.drf的request对象的init方法 authenticators是初始化参数
9.在哪初始化的: request = def initialize_request(self, request, *args, **kwargs)
10.self.get_authenticators() 需要 self.authentication_classes
11.self代表APIView类或子类对象,在自定义Books(APIView)中提供
"""
​
​
class Auth:
    def authenticate(self, request):
        print(request)
        # 完成具体认证功能,拿到的就是drf的request对象,对其内容做认证
        # eg:登录认证,就是判断request中的数据是否有token,并做token校验
        pass
​
class Books(APIView):
    authentication_classes = [Auth, ]
    # 请求的业务处理,都要晚于authenticate的执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值