|
|
|
from rest_framework import serializers
|
|
|
|
from article.models import Article, Category, Tag
|
|
|
|
from user_info.serializers import UserDescSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class CategorySerializer(serializers.ModelSerializer):
|
|
|
|
"""所有分类的序列化器"""
|
|
|
|
# 将路由间的表示转换为超链接
|
|
|
|
# category-detail是自动注册路由时, Router默认帮你设置的详情页面的名称
|
|
|
|
url = serializers.HyperlinkedIdentityField(view_name='category-detail')
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Category
|
|
|
|
fields = '__all__'
|
|
|
|
# 创建时间不能修改
|
|
|
|
read_only_fields = ['created']
|
|
|
|
|
|
|
|
|
|
|
|
class ArticleBaseSerializer(serializers.HyperlinkedModelSerializer):
|
|
|
|
"""将原来的ArticleSerializer抽象出一个父类"""
|
|
|
|
author = UserDescSerializer(read_only=True)
|
|
|
|
# 希望文章接口不仅仅只返回分类的id而已,所以需要显式指定category,将其变成一个嵌套数据,
|
|
|
|
# 分类的嵌套序列化字段
|
|
|
|
category = CategorySerializer(read_only=True)
|
|
|
|
# 显示指定category的id字段,用于创建/更新category外键
|
|
|
|
category_id = serializers.IntegerField(write_only=True, allow_null=True, required=False)
|
|
|
|
# 新增tag字段, 直接显示Tag的text字段
|
|
|
|
tags = serializers.SlugRelatedField(
|
|
|
|
queryset=Tag.objects.all(),
|
|
|
|
many=True,
|
|
|
|
required=False,
|
|
|
|
slug_field='text',
|
|
|
|
)
|
|
|
|
|
|
|
|
# 验证category_id是否正确
|
|
|
|
def validate_category_id(self, value):
|
|
|
|
if not Category.objects.filter(id=value).exists() and value is not None:
|
|
|
|
raise serializers.ValidationError("Category with id {} not exist.".format(value))
|
|
|
|
return value
|
|
|
|
|
|
|
|
def to_internal_value(self, data):
|
|
|
|
tags_data = data.get('tags')
|
|
|
|
if isinstance(tags_data, list):
|
|
|
|
for text in tags_data:
|
|
|
|
# 不存在该标签则创建它
|
|
|
|
if not Tag.objects.filter(text=text).exists():
|
|
|
|
Tag.objects.create(text=text)
|
|
|
|
return super().to_internal_value(data)
|
|
|
|
|
|
|
|
|
|
|
|
class ArticleSerializer(ArticleBaseSerializer):
|
|
|
|
"""文章序列化器"""
|
|
|
|
class Meta:
|
|
|
|
model = Article
|
|
|
|
fields = '__all__'
|
|
|
|
# body字段只可写不可见
|
|
|
|
extra_kwargs = {'body': {'write_only': True}}
|
|
|
|
|
|
|
|
|
|
|
|
class ArticleDetailSerializer(ArticleBaseSerializer):
|
|
|
|
# 渲染后的正文
|
|
|
|
body_html = serializers.SerializerMethodField()
|
|
|
|
# 渲染后的目录
|
|
|
|
toc_html = serializers.SerializerMethodField()
|
|
|
|
|
|
|
|
def get_body_html(self, obj):
|
|
|
|
return obj.get_md()[0]
|
|
|
|
|
|
|
|
def get_toc_html(self, obj):
|
|
|
|
return obj.get_md()[1]
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Article
|
|
|
|
fields = '__all__'
|
|
|
|
|
|
|
|
|
|
|
|
class ArticleCategoryDetailSerializer(serializers.ModelSerializer):
|
|
|
|
"""分类详情的嵌套序列化器"""
|
|
|
|
url = serializers.HyperlinkedIdentityField(view_name='article-detail')
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Article
|
|
|
|
fields = [
|
|
|
|
'url',
|
|
|
|
'title',
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class CategoryDetailSerializer(serializers.ModelSerializer):
|
|
|
|
"""具体的分类详情页不显示url"""
|
|
|
|
# 显示某个分类下的所有文章
|
|
|
|
articles = ArticleCategoryDetailSerializer(many=True, read_only=True)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Category
|
|
|
|
fields = [
|
|
|
|
'id',
|
|
|
|
'title',
|
|
|
|
'created',
|
|
|
|
'articles',
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class TagSerializer(serializers.ModelSerializer):
|
|
|
|
# 显示url
|
|
|
|
# url = serializers.HyperlinkedIdentityField(view_name='tag-detail')
|
|
|
|
|
|
|
|
"""所有标签序列化器"""
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Tag
|
|
|
|
fields = '__all__'
|
|
|
|
|
|
|
|
# 创建或者更新前检查是否存在该tag
|
|
|
|
def check_tag_obj_exists(self, validated_data):
|
|
|
|
text = validated_data.get('text')
|
|
|
|
if Tag.objects.filter(text=text).exists():
|
|
|
|
raise serializers.ValidationError('Tag with text {} exists.'.format(text))
|
|
|
|
|
|
|
|
def create(self, validated_data):
|
|
|
|
self.check_tag_obj_exists(validated_data)
|
|
|
|
return super(TagSerializer, self).create(validated_data)
|
|
|
|
|
|
|
|
def update(self, instance, validated_data):
|
|
|
|
self.check_tag_obj_exists(validated_data)
|
|
|
|
return super(TagSerializer, self).update(instance, validated_data)
|
|
|
|
|
|
|
|
|