• 序列化组件


    from django.http import HttpResponse, JsonResponse
    from django.core import serializers
    class BookView(View):
    	
    	 # 第一版 json
    	 def get(self, request):
    		book_list = Book.objects.values("id", "title", "put_time", "category", "publisher")
    		# querset [{}, {}]
    		book_list = list(book_list)
    		ret = json.dumps(book_list, ensure_ascii=False)
    		return HttpResponse(ret)
    	
    
    	
    	#第二版 JsonResponse
    	def get(self, request):
    		book_list = Book.objects.values("id", "title", "put_time", "category", "publisher")
    		# querset [{}, {}]
    		book_list = list(book_list)
    		for book in book_list:
    			publisher_obj = Publisher.objects.filter(id=book["publisher"]).first()
    			# 手动给每个book对象添加其对应的外键出版社
    			book["publisher"] = {
    				"id": publisher_obj.id,
    				"title": publisher_obj.title
    			}
    		return JsonResponse(book_list, safe=False, json_dumps_params={"ensure_ascii": False})
    	
    	
    
    	#第三版 serialize
    	用django的serialize方法 外键依然不能够被序列化 取出来的依然是id
    	 def get(self, request):
    		book_list = Book.objects.all()
    		ret = serializers.serialize("json", book_list, ensure_ascii=False)
    		return HttpResponse(ret)    
    	
    

      

    使用rest_framework提供的序列化组件serializers

    1,声明一个序列化器. 2,视图类继承APIView或其子类

    第四版  使用serializers.Serializer

    #自己写的serializers.py文件	
    from rest_framework import serializers
    from .models import Book
    
    class PublisherSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    
    class AuthorSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        name = serializers.CharField(max_length=32)
    
    book_obj = {
        "title": "xxx",
        "category": 1,
        "publisher": 1,
        "authors": [1, 2]
    }
    
    # (read_only, write_only)
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False) # required=False反向序列化的时候不进行验证了,
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, "Python"), (2, "Linux"), (3, "go"))
        category = serializers.CharField(max_length=32, source="get_category_display", read_only=True) #使用source参数后就可以使用orm中的指令了,source后的内容就是对应orm的指令  #read_only表示只进行正向序列化,从视图到前端,处理的是get请求
        post_category = serializers.ChoiceField(choices=CHOICES, write_only=True)#write_only表示你只进行反向序列化,从前端到视图,处理的是post请求
        put_time = serializers.DateField()
    
        publisher = PublisherSerializer(read_only=True)    #将出版社的Serializer对象传给publisher字段作为外键
        authors = AuthorSerializer(many=True, read_only=True) #同样的将作者的Serializer对象列表传给authors字段,作为多对多的关联,这里因为是多对多的关系,所以需要有一个many=True的参数
    
        publisher_id = serializers.IntegerField(write_only=True)  # 这里是用于反序列化时的读取,为了区别正向序列化,和前端约定起另外的字段名
        author_list = serializers.ListField(write_only=True)
    
        def create(self, validated_data): #validated_data是通过验证后的数据
            # 执行ORM的新增数据的操作
            book_obj = Book.objects.create(title=validated_data["title"], category=validated_data["post_category"],
                                put_time=validated_data["put_time"], publisher_id=validated_data["publisher_id"])
            book_obj.authors.add(*validated_data["author_list"])
            print(validated_data["author_list"])
            return book_obj
    
        def update(self, instance, validated_data):
            # 使用update的可以提交局部数据,当然也要是json格式的,注意最后面不要加逗号,加了逗号不符合json规范  { "title": "旭哥再次再次升职记"}
            # 有就更新没有就取默认的
            instance.title = validated_data.get("title", instance.title)
            instance.category = validated_data.get("post_category", instance.category)
            instance.put_time = validated_data.get("put_time", instance.put_time)
            instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
            if validated_data.get("author_list"):
                instance.authors.set(validated_data["author_list"])
            instance.save()   #更新需要保存instance,因为instance=book_obj是从数据库取出来的数据,当然保存操作也可以在views中进行,直接保存 book_obj.save()
            return instance
    

      

    # 视图函数
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import Book
    from .serializers import BookSerializer
    
    
    class BookAPIView(APIView):
        def get(self, request):
            book_list = Book.objects.all()
            ser_obj = BookSerializer(book_list, many=True)
            # return Response("DRF接口测试ok")
            return Response(ser_obj.data)
    
        def post(self, request):
            book_obj = request.data  #request.data接收post请求提交的数据,封装好了,不再使用request.POST.get()
            print(request.data)
            ser_obj = BookSerializer(data=book_obj)
            if ser_obj.is_valid():
                print(ser_obj.validated_data)
                ser_obj.save() # save()方法调用了我们在BookSerializer重写的creat方法
                return Response(ser_obj.validated_data)
            else:
                return Response(ser_obj.errors)
    
    
    class BookEditView(APIView):
        def get(self, request, id):
            book_obj = Book.objects.filter(id=id).first()
            ser_obj = BookSerializer(book_obj)
            return Response(ser_obj.data)
    
        def patch(self, request, id):
            book_obj = Book.objects.filter(id=id).first()
            ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)  #partial=True局部等于true,允许部分验证
            if ser_obj.is_valid():
                ser_obj.save() # post里的save()方法调用了我们在BookSerializer重写的update方法,这可以在源码中看,点进去看很明显
                # book_obj.save()  可以在这里保存,也可以在BookSerializer里进行保存
                return Response(ser_obj.validated_data)
            else:
                return Response(ser_obj.errors)
    

      

    第五版 使用serializers.ModelSerializer

    # 自己写的serializers.py文件
    from rest_framework import serializers
    from .models import Book
    
    class BookSerializer(serializers.ModelSerializer):
        # 正序和反序列化不同的字段
        category_display = serializers.SerializerMethodField(read_only=True)
        publisher_info = serializers.SerializerMethodField(read_only=True)
        authors_info = serializers.SerializerMethodField(read_only=True)
    
        def get_category_display(self, obj):
            return obj.get_category_display()
    
        def get_publisher_info(self, obj):
            return {"id": obj.publisher.id, "title": obj.publisher.title}
    
        def get_authors_info(self, obj):
            # 列表生成式循环获得每个作者信息
            return [{"id": author.id, "name": author.name} for author in obj.authors.all()]
    
    
        class Meta:
            model = Book
            fields = "__all__"
            extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                            "authors": {"write_only": True}}	
    

      

    # 视图函数
    from .serializers import BookSerializer
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import Book, User
    class BookView(APIView):
        # authentication_classes = [MyAuth, ] 这个是认证先不用管
    
        def get(self, request):
            # 查看所有的图书
            queryset = Book.objects.all()
            ser_obj = BookSerializer(queryset, many=True)
            return Response(ser_obj.data)
    
        def post(self, request):
            # 新增图书
            ser_obj = BookSerializer(data=request.data)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.validated_data)
    
    class BookEditView(APIView):
        def get(self, request, pk):
            book_obj = Book.objects.filter(id=pk).first()
            ser_obj = BookSerializer(book_obj)
            return Response(ser_obj.data)
    
        def put(self, request, pk):
            book_obj = Book.objects.filter(id=pk).first()
            ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.validated_data)
            else:
                return Response(ser_obj.errors)
    
        def delete(self, request, pk):
            book_obj = Book.objects.filter(id=pk).first()
            if not book_obj:
                return Response({"code": 1001, "error": "删除的数据不存在"})
            else:
                book_obj.delete()
                return Response("")	
    

      

    # 在序列化组件中进行验证
    def my_validate(value):
        print("my_validate")
        # 对敏感信息进行过滤
        if "马化腾" in value.lower():
            raise serializers.ValidationError("不能含有敏感词汇")
        else:
            return value	
    class BookSerializer(serializers.ModelSerializer):
        category_dis= serializers.SerializerMethodField(read_only=True)
        publisher_info = serializers.SerializerMethodField(read_only=True)
        author_info = serializers.SerializerMethodField(read_only=True)
    
        def get_author_info(self, obj):
            # 通过obj拿到authors
            # 构建想要的数据结构返回
            authors = obj.authors.all()
            ret = []
            for author in authors:
                ret.append({
                    "id": author.id,
                    "name": author.name
                })
            return ret
    
    
        def get_category_dis(self, obj):
            return obj.get_category_display()
    
        def get_publisher_info(self, obj):
            # 序列化的Book对象
            # 通过Book对象找到我们的publisher对象
            # 就可以拿到我们想要的字段
            # 拼接成自己想要的数据结构
            ret = {
                "id": obj.publisher.id,
                "title": obj.publisher.title
            }
            return ret
    
        class Meta:
            model = Book
            # fields = ["id", "title", "put_time"]
            fields = "__all__"
            # depth = 1  # 自动寻找一层外键的字段,depth=2就寻找两层外键的字段, 当时会让你这些外键关系的字段变成read_only = True  一般不建议用,
            extra_kwargs = {"category": {"write_only": True},"publisher": {"write_only": True},
                            "authors":{"write_only": True},"title": {"validators": [my_validate]}}	
    

      

    序列化组件类的相互引用

    # 序列化组件间的相互引用
    from rest_framework import serializers
    from course.models import Course,CourseDetail
    
    
    class CourseSerializer(serializers.ModelSerializer):
        course_type_display = serializers.SerializerMethodField(read_only=True)
        level_display = serializers.SerializerMethodField(read_only=True)
        status_display = serializers.SerializerMethodField(read_only=True)
        category_info = serializers.SerializerMethodField(read_only=True)
        price_policy = serializers.SerializerMethodField(read_only=True)
    
        def get_course_type_display(self, obj):
            return obj.get_course_type_display()
    
        def get_level_display(self, obj):
            return obj.get_level_display()
    
        def get_status_display(self, obj):
            return obj.get_status_display()
    
        def get_category_info(self, obj):
            return {'id': obj.category.id, 'title': obj.category.title}
    
        def get_price_policy(self, obj):
            ret = [{
                'id': price_obj.id,
                'valid_price_display': price_obj.get_valid_period_display(),
                "price": price_obj.price}
                for price_obj in obj.price_policy.all()]
    
            return ret
    
        class Meta:
            model = Course
            fields = "__all__"
            # depth = 1
            extra_kwargs = {"course_type": {"write_only": True}, "level": {"write_only": True},
                            "status": {"write_only": True}, "category": {"write_only": True}}
    
    class CourseDetailSerializer(serializers.ModelSerializer):
        course_info=serializers.SerializerMethodField(read_only=True)   
        def get_course_info(self,obj):
            # print(obj.course,type(obj.course))
            # 这里引用了CourseSerializer,就不用再重复写了
            course_queryset= Course.objects.filter(id=obj.id)
            return CourseSerializer(course_queryset,many=True).data[0]   # 这样得到是字典,不然是列表,多对多的关系中应该用列表
    
        class Meta:
            model=CourseDetail
            fields = '__all__'
            extra_kwargs = {"course": {"write_only": True},}
    

      

    这是model.py表关系

    from django.db import models
    
    # Create your models here.
    
    from django.db import models
    from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    from django.contrib.contenttypes.models import ContentType
    
    # Create your models here.
    __all__ = ["Category", "Course", "CourseDetail", "Teacher", "DegreeCourse", "CourseChapter",
               "CourseSection", "PricePolicy", "OftenAskedQuestion", "Comment", "Account", "CourseOutline"]
    
    
    class Category(models.Model):
        """课程分类表"""
        title = models.CharField(max_length=32, unique=True, verbose_name="课程的分类")
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "01-课程分类表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class Course(models.Model):
        """课程表"""
        title = models.CharField(max_length=128, unique=True, verbose_name="课程的名称")
        course_img = models.ImageField(upload_to="course/%Y-%m", verbose_name='课程的图片')
        category = models.ForeignKey(to="Category", verbose_name="课程的分类")
        COURSE_TYPE_CHOICES = ((0, "付费"), (1, "vip专享"), (2, "学位课程"))
        course_type = models.SmallIntegerField(choices=COURSE_TYPE_CHOICES)
        degree_course = models.ForeignKey(to="DegreeCourse", blank=True, null=True, help_text="如果是学位课程,必须关联学位表")
    
        brief = models.CharField(verbose_name="课程简介", max_length=1024)
        level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
        level = models.SmallIntegerField(choices=level_choices, default=1)
        status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
        status = models.SmallIntegerField(choices=status_choices, default=0)
        pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
        order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排,尽量间隔几个数字")
        study_num = models.IntegerField(verbose_name="学习人数", help_text="只要有人买课程,订单表加入数据的同时给这个字段+1")
    
        # order_details = GenericRelation("OrderDetail", related_query_name="course")
        # coupon = GenericRelation("Coupon")
        # 只用于反向查询不生成字段
        price_policy = GenericRelation("PricePolicy")
        often_ask_questions = GenericRelation("OftenAskedQuestion")
        course_comments = GenericRelation("Comment")
    
        def save(self, *args, **kwargs):
            if self.course_type == 2:
                if not self.degree_course:
                    raise ValueError("学位课必须关联学位课程表")
            super(Course, self).save(*args, **kwargs)
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "02-课程表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class CourseDetail(models.Model):
        """课程详细表"""
        course = models.OneToOneField(to="Course")
        hours = models.IntegerField(verbose_name="课程时长", default=7)
        # course_slogan = models.CharField(max_length=125, blank=True, null=True, verbose_name="课程口号")
        video_brief_link = models.CharField(max_length=255, blank=True, null=True)
        summary = models.TextField(max_length=2048, verbose_name="课程概述")
        why_study = models.TextField(verbose_name="为什么学习这门课程")
        what_to_study_brief = models.TextField(verbose_name="我将学到哪些内容")
        career_improvement = models.TextField(verbose_name="此项目如何有助于我的职业生涯")
        prerequisite = models.TextField(verbose_name="课程先修要求", max_length=1024)
        recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)
        teachers = models.ManyToManyField("Teacher", verbose_name="课程讲师")
    
        def __str__(self):
            return self.course.title
    
        class Meta:
            verbose_name = "03-课程详细表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class Teacher(models.Model):
        """讲师表"""
        name = models.CharField(max_length=32, verbose_name="讲师名字")
        brief = models.TextField(max_length=1024, verbose_name="讲师介绍")
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name = "04-教师表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class DegreeCourse(models.Model):
        """
        字段大体跟课程表相同,哪些不同根据业务逻辑去区分
        """
        title = models.CharField(max_length=32, verbose_name="学位课程名字")
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "05-学位课程表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class CourseChapter(models.Model):
        """课程章节表"""
        course = models.ForeignKey(to="Course", related_name="course_chapters")
        chapter = models.SmallIntegerField(default=1, verbose_name="第几章")
        title = models.CharField(max_length=32, verbose_name="课程章节名称")
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "06-课程章节表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ("course", "chapter")
    
    
    class CourseSection(models.Model):
        """课时表"""
        chapter = models.ForeignKey(to="CourseChapter", related_name="course_sections")
        title = models.CharField(max_length=32, verbose_name="课时")
        section_order = models.SmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
        section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
        free_trail = models.BooleanField("是否可试看", default=False)
        section_type = models.SmallIntegerField(default=2, choices=section_type_choices)
        section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文档,填link")
    
        def course_chapter(self):
            return self.chapter.chapter
    
        def course_name(self):
            return self.chapter.course.title
    
        def __str__(self):
            return "%s-%s" % (self.chapter, self.title)
    
        class Meta:
            verbose_name = "07-课程课时表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ('chapter', 'section_link')
    
    
    class PricePolicy(models.Model):
        """价格策略表"""
        # conten_type  指定表id
        content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
        # 关联的表里的对象id
        object_id = models.PositiveIntegerField()
        #  关联的表里的那个对象
        content_object = GenericForeignKey('content_type', 'object_id')
    
        valid_period_choices = ((1, '1天'), (3, '3天'),
                                (7, '1周'), (14, '2周'),
                                (30, '1个月'),
                                (60, '2个月'),
                                (90, '3个月'),
                                (120, '4个月'),
                                (180, '6个月'), (210, '12个月'),
                                (540, '18个月'), (720, '24个月'),
                                (722, '24个月'), (723, '24个月'),
                                )
        # 周期
        valid_period = models.SmallIntegerField(choices=valid_period_choices)
        # 价格
        price = models.FloatField()
    
        def __str__(self):
            return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)
    
        class Meta:
            verbose_name = "08-价格策略表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ("content_type", 'object_id', "valid_period")
    
    
    class OftenAskedQuestion(models.Model):
        """常见问题"""
        content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')
    
        question = models.CharField(max_length=255)
        answer = models.TextField(max_length=1024)
    
        def __str__(self):
            return "%s-%s" % (self.content_object, self.question)
    
        class Meta:
            verbose_name = "09-常见问题表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ('content_type', 'object_id', 'question')
    
    
    class Comment(models.Model):
        """通用的评论表"""
        content_type = models.ForeignKey(ContentType, blank=True, null=True)
        object_id = models.PositiveIntegerField(blank=True, null=True)
        content_object = GenericForeignKey('content_type', 'object_id')
    
        content = models.TextField(max_length=1024, verbose_name="评论内容")
        account = models.ForeignKey("Account", verbose_name="会员名")
        date = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.content
    
        class Meta:
            verbose_name = "10-评价表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class Account(models.Model):
        username = models.CharField(max_length=32, verbose_name="用户姓名")
        # head_img = models.CharField(max_length=256, default='/static/frontend/head_portrait/logo@2x.png',
        #                             verbose_name="个人头像")
    
        def __str__(self):
            return self.username
    
        class Meta:
            verbose_name = "11-用户表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
    
    
    class CourseOutline(models.Model):
        """课程大纲"""
        course_detail = models.ForeignKey(to="CourseDetail", related_name="course_outline")
        title = models.CharField(max_length=128)
        order = models.PositiveSmallIntegerField(default=1)
        # 前端显示顺序
    
        content = models.TextField("内容", max_length=2048)
    
        def __str__(self):
            return "%s" % self.title
    
        class Meta:
            verbose_name = "12-课程大纲表"
            db_table = verbose_name
            verbose_name_plural = verbose_name
            unique_together = ('course_detail', 'title')
    

      

  • 相关阅读:
    线性关系和相关系数
    CSS中的display:inlineblock
    SQL Server中常用的SQL语句
    Access SQL中Left Join、Right Join和Inner Join的使用
    PHP合并静态文件
    PHP中的include功能
    CSS背景图片居中的细节
    IIS Web服务扩展中添加ASP.NET4.0
    修改SQL server数据库中的逻辑文件名
    在SQL Server中,不使用“SQL 邮件”的情况下发送邮件
  • 原文地址:https://www.cnblogs.com/perfey/p/9949007.html
Copyright © 2020-2023  润新知