1.针对列表页和详情页接口定义不同的Serializer类,根据需求展示对应的字段
对应app下 serializers.py
from rest_framework import serializers, pagination
from .models import Post, Category
# 定义serializer序列化列表页的数据,类似于form表单,form表单继承自forms.ModelForm
class PostSerializer(serializers.ModelSerializer):
# 类似form表单,对某些特殊的字段进行处理
# 外键需要如下配置
category = serializers.SlugRelatedField(
read_only=True,
slug_field='name',
)
tag = serializers.SlugRelatedField(
many=True, # 多对多
read_only=True, # 定义外键是否可写
slug_field='name', # 定义外键展示对应主表中的字段
)
owner = serializers.SlugRelatedField(read_only=True, slug_field='username',)
# 设置日期时间的格式
created_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
# 类似form表单,定义关联的模型以及列表页展示的字段
class Meta:
model = Post
# id用来获取详情页
fields = ['id', 'title', 'category', 'tag', 'owner', 'created_time']
# 定义详情页接口需要的Serializer类
# 继承自列表页的序列化器,然后重新定义展示的字段即可
class PostDetailSerializer(PostSerializer):
class Meta:
model = Post
fields = ['id', 'title', 'category', 'tag', 'owner', 'content_html', 'created_time']
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'name', 'created_time')
# 获取某个分类下的文章列表,从资源的角度看,相当于分类的详情页数据
class CategoryDetailSerializer(CategorySerializer):
# 将posts字段获取的内容映射到paginated_posts方法上
# 即最终返回数据时,posts对应的数据从paginated_posts方法中获取
posts = serializers.SerializerMethodField('paginated_posts')
# http://127.0.0.1:8000/api/category/2/?page=3
def paginated_posts(self, obj):
posts = obj.post_set.filter(status=Post.STATUS_NORMAL)
paginator = pagination.PageNumberPagination()
page = paginator.paginate_queryset(posts, self.context['request'])
serializer = PostSerializer(page, many=True, context={'request': self.context['request']})
return {
'count': posts.count(),
'results': serializer.data,
'previous': paginator.get_previous_link(),
'next': paginator.get_next_link(),
}
class Meta:
model = Category
fields = ('id', 'name', 'created_time', 'posts')
2.重写详情页获取数据的接口,指定serializer_class;根据分类获取对应的文章列表
对应app下 apis.py
from rest_framework import viewsets
from .models import Post, Category
from .serializers import PostSerializer, PostDetailSerializer, CategorySerializer, CategoryDetailSerializer
# 定义视图层的逻辑
class PostViewSet(viewsets.ReadOnlyModelViewSet):
"""文档说明,这里的内容可以在接口文档中看到"""
# 指定序列化的类和数据
serializer_class = PostSerializer
queryset = Post.objects.filter(status=Post.STATUS_NORMAL)
# 重写获取详情页数据的接口
def retrieve(self, request, *args, **kwargs):
# 重新赋值给serializer_class,以区分列表页和详情页的Serializer
self.serializer_class = PostDetailSerializer
return super().retrieve(request, *args, **kwargs)
# 获取某个分类下的文章列表
# http://127.0.0.1:8000/api/post/?category=2
def filter_queryset(self, queryset):
# 获取URL中category参数,然后进行过滤
category_id = self.request.query_params.get('category')
if category_id:
return queryset.filter(category_id=category_id)
return queryset
class CategoryViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CategorySerializer
queryset = Category.objects.filter(status=Category.STATUS_NORMAL)
# 重写分类的详情页接口,展示分类下的所有文章列表
def retrieve(self, request, *args, **kwargs):
self.serializer_class = CategoryDetailSerializer
return super().retrieve(request, *args, **kwargs)
3.实现分页,解决报错:‘AutoSchema’ object has no attribute ‘get_link’ settings.py
# 配置RESTful接口的分页
REST_FRAMEWORK = {
# 解决报错问题:'AutoSchema' object has no attribute 'get_link'
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
# 其他分页选项
# rest_framework.pagination.PageNumberPagination:常用,当前是第几页,每页多少条数据
# rest_framework.pagination.CursorPagination:不能自己输入分页参数,防止用户填写任意页码和数据量来获取数据
# Cursor分页默认以created字段来排序,如果表中没有该字段,可通过继承CursorPagination自定义ordering属性为id或其他字段
# 这个是基于偏移量和limit的分页,即当前是第几条,还要获取多少条
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 2,
}
4.关于获取某个分类下的文章列表:
1.在PostViewSet中通过获取URL上的查询参数,重写类似get_queryset的方法大来实现过滤(简单)
2.以资源的角度来看,获取分类下的文章列表,其实就相当于获取分类的详情页
5.url的配置
from rest_framework.routers import DefaultRouter
from finance.apis import FinanceViewSet
from rest_framework.documentation import include_docs_urls
# 创建router代理一整套的restful接口
router = DefaultRouter()
router.register(r'finance', FinanceViewSet, base_name='api-finance')
urlpatterns = [
path('api/', include(router.urls)),
path('api/docs/', include_docs_urls(title='finance_restful_doc')),
参考:《Django企业开发实战》