Appearance
传统 Django 中就有基于类的视图的存在,DRF 中自然也有。优点也都差不多,即实现功能的模块化继承、封装,减少重复代码。接下来就用文章详情接口练练手。
首先在视图中新增下面的代码:
python
# article/views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from django.http import Http404
from article.models import Article
from article.serializers import ArticleDetailSerializer
class ArticleDetail(APIView):
"""文章详情视图"""
def get_object(self, pk):
"""获取单个文章对象"""
try:
# pk 即主键,默认状态下就是 id
return Article.objects.get(pk=pk)
except:
raise Http404
def get(self, request, pk):
article = self.get_object(pk)
serializer = ArticleDetailSerializer(article)
# 返回 Json 数据
return Response(serializer.data)
def put(self, request, pk):
article = self.get_object(pk)
serializer = ArticleDetailSerializer(article, data=request.data)
# 验证提交的数据是否合法
# 不合法则返回400
if serializer.is_valid():
# 序列化器将持有的数据反序列化后,
# 保存到数据库中
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
article = self.get_object(pk)
article.delete()
# 删除成功后返回204
return Response(status=status.HTTP_204_NO_CONTENT)
...
代码不复杂,就是提供了对文章详情的获取、修改、删除的 3 个方法,以及 1 个用于获取单个文章 model 的辅助方法。和之前说的一样,DRF 类视图与传统 Django 的区别,.get()
、 .put()
就是多了一个将对象序列化(或反序列化)的步骤。.delete()
方法因为不用返回实际数据,执行完删除动作就OK了。
从这个地方就可以看出,序列化器
serializer
不仅可以将数据进行序列化、反序列化,还包含数据验证、错误处理、数据库操作等能力。序列化这个概念与具体语言无关。Python 或 JavaScript 对象转换为 Json 都称为序列化,反之为反序列化。Json 是两种语言传输信息的桥梁,一但信息到达,对方都需要将其还原为自身的数据结构。
由于详情接口需要返回完整的字段数据(与阉割版的文章列表接口不同),所以要重新给它定义一个序列化器:
python
# article/serializers.py
...
class ArticleDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = '__all__'
fields = '__all__'
代表要使用所有字段。
配置 urls.py
:
python
# article/urls.py
...
urlpatterns = [
...
path('<int:pk>/', views.ArticleDetail.as_view(), name='detail'),
]
这就可以了。
发送一个请求试试:
python
# 再次提醒:建议用 Postman 来发送 web 请求
# 教程为了轻便使用了httpie,读者改为Postman即可
> http http://127.0.0.1:8000/api/article/1/
HTTP/1.1 200 OK
Allow: GET, PUT, DELETE, HEAD, OPTIONS
Content-Length: 141
Content-Type: application/json
...
{
"body": "Maybe say somthing here...",
"created": "2020-06-15T09:24:18Z",
"id": 1,
"title": "My first post",
"updated": "2020-06-15T09:24:38.622789Z"
}
再试试修改文章接口:(注意请求方式变成了 PUT
)
python
> http PUT http://127.0.0.1:8000/api/article/1/ title=something... body=changed...
HTTP/1.1 200 OK
...
{
"body": "changed...",
"created": "2020-06-15T09:24:18Z",
"id": 1,
"title": "something...",
"updated": "2020-07-02T07:05:49.554354Z"
}
再试试把它删除掉:
python
> http DELETE http://127.0.0.1:8000/api/article/1/
HTTP/1.1 204 No Content
Allow: GET, PUT, DELETE, HEAD, OPTIONS
...
这篇 id=1
的文章就被删除掉了。
通用视图
对数据的增删改查是几乎每个项目的通用操作,因此可以通过 DRF 提供的 Mixin 类直接集成对应的功能。
修改一下 ArticleDetail
视图:
python
# article/views.py
...
from rest_framework import mixins
from rest_framework import generics
class ArticleDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
"""文章详情视图"""
queryset = Article.objects.all()
serializer_class = ArticleDetailSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
使用 Mixin 已经足够简单了,但我们还可以让它更简单:
python
# article/views.py
...
class ArticleDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleDetailSerializer
发送请求试试,功能和最开头那个继承 APIView
的视图是完全相同的。
列表接口也可以做同样的修改:
python
# article/views.py
...
class ArticleList(generics.ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleListSerializer
除了上述介绍的以外,框架还提供
ListModelMixin
、CreateModelMixin
等混入类或通用视图,覆盖了基础的增删改查需求。