欢迎光临
我们一直在努力

Django开发restful api的最佳实践 (三)——Serializers、View和Url路由

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”
不出意外 你会看到类似如下的页面

django drf框架测试页面

这也是drf的一大好处 给我们提供了一个完善的api可视化测试页面,你可以在这个页面上试一下我们实现的增删改查的restful接口。

后续篇章,我们会介绍djangorestframework 引入授权认证

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » Django开发restful api的最佳实践 (三)——Serializers、View和Url路由
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址