Contents
Django开发restful api的最佳实践 (三)——Serializers、View和Url路由
承接本系列的上面两篇
– Django开发restful api的最佳实践 (一) 环境和django框架搭建
– Django开发restful api的最佳实践 (二) 创建model和测试用例
本篇将会介绍django-rest-framework方面的东西,好了let’s go。
在上一篇中我们写完了我们本次的demo的实体类Book,也就是我们要围绕着这Book使用django-rest-framework(以下简称drf)实现增删改查的Restful API。
编写serializer.py
所谓的restful api,数据的交换格式自然是json,所以就需要一个将model和前台json互相转换的媒介 这个媒介就是serializer。在我们的django应用目录也就是api/下新建一个文件 serializer.py 。内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #!/usr/bin/env python
# -*- coding:utf-8 -*-
# api/serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id', 'name', 'date_created', 'date_modified')
read_only_fields = ('date_created', 'date_modified')
编写视图层 views.py
接下来我们可以编写视图层views.py 这个文件应该在我们生成django app的时候已经创建了,我们打开它。题外话,虽然叫视图层,但是如果你做过java web或者php的话,会觉得这一层叫controller层更合适一些,因为这里主要是一些web逻辑部分。
编辑此文件为如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 from django.shortcuts import render
# Create your views here.
from rest_framework import generics
from .serializers import BookSerializer
from .models import Book
class CreateView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def perform_create(self, serializer):
serializer.save()
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
可以看到每个view都继承自drf里面的generics里的通用视图。
比如generics.ListCreateAPIView 提供默认的restful中的list(列)和create(增)
generics.RetrieveUpdateDestroyAPIView 则提供get(查),put(改),delete(删)功能
编写测试用例 tests.py
这个不用多说,直接编辑tests.py 为如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 from django.test import TestCase
# Create your tests here.
from django.test import TestCase
from .models import Book
from rest_framework.test import APIClient
from rest_framework import status
# from django.core.urlresolvers import reverse
from django.urls import reverse # 2.0的变化
class ModelTestCase(TestCase):
def setUp(self):
self.book = Book(name="Thinking in Python")
def test_model_can_create_a_book(self):
old_count = Book.objects.count()
self.book.save()
new_count = Book.objects.count()
self.assertEqual(old_count + 1, new_count)
class ViewTestCase(TestCase):
"""Test suite for the api views."""
def setUp(self):
"""Define the test client and other test variables."""
self.client = APIClient()
self.book_data = {'name': 'Thinking in java'}
self.response = self.client.post(
reverse('create'),
self.book_data,
format="json")
def test_api_can_create_a_book(self):
"""Test the api has bucket creation capability."""
self.assertEqual(self.response.status_code, status.HTTP_201_CREATED)
def test_api_can_get_a_book(self):
"""Test the api can get a given book."""
book = Book.objects.get()
response = self.client.get(
reverse('details',
kwargs={'pk': book.id}), format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertContains(response, book)
def test_api_can_update_book(self):
"""Test the api can update a given book."""
book = Book.objects.get()
change_book = {'name': 'Thinking in php'}
res = self.client.put(
reverse('details', kwargs={'pk': book.id}),
change_book, format='json'
)
self.assertEqual(res.status_code, status.HTTP_200_OK)
def test_api_can_delete_book(self):
"""Test the api can delete a book."""
book = Book.objects.get()
response = self.client.delete(
reverse('details', kwargs={'pk': book.id}),
format='json',
follow=True)
self.assertEquals(response.status_code, status.HTTP_204_NO_CONTENT)
这里也注释了reverse函数在django2.0之前是django.core.urlresolvers里的,django2.0中改成了django.urls包。
测试用例写完,我们可以执行一下
1 | python manage.py test |
不出意外 就会提示ok,而且不用担心测试用例会弄脏我们的数据库,django执行测试用例的时候会创建临时的db,执行完后会清理掉的。
编写url路由
Django的url配置最好的方法就是在顶层项目文件夹中(也就是和settings.py同级别的目录)的urls.py中通过include的方式,引入各个django app中的urls.py 这样结构清晰,方便管理维护。
所以我们首先编辑settings.py同级目录下的urls.py(我们可以叫他根urls.py)
1
2
3
4
5
6
7
8 from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^', include('api.urls')) # 引入api模块下的urls.py
]
然后再编辑api/urls.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #!/usr/bin/env python
# -*- coding:utf-8 -*-
# api/urls.py
from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from .views import CreateView, DetailsView
urlpatterns = {
url(r'^book/$', CreateView.as_view(), name="create"),
url(r'^book/(?P<pk>[0-9]+)/$',
DetailsView.as_view(), name="details"),
}
urlpatterns = format_suffix_patterns(urlpatterns)
这样我们基本上这一篇算是完工了,现在来验证成功
运行demo
执行
1 | python manage.py runserver |
然后再浏览器里打开 “http://localhost:8000/book”
不出意外 你会看到类似如下的页面
这也是drf的一大好处 给我们提供了一个完善的api可视化测试页面,你可以在这个页面上试一下我们实现的增删改查的restful接口。