Django RESTful API的测试驱动开发

This post walks through the process of developing a CRUD-based RESTful API with Django and Django REST Framework, which is used for rapidly building RESTful APIs based on Django models.

这篇文章逐步介绍了使用Django和Django REST Framework开发基于CRUD的RESTful API的过程,该过程用于基于Django模型快速构建RESTful API。

Django REST Framework logo

NOTE: Check out the third Real Python course for a more in-depth tutorial on Django REST Framework.

注意:查看第三本Real Python课程,以获得有关Django REST Framework的更深入的教程。

This application uses:

该应用程序使用:

  • Python v3.6.0
  • Django v1.11.0
  • Django REST Framework v3.6.2
  • Postgres v9.6.1
  • Psycopg2 v2.7.1
  • Python v3.6.0
  • Django v1.11.0
  • Django REST框架v3.6.2
  • Postgres v9.6.1
  • Psycopg2 v2.7.1

目标 (Objectives)

By the end of this tutorial you will be able to…

在本教程结束时,您将能够...

  1. Discuss the benefits of using Django REST Framework for bootstrapping the development of a RESTful API
  2. Validate model querysets using serializers
  3. Appreciate Django REST Framework’s Browsable API feature for a cleaner and well-documented version of your APIs
  4. Practice test-driven development
  1. 讨论使用Django REST Framework引导RESTful API开发的好处
  2. 使用序列化器验证模型查询集
  3. 赞赏Django REST Framework的Browsable API功能,可实现API的更干净和文档完善的版本
  4. 实践测试驱动的开发

为什么选择Django REST Framework? (Why Django REST Framework?)

Django REST Framework (REST Framework) provides a number of powerful features out-of-the-box that go well with idiomatic Django, including:

Django REST框架(REST框架)提供了许多现成的Django良好的强大功能,其中包括:

  1. Browsable API: Documents your API with a human-friendly HTML output, providing a beautiful form-like interface for submitting data to resources and fetching from them using the standard HTTP methods.
  2. Auth Support: REST Framework has rich support for various authentication protocols along with permissions and throttling policies which can be configured on a per-view basis.
  3. Serializers: Serializers are an elegant way of validating model querysets/instances and converting them to native Python datatypes that can be easily rendered into JSON and XML.
  4. Throttling: Throttling is way to determine whether a request is authorized or not and can be integrated with different permissions. It is generally used for rate limiting API requests from a single user.
  1. 可浏览的API :通过对人类友好HTML输出来记录您的API,并提供一个漂亮的类似于表单的界面,用于使用标准的HTTP方法将数据提交到资源并从中获取。
  2. 身份验证支持 :REST框架对各种身份验证协议以及权限和限制策略提供了丰富的支持,可以基于每个视图进行配置。
  3. 序列化器 :序列化器是一种验证模型查询集/实例并将其转换为可轻松呈现为JSON和XML的本地Python数据类型的绝妙方法。
  4. 限制 :限制是一种确定请求是否被授权并且可以与不同权限集成的方法。 它通常用于限制来自单个用户的API请求的速率。

Plus, the documentation is easy to read and full of examples. If you’re building a RESTful API where you have a one-to-one relationship between your API endpoints and your models, then REST Framework is the way to go.

另外,该文档易于阅读并且包含示例。 如果要构建RESTful API,并且API端点和模型之间具有一对一的关系,那么REST Framework是可行的方法。

Django专案设定 (Django Project Setup)

Create and activate a virtualenv:

创建并激活一个virtualenv:

1
1
2
2
3
3
4
4

Install Django and set up a new project:

安装Django并建立一个新项目:

1
1
2
2

Your current project structure should look like this:

您当前的项目结构应如下所示:

1
1
2
2
3
3
4
4
5
5
6
6
7
7

Django App和REST框架设置 (Django App and REST Framework Setup)

Start by creating the puppies app and installing REST Framework inside your virtualenv:

首先创建puppies应用程序,然后在您的virtualenv中安装REST Framework:

1
1
2
2
3
3

Now we need to configure our Django project to make use of REST Framework.

现在,我们需要配置Django项目以使用REST框架。

First, add the puppies app and rest_framework to the INSTALLED_APPS section within puppy_store/puppy_store/settings.py:

首先,添加puppies的应用程序和rest_frameworkINSTALLED_APPS内puppy_store / puppy_store / settings.py部分:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10

Next, define global settings for REST Framework in a single dictionary, again, in the settings.py file:

接下来,再次在settings.py文件中为单个字典定义REST Framework的全局设置

1
1
2
2
3
3
4
4
5
5
6
6
7
7

This allows unrestricted access to the API and sets the default test format to JSON for all requests.

这允许无限制地访问API,并将所有请求的默认测试格式设置为JSON。

NOTE: Unrestricted access is fine for local development, but in a production environment you may need to restrict access to certain endpoints. Make sure to update this. Review the docs for more information.

注意:不受限制的访问适合于本地开发,但是在生产环境中,您可能需要限制对某些端点的访问。 确保对此进行更新。 查看文档以获取更多信息。

Your current project structure should now look like:

您当前的项目结构现在应如下所示:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16

数据库和模型设置 (Database and Model Setup)

Let’s set up the Postgres database and apply all the migrations to it.

让我们设置Postgres数据库并将所有迁移应用到该数据库。

NOTE: Feel free to swap out Postgres for the relational database of your choice!

注意 :随意将Postgres换成您选择的关系数据库!

Once you have a working Postgres server on your system, open the Postgres interactive shell and create the database:

一旦您的系统上有可用的Postgres服务器,打开Postgres交互式外壳并创建数据库:

1
1
2
2
3
3
4
4

Install psycopg2 so that we can interact with the Postgres server via Python:

安装psycopg2,以便我们可以通过Python与Postgres服务器进行交互:

1
1

Update the database configuration in settings.py, adding the appropriate username and password:

在settings.py中更新数据库配置,并添加适当的用户名和密码:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10

Next, define a puppy model with some basic attributes in django-puppy-store/puppy_store/puppies/models.py:

接下来,在django-puppy-store / puppy_store / puppies / models.py中定义具有一些基本属性的小狗模型:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20

Now apply the migration:

现在应用迁移:

1
1
2
2

完整性检查 (Sanity Check)

Hop into psql again and verify that the puppies_puppy has been created:

再次跳入psql并验证是否已创建puppies_puppy

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19

NOTE: You can run d+ puppies_puppy if you want to look at the actual table details.

注意:如果要查看实际的表详细信息,可以运行d+ puppies_puppy

Before moving on, let’s write a quick unit test for the Puppy model.

在继续之前,让我们为Puppy模型编写一个快速的单元测试。

Add the following code to a new file called test_models.py in a new folder called “tests” within “django-puppy-store/puppy_store/puppies”:

将以下代码添加到“ django-puppy-store / puppy_store / puppies”内名为“ tests”的新文件夹中名为test_models.py的新文件中:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20

In the above test, we added dummy entries into our puppy table via the setUp() method from django.test.TestCase and asserted that the get_breed() method returned the correct string.

在上面的测试中,我们通过django.test.TestCasesetUp()方法将虚拟条目添加到了我们的小狗表中,并断言get_breed()方法返回了正确的字符串。

Add an __init__.py file to “tests” and remove the tests.py file from “django-puppy-store/puppy_store/puppies”.

将__init__.py文件添加到“测试”,然后从“ django-puppy-store / puppy_store / puppies”中删除tests.py文件。

Let’s run our first test:

让我们运行第一个测试:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8

Great! Our first unit test has passed!

大! 我们的第一个单元测试已经通过!

序列化器 (Serializers)

Before moving on to creating the actual API, let’s define a serializer for our Puppy model which validates the model querysets and produces Pythonic data types to work with.

移动到创建实际的API之前,让我们定义一个串行的这验证了我们的模型,模型小狗查询集并产生Python的数据类型与工作。

Add the following snippet to django-puppy-store/puppy_store/puppies/serializers.py:

将以下代码段添加到django-puppy-store / puppy_store / puppies / serializers.py:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8

In the above snippet we defined a ModelSerializer for our puppy model, validating all the mentioned fields. In short, if you have a one-to-one relationship between your API endpoints and your models – which you probably should if you’re creating a RESTful API – then you can use a ModelSerializer to create a Serializer.

在上面的代码段中,我们为小狗模型定义了ModelSerializer ,以验证所有提到的字段。 简而言之,如果您的API端点和模型之间存在一对一的关系(如果您正在创建RESTful API的话,则应该是一对一的关系),则可以使用ModelSerializer创建序列化器。

With our database in place, we can now start building the RESTful API…

有了数据库之后,我们现在就可以开始构建RESTful API了……

RESTful结构 (RESTful Structure)

In a RESTful API, endpoints (URLs) define the structure of the API and how end users access data from our application using the HTTP methods – GET, POST, PUT, DELETE. Endpoints should be logically organized around collections and elements, both of which are resources.

在RESTful API中,端点(URL)定义API的结构以及最终用户如何使用HTTP方法GET,POST,PUT,DELETE从我们的应用程序访问数据。 端点应在逻辑上围绕集合和元素进行组织,这两者都是资源。

In our case, we have one single resource, puppies, so we will use the following URLS – /puppies/ and /puppies/<id> for collections and elements, respectively:

在我们的例子中,我们只有一个资源puppies ,因此我们将使用以下URL- /puppies//puppies/<id>分别用于集合和元素:

CRUD routes

路线与测试(TDD) (Routes and Testing (TDD))

We will be taking a test-first approach rather than a thorough test-driven approach, wherein we will be going through the following process:

我们将采用测试优先的方法,而不是彻底的测试驱动的方法,其中,我们将经历以下过程:

  • add a unit test, just enough code to fail
  • then update the code to make it pass the test.
  • 添加一个单元测试,刚好失败的代码
  • 然后更新代码以使其通过测试。

Once the test passes, start over with the same process for the new test.

测试通过后,重新开始新测试的相同过程。

Begin by creating a new file, django-puppy-store/puppy_store/puppies/tests/test_views.py, to hold all the tests for our views and create a new test client for our app:

首先创建一个新文件django-puppy-store / puppy_store / puppies / tests / test_views.py,以保存我们视图的所有测试并为我们的应用程序创建一个新的测试客户端:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10

Before starting with all the API routes, let’s first create a skeleton of all view functions that return empty responses and map them with their appropriate URLs within the django-puppy-store/puppy_store/puppies/views.py file:

在开始所有API路由之前,让我们首先创建所有视图函数的框架,这些框架将返回空响应,并将它们与django-puppy-store / puppy_store / puppies / views.py文件中的相应URL进行映射:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24
25
25
26
26
27
27
28
28
29
29
30
30
31
31
32
32
33
33

Create the respective URLs to match the views in django-puppy-store/puppy_store/puppies/urls.py:

创建相应的URL以匹配django-puppy-store / puppy_store / puppies / urls.py中的视图:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16

Update django-puppy-store/puppy_store/puppy_store/urls.py as well:

同时更新django-puppy-store / puppy_store / puppy_store / urls.py:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11

可浏览的API (Browsable API)

With all routes now wired up with the view functions, let’s open up REST Framework’s Browsable API interface and verify whether all the URLs are working as expected.

现在将所有路由与视图功能连接起来,让我们打开REST Framework的Browsable API接口,并验证所有URL是否按预期工作。

First, fire up the development server:

首先,启动开发服务器:

1
1

Make sure to comment out all the attributes in REST_FRAMEWORK section of our settings.py file, to bypass login. Now visit http://localhost:8000/api/v1/puppies

确保注释掉settings.py文件的REST_FRAMEWORK部分中的所有属性,以绕过登录。 现在访问http://localhost:8000/api/v1/puppies

You will see an interactive HTML layout for the API response. Similarly we can test the other URLs and verify all URLs are working perfectly fine.

您将看到API响应的交互式HTML布局。 同样,我们可以测试其他URL并验证所有URL是否工作正常。

Let’s start with our unit tests for each route.

让我们从每个路线的单元测试开始。

路线 (Routes)

得到所有 (GET ALL)

Start with a test to verify the fetched records:

从测试开始以验证提取的记录:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21

Run the test. You should see the following error:

运行测试。 您应该看到以下错误:

1
1
2
2

Update the view to get the test to pass.

更新视图以使测试通过。

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10

Here, we get all the records for puppies and validate each using the PuppySerializer.

在这里,我们获得了所有小狗的记录,并使用PuppySerializer进行了PuppySerializer

Run the tests to ensure they all pass:

运行测试以确保它们全部通过:

1
1
2
2
3
3

取得单身 (GET Single)

Fetching a single puppy involves two test cases:

取回一只小狗涉及两个测试用例:

  1. Get valid puppy – e.g., the puppy exists
  2. Get invalid puppy – e.g., the puppy does not exists
  1. 获得有效的小狗-例如,小狗存在
  2. 取得无效的小狗-例如,小狗不存在

Add the tests:

添加测试:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24
25
25

Run the tests. You should see the following error:

运行测试。 您应该看到以下错误:

1
1
2
2

Update the view:

更新视图:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11

In the above snippet, we get the puppy using an ID. Run the tests to ensure they all pass.

在以上代码段中,我们使用ID获得了小狗。 运行测试以确保它们全部通过。

开机自检 (POST)

Inserting a new record involves two cases as well:

插入新记录还涉及两种情况:

  1. Inserting a valid puppy
  2. Inserting a invalid puppy
  1. 插入有效的小狗
  2. 插入无效的小狗

First, write tests for it:

首先,为其编写测试:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24
25
25
26
26
27
27
28
28
29
29
30
30
31
31
32
32
33
33

Run the tests. You should see two failures:

运行测试。 您应该看到两个失败:

1
1
2
2
3
3
4
4
5
5

Again, update the view to get the tests to pass:

再次,更新视图以使测试通过:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20

Here, we inserted a new record by serializing and validating the request data before inserting to the database.

在这里,我们在插入数据库之前通过序列化和验证请求数据来插入新记录。

Run the tests again to ensure they pass.

再次运行测试以确保它们通过。

You can also test this out with the Browsable API. Fire up the development server again, and navigate to http://localhost:8000/api/v1/puppies/. Then, within the POST form, submit the following as application/json:

您也可以使用Browsable API进行测试。 再次启动开发服务器,并导航到http:// localhost:8000 / api / v1 / puppies / 。 然后,在POST表单中,将以下内容提交为application/json

1
1
2
2
3
3
4
4
5
5
6
6

Be sure the GET ALL and Get Single work as well.

确保“全部获取”和“获取单个”也能正常工作。

(PUT)

Start with a test to update a record. Similar to adding a record, we again need to test for both valid and invalid updates:

从测试开始以更新记录。 与添加记录类似,我们再次需要测试有效和无效更新:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24
25
25
26
26
27
27
28
28
29
29
30
30
31
31
32
32
33
33
34
34
35
35
36
36

Run the tests.

运行测试。

1
1
2
2
3
3
4
4
5
5

Update the view:

更新视图:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23

In the above snippet, similar to an insert, we serialize and validate the request data and then respond appropriately.

在上面的代码段中,类似于插入代码,我们序列化并验证请求数据,然后进行适当响应。

Run the tests again to ensure that all the tests pass.

再次运行测试以确保所有测试均通过。

删除 (DELETE)

To delete a single record, an ID is required:

要删除一条记录,需要一个ID:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18

Run the tests. You should see:

运行测试。 您应该看到:

1
1
2
2

Update the view:

更新视图:

1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24

Run the tests again. Make sure all of them pass. Make sure to test out the UPDATE and DELETE functionality within the Browsable API as well!

再次运行测试。 确保它们全部通过。 请务必同时测试Browsable API中的UPDATE和DELETE功能!

结论和后续步骤 (Conclusion and Next Steps)

In this tutorial, we went through the process of creating a RESTful API using Django REST Framework with a test-first approach.

在本教程中,我们介绍了使用Django REST Framework和测试优先方法创建RESTful API的过程。

翻译自: https://www.pybloggers.com/2017/05/test-driven-development-of-a-django-restful-api/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值