3-3 序列化-DRF模型序列化高级

目录:

  • 设计分类表(Category)(1对多)
  • 序列化高级用法:
StringRelatedField:将返回一个对应的 model的str() 方法的字符串。

PrimaryKeyRelatedField: 将返回一个对应关系 model 的主键。

HyperlinkedRelatedField:使用 HyperlinkedRelatedField 将返回一个超链接,该链接指向对应关系 model 的详细数据,view-name 是必选参数,为对应的视图生成超链接。

SlugRelatedField:将返回一个指定对应关系 model 中的字段,需要参数 slug_field 中指定字段名称。

HyperlinkedIdentityField:将返回指定 view-name 的超链接的字段。
  • HyperlinkedModelSerializer的使用
  • 嵌套序列化关系模型
  • 深度遍历:depth
  • 自定义属性:SerializerMethodField
  • 自定义数据源:source
  • to_representation方法(多对多关系):自定义字段格式显示

一、设计分类表(Category)(1对多)

 我们设计分类表(Category),与文章表(Article)是一对多的关系,然后我们通过这个关系,看下 序列化高级的用法。废话不多,我们先来设计表结构(1对多)

1.1、设计模型类

说明:分类表(Category) 和 文章表(Article) 是 一对多外键关系。在 models.py中 设计表结构:

from django.db import models

class Article(models.Model):
    ....
    category = models.ForeignKey(to="Category",on_delete=models.CASCADE,related_name="articles")  #related_name反查

    def __str__(self):
        return self.title

class Category(models.Model):
    name = models.CharField(verbose_name="分类",max_length=10)

    def __str__(self):
        return  self.name

1.2、序列化

说明:编写 serializers.py序列化文件,设置序列化。fields显示的字段,是你 返回的值显示的。

from rest_framework import serializers
from .models import Article,Category

#模型序列化
class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')  #增加 category 序列化外键


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id','name')

1.3、设置路由

说明:这个在子路由中设置。上面我们已经设置过了父路由的设置。app02 -> urls.py

from django.urls import path
from app02 import views


urlpatterns = [
    ...
    #新增 category的路由
    path("category/", views.category_list, name="category-list"),
    path("category/<int:id>/", views.category_detail, name="category-detail"),
]

1.4、视图

说明:编辑 views.py,增加 分类的(category) 视图代码,跟article是一样的逻辑。

from .serializers import ArticleSerializer,CategorySerializer
....
from .models import Article,Category
....

# Create your views here.

class JSONResponse(HttpResponse):
    """重新封装一下HttpResponse避免重复代码"""
    ...


@csrf_exempt
def article_list(request):
    ...

@csrf_exempt
def article_detail(request,id):
    ...

@csrf_exempt
def category_list(request):
    """
    文章标题
    :return:
    """
    if request.method == "GET":
        arts = Category.objects.all()
        ser = CategorySerializer(instance=arts, many=True)
        return JSONResponse(ser.data, status=200)
    elif request.method == "POST":
        data = JSONParser().parse(request)
        ser = CategorySerializer(data=data)
        if ser.is_valid():
            ser.save()
            return JSONResponse(ser.data, status=201)
        return JSONResponse(ser.errors,status=401)


@csrf_exempt
def category_detail(request,id):
    """
    文章详情
    :param request:
    :param id: 文章id
    :return:
    """
    try:
        art = Category.objects.get(id=id)
    except Category.DoesNotExist as e:
        return HttpResponse(status=404)

    if request.method == "GET":
        ser = CategorySerializer(instance=art)
        return JSONResponse(ser.data,status=200)

    elif request.method == "PUT":
        data = JSONParser().parse(request)
        ser = CategorySerializer(instance=art,data=data)
        if ser.is_valid():
            ser.save()
            return JSONResponse(ser.data,status=201)
        return JSONResponse(ser.errors,status=400)
    elif request.method == "PATCH":
        data = JSONParser().parse(request)
        ser = CategorySerializer(instance=art,data=data,partial=True) #partial=True 意思是我要部分更新,默认是False
        if ser.is_valid():
            ser.save()
            return JSONResponse(ser.data,status=201)
        return JSONResponse(ser.errors,status=400)

    elif request.method == "DELETE":
        art.delete()
        return HttpResponse(status=204)
views.py

1.5、postman测试运行:

二、 序列化高级用法

 序列化高级用法:都是针对编辑 serializers.py 序列化文件,根据不同的高级用法,响应不同我们想要的结果, fields 关键字,表示你要响应显示什么字段,需要在我们的fields中定义,不管你在序列化类中定义多少字段,只要想显示都需要在fields 字段中定义。这个很重要,一定要记住。

2.1、StringRelatedField

说明:StringRelatedField将返回一个对应关系 model 的 __str__() 方法的字符串。

1、序列化文章(article),返回__str__() 方法的字符串

from rest_framework import serializers
from .models import Article,Category

#StringRelatedField获取 model 模型类中Category类的 def __str__中返回的值(self.name)

class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.StringRelatedField()  # modle模型Article中有category字段
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')  #新增显示category字段。


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id','name')

post请求结果:

GET: http://127.0.0.1:8000/api/article/2/

响应结果(response):
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": "监控中心"  #category 显示的值是 模型类中 Catagory 中的 def __str__(self): return self.name。str()中 return 啥值,就返回什么值
}

2、序列化分类(catagory),反查文章(article),返回 str()方法字符串

from rest_framework import serializers
from .models import Article,Category

#StringRelatedField

class ArticleSerializer(serializers.ModelSerializer):
    ....

class CategorySerializer(serializers.ModelSerializer):
    articles = serializers.StringRelatedField(many=True)  #因为查文章分类是多个对象,所以要加 many=True
    class Meta:
        model = Category
        fields = ('id','name','articles')  #article字段是在模型类Article中related_name中反射出来的

post请求结果:

GET: http://127.0.0.1:8000/api/category/1/

响应结果(reponse):
{
    "id": 1,
    "name": "资产管理",
    "articles": [
        "gaogege is very handsome",
        "gaogege is very handsome",
        "gaogege is very handsome",
        "gaogege is very handsome",
        "gaogege is very handsome"
    ]
}

2.2、PrimaryKeyRelatedField

说明:使用PrimaryKeyRelatedField 将返回一个对应关系的model的主键。

参数:

  • queryset 用于在验证字段输入时模型实例查找。 关系必须明确设置 queryset,或设置 read_only = True
  • many 如果是对应多个的关系,就设置为 True
  • allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False
  • pk_field 设置为一个字段以控制主键值的序列化/反序列化。例如,pk_field = UUIDField(format ='hex') 将UUID主键序列化为紧凑的十六进制表示。
from rest_framework import serializers
from .models import Article,Category
# PrimaryKeyRelatedField

class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.PrimaryKeyRelatedField(read_only=True)  #read_only=True 是必须传的,不然会报错
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')


class CategorySerializer(serializers.ModelSerializer):
    articles = serializers.PrimaryKeyRelatedField(read_only=True,many=True)  #多个实例,一个分类下有多篇文章
    class Meta:
        model = Category
        fields = ('id','name','articles')

post运行结果:

#请求文章article路由
GET:http://127.0.0.1:8000/api/article/2/

Reponse:
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": 2  #只显示category主键
}

#请求文章分类category路由
GET: http://127.0.0.1:8000/api/category/2/

Repose:
{
    "id": 2,
    "name": "监控中心",
    "articles": [  #只显示articles主键
        2
    ]
}

2.3、HyperlinkedRelatedField

说明:使用 HyperlinkedRelatedField 将返回一个超链接,该链接指向对应关系 model 的详细数据,view-name 是必选参数,为对应的视图生成超链接。

参数:

  • view_name 用作关系目标的视图名称。如果使用的是标准路由器类,那么它的格式为 <modelname>-detail 的字符串
  • queryset 验证字段输入时用于模型实例查询的查询器。关系必须明确设置 queryset,或设置 read_only = True
  • many 如果应用于多对多关系,则应将此参数设置为 True
  • allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False
  • lookup_field 应该用于查找的目标上的字段。应该对应于引用视图上的 URL 关键字参数。默认值为 pk
  • lookup_url_kwarg 与查找字段对应的 URL conf 中定义的关键字参数的名称。默认使用与 lookup_field 相同的值
  • format 如果使用 format 后缀,超链接字段将对目标使用相同的 format 后缀,除非使用 format 参数进行覆盖。
from rest_framework import serializers
from .models import Article,Category
#HyperlinkedRelatedField

class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.HyperlinkedRelatedField(
        view_name= 'category-detail',  #urls路由的别名
        lookup_field= 'id', #数据库字段的名字,这个字段到数据库中去找
        read_only=True
    )
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')


class CategorySerializer(serializers.ModelSerializer):
    articles = serializers.HyperlinkedRelatedField(
        view_name = 'article-detail',
        lookup_field = "id",
        many=True,
        read_only=True
    )
    class Meta:
        model = Category
        fields = ('id','name','articles')

错误解决:

`HyperlinkedRelatedField` requires the request in the serializer context. Add `context={'request': request}` when instantiating the serializer.

在所有使用ArticleSerializer和CategorySerializer的地方加上context={'request': request},编辑视图views.py:

#序列化文章标题时,加上context={'request':request}
ser = ArticleSerializer(instance=art,context={'request':request})

#序列化分类时,加context={'request':request}参数
ser = CategorySerializer(instance=arts, many=True,context={'request':request})

post运行结果:

#访问文章标题
GET: http://127.0.0.1:8000/api/article/2/

运行结果;
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": "http://127.0.0.1:8000/api/category/2/"
}


#访问分类
GET:http://127.0.0.1:8000/api/category/2/

运行的结果:
{
    "id": 2,
    "name": "监控中心",
    "articles": [
        "http://127.0.0.1:8000/api/article/2/"
    ]
}

那我如果在根级路由写了一个别名,我想调用访问咋办啊,设置根级路由:

from django.urls import path, include
from app01 import views

urlpatterns = [
    ...
    path('api/', include(('app02.urls', 'app02'), namespace="app02"))  #根级路由设置命名空间
]

我在 serializers.py中的HyperlinkedRelatedField 这么使用:

class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.HyperlinkedRelatedField(
        view_name= 'app02:category-detail',  #需要加上根级路由app02
        ...
    )


class CategorySerializer(serializers.ModelSerializer):
    articles = serializers.HyperlinkedRelatedField(
        view_name = 'app02:article-detail', #需要加上根级路由app02
        ...
    )

2.4、SlugRelatedField

说明:使用 SlugRelatedField 将返回一个指定对应关系 model 中的字段,需要参数 slug_field 中指定字段名称。

参数:

  • slug_field 应该用于表示目标的字段。这应该是唯一标识任何给定实例的字段。例如 username 。这是必选参数
  • queryset 验证字段输入时用于模型实例查询的查询器。 关系必须明确设置 queryset,或设置 read_only = True
  • many 如果应用于多对多关系,则应将此参数设置为 True
  • allow_null 如果设置为 True,则该字段将接受 None 的值或为空的关系的空字符串。默认为 False
#SlugRelatedField

class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.SlugRelatedField(
        read_only=True,
        slug_field= 'name'  #指定只返回模型类Category中的某个字段,这边我们返回name吧。
    )
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')


class CategorySerializer(serializers.ModelSerializer):
    articles = serializers.SlugRelatedField(
        read_only=True,
        slug_field='vum',  #指定只返回模型类Article的vum字段
        many=True
    )
    class Meta:
        model = Category
        fields = ('id','name','articles')

post运行结果:

#article文章路由
GET: http://127.0.0.1:8000/api/article/2/

运行结果:
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": "监控中心"  #返回Catagory中的name值
}

#访问category分类路由
GET:http://127.0.0.1:8000/api/category/2/

运行结果;
{
    "id": 2,
    "name": "监控中心",
    "articles": [  #返回Article中的vum值
        12
    ]
}

2.4、HyperlinkedIdentityField

说明:使用 HyperlinkedIdentityField 将返回指定 view-name 的超链接的字段。

参数:

  • view_name 应该用作关系目标的视图名称。如果您使用的是标准路由器类,则它将是格式为 <model_name>-detail的字符串。必选参数
  • lookup_field 应该用于查找的目标上的字段。应该对应于引用视图上的 URL 关键字参数。默认值为 pk
  • lookup_url_kwarg 与查找字段对应的 URL conf 中定义的关键字参数的名称。默认使用与 lookup_field 相同的值
  • format 如果使用 format 后缀,超链接字段将对目标使用相同的 format 后缀,除非使用 format 参数进行覆盖
# HyperlinkedIdentityField
class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.HyperlinkedIdentityField(
        view_name= "category-detail",  #view_name是必须传的
        lookup_field= 'id' #默认是pk

    )
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')


class CategorySerializer(serializers.ModelSerializer):
    articles = serializers.HyperlinkedIdentityField(
        view_name= "article-detail",
        many=True
    )
    class Meta:
        model = Category
        fields = ('id','name','articles')

post运行结果:

#article文章路由
GET: http://127.0.0.1:8000/api/article/2/

运行结果:
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": "http://127.0.0.1:8000/api/category/2/"
}

#访问category分类路由
GET:http://127.0.0.1:8000/api/category/2/

运行结果;
{
    "id": 2,
    "name": "监控中心",
    "articles": [
        "http://127.0.0.1:8000/api/article/2/"
    ]
}

三、HyperlinkedModelSerializer

说明:HyperlinkedModelSerializer 类与 ModelSerializer 类相似,只不过它使用超链接来表示关系而不是主键。用这个序列化的时候,必须继承的是HyperlinkedModelSerializer,而不是 ModelSerializer了。

#HyperlinkedModelSerializer

class ArticleSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Article
        fields = "__all__"

        extra_kwargs = {
            'url': {'view_name': 'article-detail', 'lookup_field': 'id'},
            'category': {'view_name': 'category-detail', 'lookup_field': 'id'},
        }


class CategorySerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Category
        fields = ('id','name','articles','url')  #url字段自己添加

        extra_kwargs = {
            'url': {'view_name': 'category-detail', 'lookup_field': 'id'},
            'articles': {'view_name': 'article-detail', 'lookup_field': 'id'},
        }

注意:

使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数---字典格式

extra_kwargs = {

  'vnum': {'min_value': 0, 'required': True},
}

postman运行结果:

#article文章路由
GET: http://127.0.0.1:8000/api/article/2/

运行结果:
{
    "url": "http://127.0.0.1:8000/api/article/2/",
    "title": "gaogege is very handsome",
    "vum": 12,
    "content": "that is very error",
    "category": "http://127.0.0.1:8000/api/category/2/"
}

#访问category分类路由
GET:http://127.0.0.1:8000/api/category/2/

运行结果;
{
    "id": 2,
    "name": "监控中心",
    "articles": [
        "http://127.0.0.1:8000/api/article/2/"
    ],
    "url": "http://127.0.0.1:8000/api/category/2/"
}

看到了吧,如果你重新定义字段的话,需要在 extra_kwargs 中通过字典的方式修改,跟ModelSerializer是不一样的。

四、 嵌套序列化关系模型

顾名思义就是序列化里面有另一个序列化类。这要强调一下,序列化嵌套,只能一方嵌套一方,不能相互嵌套。

#序列化嵌套

class ArticleSerializer(serializers.ModelSerializer):
    #category = CategorySerializer() 这边不能嵌套CategorySerializer(),会报CategorySerializer没有定义错误
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')


class CategorySerializer(serializers.ModelSerializer):
    articles = ArticleSerializer(many=True)  #所以只能这边嵌套序列化关系

    class Meta:
        model = Category
        fields = ('id','name','articles')  #articles先通过文章模型(Article类)去找文章序列化,系列化哪些字段,这边是全局字段

postman运行结果:

GET: http://127.0.0.1:8000/api/category/1/

运行结果:
{
    "id": 2,
    "articles": [  #关联的文章信息全部显示出来
        {
            "id": 2,
            "vum": 12,
            "content": "that is very error",
            "title": "gaogege is very handsome",
            "category": 2
        }
    ],
    "name": "监控中心"
}

序列化嵌套: 会去找对应的模型类(Modles),然后再去序列化出来。

五、深度遍历:depth

depth:这个字段可以用来深度遍历。就是继续往下找,官网上最多深度遍历10层,但是一般建议 2-3层,但是只是叠加数据返回量。

#序列化嵌套

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')
        depth = 2  #表示深度查找2层


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id','name','articles')

postman运行结果:

GET:http://127.0.0.1:8000/api/article/2/
运行结果:
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": {  #深度显示详细数据
        "id": 2,
        "name": "监控中心"
    }
}

六、自定义属性:SerializerMethodField

说明:通过这个属性我们可以自定义一些属性。比如说我们要统计 count字段等。

class CategorySerializer(serializers.ModelSerializer):
    #articles = ArticleSerializer(many=True)
    count = serializers.SerializerMethodField()  #自定义序列化方法字段count
    class Meta:
        model = Category
        fields = ('id','name','articles','count')  #加上count字段

    def get_count(self,obj):  #obj指得是model模型Category类对象
        return obj.articles.count()  #articles反查的字段

上述代码说明:

count = serializers.SerializerMethodField()  #自定义方法字段

fields = (...,'count')  #count这边需要作为响应显示

def get_count(self,obj) => 方法名:get_字段名。obj:指的是当前序列化类对应的模型类这里是Category的对象。

postman运行结果:

GET:http://127.0.0.1:8000/api/category/2/

运行结果:
{
    "id": 2,
    "name": "监控中心",
    "articles": [
        2
    ],
    "count": 1   #返回字段的值
}

七、 自定义数据源:source

序列化的时候指定数据源

7.1、数据来源(source)是外键中的某个字段的值

#source
class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.CharField(source="category.name")  #数据来源是Category类中的name值

    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category')

postman请求运行结果:

GET:http://127.0.0.1:8000/api/article/2/

运行结果:
{
    "id": 2,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": "监控中心"   #数据来源是category类中的name值
}

7.2、数据来源(source)是外键中的所有字段的值 

#source
class ArticleSerializer(serializers.ModelSerializer):
    .....


class CategorySerializer(serializers.ModelSerializer):
    arts = serializers.CharField(source="articles.all") # related反查的情况下用articles.all
    #arts = serializers.CharField(source="articles_set.all") #没有related反查的情况下用articles_set.all
    class Meta:
        model = Category
        fields = ('id','name','articles','arts')  #添加arts字段

postman请求运行结果:

GET: http://127.0.0.1:8000/api/category/2/

运行结果:
{
    "id": 2,
    "name": "监控中心",
    "articles": [
        2
    ],
    "arts": "<QuerySet [<Article: gaogege is very handsome>]>"  #获取的是 QuerySet 对象
}

但是我们不是需要返回的一个QuerySet的对象,我们想要的是数据,所以我们对显示的数据需要用to_representation方法重写:

#source

class MyCharField(serializers.CharField):
    def to_representation(self, value):  #value 就是 articles.all中所有的值
        data_list = []
        for row in value:
            data_list.append({'title': row.title, 'content': row.content})
        return data_list  #必须要有返回值

....

class CategorySerializer(serializers.ModelSerializer):
    arts = MyCharField(source="articles.all")  #MyCharField需要跟上面自定义的一样
    class Meta:
        model = Category
        fields = ('id','name','articles','arts')

postman请求运行结果: 

GET: http://127.0.0.1:8000/api/category/2/

运行结果:
{
    "id": 2,
    "name": "监控中心",
    "articles": [
        2
    ],
    "arts": [
        {
            "title": "gaogege is very handsome",
            "content": "that is very error"
        }
    ]
}

7.3、利用source实现可读可写

from collections import OrderedDict


class ChoiceDisplayField(serializers.Field):
    """Custom ChoiceField serializer field."""

    def __init__(self, choices, **kwargs):
        """init."""
        self._choices = OrderedDict(choices)
        super(ChoiceDisplayField, self).__init__(**kwargs)

    # 返回可读性良好的字符串而不是 1,-1 这样的数字
    def to_representation(self, obj):
        """Used while retrieving value for the field."""
        return self._choices[obj]

    def to_internal_value(self, data):
        """Used while storing value for the field."""
        for i in self._choices:
            # 这样无论用户POST上来但是CHOICES的 Key 还是Value 都能被接受
            if i == data or self._choices[i] == data:
                return i
        raise serializers.ValidationError("Acceptable values are {0}.".format(list(self._choices.values())))

八、 to_representation方法(多对多关系):自定义字段格式显示

序列化器的每个字段实际都是由该字段类型的to_representation方法决定格式的,可以通过重写该方法来决定格式。

8.1、模型定义

说明:增加Tag表,实现Article 和 Tag 产生多对多关系。

from django.db import models


class Article(models.Model):
    title = models.CharField(verbose_name='标题', max_length=100)
    vum = models.IntegerField(verbose_name='浏览量')
    content = models.TextField(verbose_name='内容')
    category = models.ForeignKey(to="Category",on_delete=models.CASCADE,related_name="articles")  #related_name反查
    tags = models.ManyToManyField(to="Tag",related_name="articles") #related_name反查

    def __str__(self):
        return self.title

class Category(models.Model):
    name = models.CharField(verbose_name="分类",max_length=10)

    def __str__(self):
        return  self.name


class Tag(models.Model):
    name = models.CharField(verbose_name="标签名字",max_length=10)
    create_time = models.DateTimeField()

    def __str__(self):
        return self.name

8.2、序列化

说明:编写serializers.py,增加Tags序列化

# to_representation方法

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category','tags')


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id','name','articles')


class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ('id','name','create_time')

8.3、路由定义

说明:定义路由 app02 ->  urls.py

from django.urls import path
from app02 import views


urlpatterns = [
    ....

    path("tag/", views.tag_list, name="tag-list"),
    path("tag/<int:id>/", views.tag_detail, name="tag-detail")
]

8.3、视图

说明:跟上面一样,增加Tag的视图函数

from .serializers import ArticleSerializer,CategorySerializer,TagSerializer
....
from .models import Article,Category,Tag
...

# Create your views here.

class JSONResponse(HttpResponse):
    ....


....


@csrf_exempt
def tag_list(request):
    if request.method == "GET":
        arts = Tag.objects.all()
        ser = TagSerializer(instance=arts, many=True,context={'request':request})
        return JSONResponse(ser.data, status=200)
    elif request.method == "POST":
        data = JSONParser().parse(request)
        ser = TagSerializer(data=data)
        if ser.is_valid():
            ser.save()
            return JSONResponse(ser.data, status=201)
        return JSONResponse(ser.errors,status=401)


@csrf_exempt
def tag_detail(request,id):
    try:
        art = Tag.objects.get(id=id)
    except Tag.DoesNotExist as e:
        return HttpResponse(status=404)

    if request.method == "GET":
        ser = TagSerializer(instance=art,context={'request':request})
        return JSONResponse(ser.data,status=200)

    elif request.method == "PUT":
        data = JSONParser().parse(request)
        ser = TagSerializer(instance=art,data=data,context={'request':request})
        if ser.is_valid():
            ser.save()
            return JSONResponse(ser.data,status=201)
        return JSONResponse(ser.errors,status=400)
    elif request.method == "PATCH":
        data = JSONParser().parse(request)
        ser = TagSerializer(instance=art,data=data,partial=True,context={'request':request})
        if ser.is_valid():
            ser.save()
            return JSONResponse(ser.data,status=201)
        return JSONResponse(ser.errors,status=400)

    elif request.method == "DELETE":
        art.delete()
        return HttpResponse(status=204)
views.py

 8.4、初始化数据库

>python manage.py makemigrations
>python manage.py migrate

8.5、造tags数据

8.6、更改数据展示

class TagSerializer(serializers.ModelSerializer):
    create_time = serializers.DateTimeField(format='%Y-%m-%d')  #时间展示
    class Meta:
        model = Tag
        fields = ('id','name','create_time')

postman执行数据

POST: http://127.0.0.1:8000/api/tag/

入参:
{
    "name": "标签四",
    "create_time": "2020-04-26 20:20:20"
}

出参:
{
    "id": 4,
    "name": "标签四",
    "create_time": "2020-04-26"  #显示格式改变
}

8.6、增加多对多数据

8.7、depth深度显示

说明:深度显示只支持序列化,但是不支持反序列化。意思就是:能获取数据(get),但是想要插入数据或者更新数据(post、put、patch)就不可以了。

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category','tags')
        depth = 2  #深度显示,只支持序列化(get),不支持反序列化(post、patch、put)

运行结果:

8.8、to_representation方法

说明:depath只能解决序列化问题,但是不能解决反序列化问题,所以这个时候我们就要用到to_representation方法。序列化器的每个字段实际都是由该字段类型的to_representation方法决定格式的,可以通过重写该方法来决定格式。也就是说具体的返回的值是由to_representation方法决定的,它需要传入一个参数instance,表示当前的 实例对象。

# to_representation方法

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ("id", 'vum', 'content', 'title','category','tags')
        #depth = 2
    #决定每个字段的返回值
    def to_representation(self, instance):  #这边就是Article的model的实例
        representation = super(ArticleSerializer, self).to_representation(instance)
        representation['category'] = CategorySerializer(instance.category).data
        representation['tags'] = TagSerializer(instance.tags, many=True).data  #这边tags 想返回哪些字段是TagSerializer中的fields决定的
        return representation

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('id','name','articles')


class TagSerializer(serializers.ModelSerializer):
    create_time = serializers.DateTimeField(format='%Y-%m-%d')  #时间展示
    class Meta:
        model = Tag
        fields = ('id','name','create_time')

postman运行结果:

1、新增数据post方法:

POST:http://127.0.0.1:8000/api/article/
入参:
{
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": 2,
    "tags": [1,2,3,4]
}

出参:
{
    "id": 10,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": {
        "id": 2,
        "name": "监控中心",
        "articles": [
            2,
            8,
            9,
            10
        ]
    },
    "tags": [
        {
            "id": 1,
            "name": "标签一",
            "create_time": "2020-04-26"
        },
        {
            "id": 2,
            "name": "标签二",
            "create_time": "2020-04-26"
        },
        {
            "id": 3,
            "name": "标签三",
            "create_time": "2020-04-26"
        },
        {
            "id": 4,
            "name": "标签四",
            "create_time": "2020-04-26"
        }
    ]
}

2、获取数据GET方法:

GET:http://127.0.0.1:8000/api/article/9/

出参:
{
    "id": 9,
    "vum": 12,
    "content": "that is very error",
    "title": "gaogege is very handsome",
    "category": {
        "id": 2,
        "name": "监控中心",
        "articles": [
            2,
            8,
            9,
            10
        ]
    },
    "tags": [
        {
            "id": 1,
            "name": "标签一",
            "create_time": "2020-04-26"
        },
        {
            "id": 2,
            "name": "标签二",
            "create_time": "2020-04-26"
        }
    ]
}
            "id": 3,
            "name": "标签三",
            "create_time": "2020-04-26"
        },
        {
            "id": 4,
            "name": "标签四",
            "create_time": "2020-04-26"
        }
    ]
}

 

posted @ 2020-04-23 14:12  帅丶高高  阅读(1217)  评论(0)    收藏  举报