Django的序列化与反序列化验证

阅读: 评论:0

Django的序列化与反序列化验证

Django的序列化与反序列化验证

一、一般序列化

       Django在请求完后,需要将返回的对象序列化成json串后,最后返回的时候才能以JsonRepsonse的形式返回出来,否则会报错,前端页面也需要根据返回的json串来做响应处理。

       对象序列化

       1. 继承serializers包下的ModelSeriralizer:

from rest_framework import serializersclass UserSerialize(serializers.ModelSerializer):class Meta:model = Userfields = ("id", "username", "password")

     2. 在定义序列化的类时,一定要添加Meta,否则调用的时候会出错:

   Class UserSerializers missing "Meta" attribute

 

   3. 要序列化的字段为model里的字段,fields字段可以使用[]列表或者()元组来圈起来,也可以直接使用"__all__"来表示要序列化的所有字段, 实际开发中,只需要在fields里标注需要的字段。

class DeitalSerializer(serializers.ModelSerializer):class Meta:model = SysClassDetailfields = "__all__"

       

   4 . 序列化多对多的情况 ManyToManyField

        例如,file和HandsOnCaseItems为多对多的关系。

       1)model代码

class CourseDetail(TimestampModel):resource = models.ForeignKey(Resource, verbose_name="课程", to_field="id", related_name="course_detail_resource_id",on_delete=models.DO_NOTHING)suit = models.ManyToManyField(SuitableObject, verbose_name="适合")goal = models.ManyToManyField(StudyGoal, verbose_name="学习目标")hour = models.IntegerField(verbose_name="课时")teacher = models.ManyToManyField(Teacher, verbose_name="老师")material = models.ManyToManyField(TeacherMaterial, verbose_name="教材")image_path = models.FileField(verbose_name="图文", upload_to=resource_upload_to, default=" ")class Meta:verbose_name = "课程详情"verbose_name_plural = "课程详情"db_table = "sys_course_detail"

     2) 序列化代码 , 对ManyToMany的字段添加属性 many=True

class CourseDetailSerializers(serializers.ModelSerializer):suit = SuitableObjectSerializers(many=True)goal = StudyGoalSerializers(many=True)teacher = TeacherSerializers(many=True)material = TeacherMaterialSerializers(many=True)image_path = serializers.CharField()class Meta:model = CourseDetailfields = ('id', 'resource_id', 'image_path', 'hour', 'suit', 'goal', 'teacher', 'material')

 

 

 

   在调用的时候,需要将对象传入到UserSerialize()当作参数,传进去,否则返回的就会只一个username:""

class UserLogin(APIView):@staticmethoddef s_result(result):r = _json_string()return JsonResponse(result.__dict__,json_dumps_params={'sort_keys': False, 'indent': 4, 'ensure_ascii': False}, safe=False)def post(self, request):r = Result()try:username = request.data["username"]password = request.data["password"]result = User.objects.filter(username=username, password=password).first()if result is None:print("出错了!")raise Exception("用户名或密码错误!")# 否则登录成功, 在赋值给session之前需要先将result转换为json串,否则报错:TypeError: Object of type User is not JSON serializable# request.session['user'] = result# print(request.session['user'])print("找到记录:", result)#当前登录的result为User对象里的信息# 序列化的时候此处必须要传result,否则序列化后的结果为""r.data = UserSerialize(result).dataprint("序列化后的对象信息为:", r.data)## {'id': 4, 'username': 'zhuzhu', 'password': '123456'}request.session['user'] = r.dataprint('dict一些信息:', self.__dict__)except Exception as (e)return HttpResponse(e)return JsonResponse(r.data)

 最后返回的时候,我们需要将序列化的json串r.data用JsonResponse包含返回出去。

 

二、序列化显示英文字段对应的中文

           在实际开发中,往往需要显示有些字段对应的中文意思给前端返回,那么就需要在序列化的时候,调用SerializerMethodField(),序列化方法,然后再根据英文来将中文对应起来即可。

           需要注意的是: 

              1. 需要使用@staticmethod装饰器一个方法。

              2. 装饰的方法由get_序列化的对象名。

              3. 使用serializers.SerializerMethodField()来序列化。

import datetimefrom rest_framework import serializers# 绑定设备
from edu_dels import Studentclass StudentSerializers(serializers.ModelSerializer):# 序列化名称gender_name = serializers.SerializerMethodField()learn_goal_name = serializers.SerializerMethodField()education_name = serializers.SerializerMethodField()class Meta:model = Studentfields = ('id', 'gender', 'phone', 'enabled', 'description', 'name', 'create_datetime', 'avatar', 'real_name','gender','birthday', 'education', 'signature', 'learn_target', 'learn_goal', "address", "gender_name","learn_goal_name", "education_name")@staticmethoddef get_gender_name(obj):gender = derif gender == 0:return "男"else:return "女"@staticmethoddef get_learn_goal_name(obj):goal = obj.learn_goalif goal == 0:return "一年目标"elif goal == 1:return "三到五年目标"elif goal == 2:return "长期目标"@staticmethoddef get_education_name(obj):edu = obj.educationif edu == 0:return "初中"elif edu == 1:return "高中"elif edu == 2:return "大专"elif edu == 3:return "本科"elif edu == 4:return "硕士"elif edu == 5:return "博士"

 

三、中间表序列化

          在数据库中,往往会有两个库需要建立一个中间表,中间表存两个数据库关联字段的id,通过中间表来得到另外两张表的信息,只需要通过序列化的方式,不需要我们自己写sql。

          原理其实很简单,通过中间表,序列化另外两个表。
          model:

         第一步,关联Student表和ReourcePackage表,得到student和rouce对象,在后续序列化的时候需要用到它:

class MyClassReource(TimestampModel):student = models.ForeignKey(Student, verbose_name='资源', to_field='id',related_name='student_id',on_delete=models.DO_NOTHING, null=True)rource = models.ForeignKey(ResourcePackage,to_field='id', related_name="resource_package_id",on_delete=models.DO_NOTHING, null=True)def __str__(self):return "我的班级表"class Meta:verbose_name = "我的班级"verbose_name_plural = "我的班级资源包"db_table = "user_to_resource"

        序列化: 

        第二步,  通过model定义的student和rource对象来获取Sudent表和ResourcePackage表里的字段信息:

class MyClassInfoSerializer(serializers.ModelSerializer):user_id = serializers.IntegerField(source='student.id')user_name = serializers.CharField(source='student.name', allow_blank=True, allow_null=True)resource_package_id = serializers.CharField(source='rource.id', allow_blank=True, allow_null=True)resource_name = serializers.CharField(source='rource.name', allow_blank=True, allow_null=True)resource_price = serializers.CharField(source='rource.price', allow_blank=True, allow_null=True)resource_sales = serializers.CharField(source='rource.sales', allow_blank=True, allow_null=True)resource_description = serializers.CharField(source='rource.description', allow_blank=True,allow_null=True)class Meta:model = MyClassReourcefields = ('user_id','user_name','resource_package_id','resource_name','resource_price','resource_sales','resource_description')

       执行:
       第三步,执行序列化,一定要带many=True属性,否则会报错

       Got AttributeError when attempting to get a value for field `user_id` on serializer `MyClassInfoSerializer`.

r.data = MyClassInfoSerializer(d, many=True).data

        序列化完毕后,再转成json串后,再通过JSONRepsonse()返回出去。

  return JsonResponse(result.__dict__,json_dumps_params={'sort_keys': False, 'indent': 4, 'ensure_ascii': False}, safe=False)

      一对多ForeignKey、多对多ManyToMany模式结合:


class DeitalSerializer(serializers.ModelSerializer):class Meta:model = SysClassDetailfields = "__all__"class ScheduleSerializer(serializers.ModelSerializer):class Meta:model = Schedulefields = "__all__"class MyClassInfoSerializer(serializers.ModelSerializer):id = serializers.IntegerField()name = serializers.CharField()# 多对一detail = DeitalSerializer()# 多对多schedule = serializers.SerializerMethodField()def get_schedule(self, obj):sch = obj.schedule.all()s = ScheduleSerializer(sch, many=True)return s.dataclass Meta:model = SysClassfields = "__all__"

   总结:   1. 对于单个表,可以直接通过"__all__"来直接序列化对应的model里的所有字段。

              2. 如果表里包含外键的,可以直接调用外键的model里的序列化方法来执行,比如有个外键与student表进行关联,调用的序列化器必须要带括号,要不然序列化不生效: 

class MyCommentSerializers(serializers.ModelSerializer):schedule = ScheduleSerializer()class Meta:model = Commentfields = "__all__"

             3. 对于多对多模型的,可以先调用一下模型的序列化器,然后再根据获取到的所有对象来做一个继续序列化:


class MyClassInfoSerializer(serializers.ModelSerializer):id = serializers.IntegerField()name = serializers.CharField()# 多对一detail = DeitalSerializer()# 多对多schedule = serializers.SerializerMethodField()# student = serializers.SerializerMethodField()def get_schedule(self, obj):sch = obj.schedule.all()print("sch:", sch)s = ScheduleSerializer(sch, many=True)return s.data# def get_student(self, obj):#     stu = obj.student.all()#     s = StudentSerializers(stu, many=True)#     return s.dataclass Meta:model = SysClassfields = "__all__"

          根据schedule的名字来直接在序列化器里定义方法的名称, 将里面序列化的对象进行再序列化后,把data返回:

 def get_schedule(self, obj):sch = obj.schedule.all()print("sch:", sch)s = ScheduleSerializer(sch, many=True)return s.data

 

四、反序列化

         在项目中,我们会遇到那种保存多行信息的情况,最普通的方式是:  遍历Body里的每一个{}, 然后将{} 里的字段一一取出来,然后赋值给model里面的属性字段。这种方式的优点是简单明了,但是当字段的数量比较多时,通过这种方式来保存效率会很低。

        1.  通过反序列化可以将json数据映射成model,进而使用model来进行保存和修改, 下面是反序列化单表,没有关联关系: 

         序列化器:


class VoucherRecordSerializers(serializers.ModelSerializer):class Meta:model = VoucherRecordfields = ('id','type','subject')

     body里的json为:

[{"id": 1,"type": 3,"subject":"应收现金"},{"id":4,"type":0,"subject":"应收人民币"}
]

       问题记录: 

        1) 如果在save和update前出现不允许访问数据库的情况,如以下报错:

         You cannot call `.save()` after accessing `serializer.data`...................

         解决方案,在save前需要做validate(),参数为attrs, attrs为传入的model对象里的属性序列,如上,传入了id, type , subjet,那么attrs=("id","type","subject")

         排除is_valid()方法错误的方式, 传一下raiseException=True

     yes = record.is_valid(raiseException=True)

        2) 使用反序列化的对象调用update()方法时,需要传入两个参数:

def update(self, instance, validated_data):
      
instance:   model对象   
validated_data:   已经验证过的字典 ,结构是一个字典。

         以下是反序列化的完整过程

student = self.auth(request)body = request.bodybody_content = eval(body)for i in body_content:record = VoucherRecordSerializers(data=i)yes = record.is_valid()if not yes:raise Exception("反序列化出现错误!")record_id = i["id"]res = VoucherRecord.objects.filter(id=record_id, user_id=student["id"],case_item_id=case_item_id).first()attrs = ("id", "type", "subject")record.validate(attrs)if res is None:record.save()else:record.update(res, i)

           2. 反序列化的表中含有其他表单的外键。

本文发布于:2024-01-31 10:57:40,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170666986228013.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:序列   化与   序列化   Django
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23