Django REST framework序列化

Wesley13
• 阅读 744

参考链接:https://www.cnblogs.com/liwenzhou/p/8543035.html

APIView基础序列化类:https://www.cnblogs.com/Rivend/p/12057767.html

视图路由进阶:https://www.cnblogs.com/Rivend/p/12057803.html

serializers.Serializer

单表的GET和POST:

路由:

url(r'source/', views.SourceView.as_view()),

序列化类:

from rest_framework import serializers
from rest_framework.response import Response

# 为queryset, model对象做序列化,只要你定义了name和addr我都能给你反序列化,name和addr对应数据库中的值
class PublishSerializers(serializers.Serializer):
    name = serializers.CharField()
    addr = serializers.CharField()

视图:

from rest_framework.views import APIView

#使用
class PublishView(APIView):
    # 查询数据
    def get(self, request):
        # first inquire database
        publish = models.Publisher.objects.all()
        # data put serializers data packging
        bs = PublishSerializers(publish, many=True)  # many=True多个对象
        # return
        return Response(bs.data)

 推荐写法:

class SourceView(APIView):

    def get(self, request, *args, **kwargs):
        res = {"code": 0}
        all_source = models.Source.objects.all()
        ser_obj = SourceSerializer(all_source, many=True)
        res["data"] = ser_obj.data
        return Response(res)

    def post(self, request, *args, **kwargs):
        res = {"code": 0}
        ser_obj = SourceSerializer(data=request.data)
        if ser_obj.is_valid():
            # 数据没问题
            ser_obj.save()
            return Response(res)
        else:
            res["code"] = 1
            res["error"] = ser_obj.errors
            return Response(res)

外键的GET和POST:

路由:

url(r'comment/', views.Comment.as_view()),

序列化:

class BookSerializers(serializers.Serializer):
    title = serializers.CharField()
    pub_date = serializers.DateField()
    # 反序列化一对多字段返回的是__str__数据
    publish = serializers.CharField(source="publish.addr")  # source 可以指定返回的一对多的字段
    # authors=serializers.CharField(source="authors.all")  # 指定序列化多对多的字段(不推荐)
    authors = serializers.SerializerMethodField()

    # 多对多字段序列化方法,这个函数必须是get_authors,因为这个字段在是多对多
    def get_authors(self, obj):
        temp = []
        for obj in obj.authors.all():
            temp.append(obj.name)
        return temp

视图:

#使用
class PublishView(APIView):
    # 查询数据
    def get(self, request):
        # first inquire database
        publish = models.Publisher.objects.all()
        # data put serializers data packging
        bs = BookSerializers(publish, many=True)  # many=True多个对象
        # return
        return Response(bs.data)

class Comment(APIView):
    def get(self, request, *args, **kwargs):
        res = {"code": 0}
        all_data = models.Comment.objects.all()
        ser_obj = CommentSerializer(all_data, many=True)
        res["data"] = ser_obj.data
        return Response(res)

    def post(self, request, *args, **kwargs):
        res = {"code": 0}
        ser_obj = CommentSerializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
        else:
            res["code"] = 1
            res["error"] = ser_obj.errors
        return Response(res)

serializers.ModelSerializer

ModelSerializerSerializer区别在于

ModelSerializer支持了Serializer中所有的操作,并且通过自动生成所有数据字段与序列化类的一一对应关系,而不用自己手动添加。
SerializerModelSerializer的父类,所以ModelSerializer才会支持Serializer的所有操作.

好处:

ModelSerializer已经重载了create与update方法,它能够满足将post或patch上来的数据进行进行直接地创建与更新,

除非有额外需求,那么就可以重载create与update方法。
ModelSerializer在Meta中设置fields字段,系统会自动进行映射,省去每个字段再写一个field。

序列化原理:

"""
序列化原理BookSerializers(book_list,many=Ture):
    temp=[]
        for obj in book_list:
            temp.append({
            "title":obj.title,
            "price":str(obj.publish), #obj.publish.name 
            "author":get_authors(obj),
            
            })

"""

单表的GET和POST:

路由:

urlpatterns = [
    url(r'articlelinked/', views.ArticleLinked.as_view()),,
    url(r'source/(?P<pk>\d+)', views.SourceDetailView.as_view(), name='source-detail'),
]

序列化类:

class PublishModelSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Publisher
        fields = "__all__" #  表示所有字段
        # exclude = ('add_time',):  除去指定的某些字段
        # 定义报错信息
        # extra_kwargs = {
        #     "content": {"error_messages": {"required": "评论内容不能为空"}},
        #     "article": {"error_messages": {"required": "文章不能为空"}}
        # }

class SourceSerializer(serializers.ModelSerializer):

    def validate_name(self, value):
        if '草' in value:
            raise ValidationError('不符合社会主义核心价值观')
        return value

    class Meta:
        model = models.Source
        fields = "__all__"

class CourseDetailSerializer(serializers.ModelSerializer):
    #     # one2one/fk/choice 跨表查询 或者外间选择项
    name = serializers.CharField(source='course.name')
    img = serializers.CharField(source='course.course_img')                                       # 选择项
    level = serializers.CharField(source='course.get_level_display')

    #     m2m
    recommend_courses = serializers.SerializerMethodField()
    teachers = serializers.SerializerMethodField()

    # FK  reverse 跨表反向查询
    coursechapter = serializers.SerializerMethodField()

    #
    class Meta:
        model = models.CourseDetail
        fields = ['id', 'hours', 'course_slogan', 'video_brief_link', 'why_study', 'what_to_study_brief',
                  'career_improvement', 'prerequisite', 'name', 'level', 'img', 'recommend_courses', 'teachers',
                  'coursechapter']

        # fields = '__all__'

    def get_recommend_courses(self, obj):
        """获取推荐的所有课程"""

        queryset = obj.recommend_courses.all()
        return [{'id': row.id, 'name': row.name} for row in queryset]

    def get_teachers(self, obj):
        """获取所有老师"""
        obj = obj.teachers.all()
        return [{'id': row.id, 'name': row.name} for row in obj]

    def get_coursechapter(self, obj):
        """获取所有章节"""
        obj = obj.course.coursechapters.all()

        return [{'id': row.id, } for row in obj]

视图:

查询所有数据:

class PublishView(APIView):
    # 查询数据
    def get(self, request):
        # first inquire database
        publish = models.Publisher.objects.all()
        # data put serializers data packging
        bs = PublishModelSerializers(publish, many=True)  # many=True多个对象
        # return
        return Response(bs.data)

    # 增加数据
    def post(self, request):
        bs = PublishModelSerializers(data=request.data)  # post不需要定义many=Ture
        if bs.is_valid():
            bs.save()  # 保存
            return Response("添加成功")
        else:
            return Response("增加失败")

查询单条数据:

class PublishDetaiView(APIView):
    # 将这个pk设置成和lookup_url_kwarg='pk' 一样的值,不然加后缀会取不到值
    def get(self, request, pk):  # id 不要放到request前面
        # 查询数据库
        publish = models.Publisher.objects.filter(pk=pk)
        # 封装打包序列化数据
        bs = PublishModelSerializers(publish, many=True)  # many=True多个对象
        # Response 会直接返回josn数据格式
        return Response(bs.data)

    # #  修改数据(前端指定id值后,在data中输入k:v即可change数据)
    def put(self, request, pk):
        # inquire database
        publish = models.Publisher.objects.filter(pk=pk).first()
        # data=  form request.data client
        ps = PublishModelSerializers(publish, data=request.data, many=True)  # many=True多个对象
        # if ps pass verify
        if ps.is_valid():
            ps.save()
            return Response(ps.data)
        else:
            return Response(ps.errors)

    # 删除数据
     def delete(self, request, pk):
         models.Publisher.objects.filter(pk=pk).delete()
         return Response("删除成功")

推荐写法:

class ArticleList(APIView):
    def get(self, request, *args, **kwargs):
        res = {"code": 0}
        article_list = models.Article.objects.all()
        ser_obj = ArticleSerializer(article_list, many=True)
        res["data"] = ser_obj.data
        return Response(res)

    def post(self, request, *args, **kwargs):
        res = {"code": 0}
        ser_obj = ArticleWriteSerializer(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
        else:
            res["code"] = 1
            res["error"] = ser_obj.errors
        return Response(res)

自定义字段超链接路径:

路由:

urlpatterns = [

    re_path(r"^Books/$", views.BookView.as_view(), name='book'),
    re_path(r"^Book/(?P<id>\d+)/$", views.BookDetaiView.as_view(), name='books'),


]

序列化:

from rest_framework import serializers

class BookModelSerializers(serializers.ModelSerializer):
    # 自定义publish字段超链接路径
    depth = 1  # 0 ~ 10
    publish = serializers.HyperlinkedIdentityField(view_name='books',
                                                   lookup_field='publish_id',
                                                   lookup_url_kwarg='id')

    """
    # view_name           参数 进行传参的时候是参考路由匹配中的name与namespace参数.
    #  lookeup_field      参数是根据在UserInfo表中的连表查询字段group_id.
    # look_url_kwarg      参数在做url反向解析的时候会用到.
    """

    class Meta:
        model = Book
        # fields = ['id', 'title', 'pub_date', 'publish', 'authors']# 这个是可以自定义字段的
        fields = "__all__"
        depth = 0
        # 自动向内部进行深度查询,就是查询的比较详细  depth表示查询层数

视图:

查询所有:

class BookView(APIView):
    def get(self, request, *args, **kwargs):
        book_list = Book.objects.all()
        # context十分关键,如果不将request传递给它,在序列化的时候,图片与文件这些Field不会再前面加上域名,也就是说,只会有/media/img...这样的路径!
        bs = BookModelSerializers(instance=book_list, many=True, context={'request': request})  # 在做链接的时候需要添加context参数
        print(bs)
        # 默认就返回json格式的字符串
        return Response(bs.data)

    # 其他还未实现

查询单条:

class BookDetaiView(APIView):
    # inquire database
    def get(self, request, id, *args, **kwargs):
        book_list = Book.objects.filter(id=id)
        bs = BookModelSerializers(instance=book_list, many=True, context={'request': request})  # 在做链接的时候需要添加context参数
        print(bs)
        # 默认就返回json格式的字符串
        return Response(bs.data)

推荐写法:

class ArticleLinked(APIView):
    def get(self, request, *args, **kwargs):
        res = {"code": 0}
        article_list = models.Article.objects.all()
        ser_obj = ArticleHyperlinkedSerializer(article_list, many=True, context={'request': request})
        res["data"] = ser_obj.data
        return Response(res)

 重写save中的create方法

#  重写save中的create方法2
    def create(self, validated_data):
        print(validated_data["title"], validated_data["pub_date"], validated_data["publish"])
        publish_id = validated_data["publish"]
        book = models.Book.objects.create(title=validated_data["title"], pub_date=validated_data["pub_date"],
                                          publish=publish_id)
        book.authors.add(*validated_data["authors"])
        return book

实例代码:

class BookModelSerializers(serializers.ModelSerializer):
    # 自定义publish字段超链接路径
    publish_url = serializers.HyperlinkedIdentityField(view_name='detailpublish',
                                                       lookup_field='publish_id',
                                                       lookup_url_kwarg='pk',
                                                       )
    publish = serializers.CharField(source="publish.id")
    """
    # view_name参数 进行传参的时候是参考路由匹配中的name与namespace参数
    #  lookeup_field参数是根据在UserInfo表中的连表查询字段group_id
    # look_url_kwarg参数在做url反向解析的时候会用到
    """

    #  重写save中的create方法
    def create(self, validated_data):
        # create 方法之前也可以单独pop在添加
        """
        author = validated_data.pop[title]
        然后再进行额外自己添加
        obj = Book.objecte.create(**validated_data)
        obj.authors.add(*authors)
        """
        publish_id = validated_data["publish"]["id"]
        book = models.Book.objects.create(title=validated_data["title"], pub_date=validated_data["pub_date"],
                                          publish=models.Publisher.objects.filter(pk=publish_id).first()
                                          )
        book.authors.add(*validated_data["authors"])
        return book

    class Meta:
        model = models.Book
        # fields = ['id', 'title', 'pub_date', 'publish', 'authors']
        fields = "__all__"
        depth = 0  ## 0 ~ 10
        # 自动向内部进行深度查询,就是查询的比较详细  depth表示查询层数
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
4cast
4castpackageloadcsv.KumarAwanish发布:2020122117:43:04.501348作者:KumarAwanish作者邮箱:awanish00@gmail.com首页:
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这