写点什么

Django API 开发:一个 Todo 应用的后端

作者:宇宙之一粟
  • 2022 年 6 月 04 日
  • 本文字数:7228 字

    阅读完需:约 24 分钟

Django API 开发:一个 Todo 应用的后端

引言

在接下来的两章中,我们将构建一个 Todo API 后端,然后将其与 React 前端连接。 我们已经制作了第一个 API,并回顾了 HTTP 和 REST 的抽象工作原理,但是您仍然可能还没有“完全”了解它们如何结合在一起。 在这两章的最后,您将学到。


由于我们要制作专用的后端和前端,因此我们会将代码分成相似的结构。 在现有代码目录中,我们将创建一个 todo 目录,其中包含我们的后端 Django Python 代码和我们的前端 React JavaScript 代码。


最终的布局将如下所示。


todo|  ├──frontend|      ├──React... |  ├──backend|      ├──Django...
复制代码


本章重点介绍后端,而第 4 章介绍前端。

初始化创建

任何 Django API 的第一步始终是安装 Django,然后在其之上添加 Django REST Framework。 首先在桌面上的代码目录中创建一个专用的 todo 目录。


打开一个新的命令行控制台,然后输入以下命令:


$ cd ~/Desktop$ cd code$ mkdir todo && cd todo
复制代码


注意: 确保已从上一章中停用了虚拟环境。 您可以通过键入退出来执行此操作。 命令行前面是否没有括号? 好。 那么您就不在现有的虚拟环境中。


在此 todo 文件夹中将是我们的后端和前端目录。 让我们创建一个后端文件夹,安装 Django,然后激活一个新的虚拟环境。


$ mkdir backend && cd backend $ pipenv install django==2.2.6 $ pipenv shell
复制代码


您应该在命令行上看到括号,以确认虚拟环境(后端)已激活。


现在已经安装了 Django,我们应该首先创建一个传统的 Django 项目 todo_project,在其中添加第一个应用程序 todo,然后迁移初始数据库。


(backend) $ django-admin startproject todo_project . (backend) $ python manage.py startapp todos (backend) $ python manage.py migrate
复制代码


在 Django 中,我们始终需要将新应用添加到 INSTALLED_APPS 设置中,所以现在就这样做。 在文本编辑器中打开 todo_project/settings.py。 在文件底部,添加 todos.apps.TodosConfig


# todo_project/settings.pyINSTALLED_APPS = [     'django.contrib.admin',     'django.contrib.auth',     'django.contrib.contenttypes',    'django.contrib.sessions',     'django.contrib.messages',    'django.contrib.staticfiles',      # Local    'todos.apps.TodosConfig', # new ]
复制代码


如果您现在在命令行上运行python manage.py runserver并导航至http://127.0.0.1:8000/,则可以看到我们的项目已成功安装。



准备开始吧!

Models

接下来是在 todos 应用程序中定义我们的 Todo 数据库模型。 我们将保持基本状态,只有两个字段:title 和 body。


# todos/models.pyfrom django.db import models

class Todo(models.Model): title = models.CharField(max_length=200) body = models.TextField() def __str__(self): return self.title
复制代码


我们在顶部导入模型,然后将其子类化以创建自己的 Todo 模型。 我们还添加了__str__方法,以为每个将来的模型实例提供易于理解的名称。


由于我们已经更新了模型,现在该是 Django 进行两步操作的时候了:制作一个新的迁移文件,然后每次将数据库与更改同步。 在命令行上,键入 Control + c 以停止我们的本地服务器。 然后运行以下两个命令:


(backend) $ python manage.py makemigrations todos (backend) $ python manage.py migrate
复制代码


可以选择添加我们要为其创建迁移文件的特定应用程序(我们可以只键入python manage.py makemigrations),但这是采用的最佳做法。 迁移文件是调试应用程序的一种绝妙方法,您应该努力为每个小的更改创建一个迁移文件。 如果我们在两个不同的应用程序中更新了模型,然后运行python manage.py makemigrations,则生成的单个迁移文件将包含两个应用程序中的数据。 这只会增加调试难度。 尝试使您的迁移尽可能小。


现在,我们可以使用内置的 Django 管理应用程序与我们的数据库进行交互。 如果我们立即进入管理员,我们的 Todos 应用程序将不会出现。 我们需要通过 todos / admin.py 文件显式添加它,如下所示。


# todos/admin.pyfrom django.contrib import admin
from .models import Todo
admin.site.register(Todo)
复制代码


而已! 现在,我们可以创建一个超级用户帐户来登录管理员。


(backend) $ python manage.py createsuperuser
复制代码


然后再次启动本地服务器:


(backend) $ python manage.py runserver
复制代码


现在,如果您浏览至http://127.0.0.1:8000/admin/,则可以登录。



单击 Todos 旁边的“ +Add”,并创建 3 个新的待办事项,并确保为两者添加标题和正文。 这是我的样子:



至此,我们实际上已经完成了 Todo API 的传统 Django 部分。 由于我们不必为该项目建立网页,因此不需要网站 URL,视图或模板。 我们需要的只是一个模型,而 Django REST Framework 将负责其余的工作。

Dajngo REST 框架

停止本地服务器 Control + c,然后通过 pipenv 安装 Django REST Framework。


(backend) $ pipenv install djangorestframework==3.10.3
复制代码


然后像其他任何第三方应用程序一样,将 rest_framework 添加到我们的 INSTALLED_APPS 设置中。 我们还希望开始配置所有 REST_FRAMEWORK 下存在的 Django REST Framework 特定设置。 首先,我们将权限明确设置为 AllowAny。 此行位于文件的底部。


# todo_project/settings.pyINSTALLED_APPS = [    'django.contrib.admin',     'django.contrib.auth',     'django.contrib.contenttypes',    'django.contrib.sessions',     'django.contrib.messages',    'django.contrib.staticfiles',
# 3rd party 'rest_framework', # new # Local 'todos.apps.TodosConfig', ]
# newREST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ]}
复制代码


Django REST Framework 包含冗长的隐式设置默认设置列表。 您可以在此处查看完整列表。 AllowAny 是其中之一,这意味着当我们像上面所做的那样显式设置它时,其效果与没有设置 DEFAULT_PERMISSION_CLASSES 的配置完全相同。


学习默认设置需要花费一些时间。 在本书学习过程中,我们将对其中的一些熟悉。 要记住的主要内容是,隐式默认设置的设计旨在使开发人员可以进入并开始在本地开发环境中快速工作。 但是,默认设置不适用于生产。 因此,通常我们会在项目过程中对它们进行一些更改。


好的,这样就安装了 Django REST Framework。 接下来是什么?与上一章中我们同时构建网页和 API 的 Library 项目不同,在这里我们仅构建 API。 因此,我们不需要创建任何模板文件或传统的 Django 视图。


相反,我们将更新三个特定于 Django REST 框架的文件,以将数据库模型转换为 Web API:urls.py,views.py 和 serializers.py。

URLs

我喜欢先从 URL 开始,因为它们是我们 API 端点的入口点。 就像在传统的 Django 项目中一样,urls.py 文件使我们可以配置路由。


从 Django 项目级文件 todo_project / urls.py 开始。 我们在第二行导入 include,并在 api /为我们的 todos 应用添加一条路线。


# todo_project/urls.pyfrom django.contrib import adminfrom django.urls import include, path  # new
urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('todos.urls')), # new]
复制代码


接下来,创建我们的应用程序级别的 todos / urls.py 文件。


(backend) $ touch todos/urls.py
复制代码


并使用以下代码对其进行更新。


# todos/urls.pyfrom django.urls import pathfrom .views import ListTodo, DetailTodo
urlpatterns = [ path('<int:pk>/', DetailTodo.as_view()), path('', ListTodo.as_view()),]
复制代码


请注意,我们引用的还有两个尚未创建的视图:ListTodo 和 DetailTodo。 但是,路由现已完成。 api/有所有待办事项的列表位于空字符串 '',即。 每个待办事项都将在其主键上可用,这是 Django 在每个数据库表中自动设置的值。 第一个条目是 1,第二个条目是 2,依此类推。 因此,我们的第一个待办事项最终将位于 API 端点api/1/

Serializers

让我们回顾一下到目前为止。 我们从一个传统的 Django 项目和应用程序开始,我们创建了数据库模型并添加了数据。 然后,我们安装了 Django REST Framework 并配置了 URL。 现在,我们需要将模型中的数据转换为将在 URL 输出的 JSON。 因此,我们需要一个序列化器。


Django REST Framework 附带了一个强大的内置序列化程序类,我们可以使用少量代码快速扩展它们。 这就是我们在这里要做的。


首先在 todos 应用中创建一个新的 serializers.py 文件。


(backend) $ touch todos/serializers.py
复制代码


然后更新代码,如下所示:


# todos/serializers.pyfrom rest_framework import serializers from .models import Todo

class TodoSerializer(serializers.ModelSerializer): class Meta: model = Todo fields = ('id', 'title', 'body',)
复制代码


在顶部,我们从 Django REST Framework 以及我们的 models.py 文件导入了序列化器。 接下来,我们创建一个类 TodoSerializer。 这里的格式与我们在 Django 本身中创建模型类或表单的方式非常相似。 我们正在指定要使用的模型以及我们要公开的特定字段。 请记住,id 是 Django 自动创建的,因此我们不必在 Todo 模型中定义它,但是我们将在细节视图中使用它。


就是这样。 Django REST Framework 现在将神奇地将我们的数据转换为 JSON,从而公开来自 Todo 模型的 id,title 和 body 字段。


我们需要做的最后一件事是配置我们的 views.py 文件。

Views

在传统的 Django 中,视图用于自定义要发送到模板的数据。 在 Django REST Framework 中,视图执行相同的操作,但对序列化的数据而言。


Django REST Framework 视图的语法故意与常规 Django 视图非常相似,就像常规 Django 一样,Django REST Framework 随附了通用视图以用于常见用例。 这就是我们在这里使用的。


更新 todos / views.py 文件,如下所示:


# todos/views.pyfrom rest_framework import generics
from .models import Todofrom .serializers import TodoSerializer

class ListTodo(generics.ListAPIView): queryset = Todo.objects.all() serializer_class = TodoSerializer
class DetailTodo(generics.RetrieveAPIView): queryset = Todo.objects.all() serializer_class = TodoSerializer
复制代码


在顶部,我们导入 Django REST Framework 的泛型视图以及我们的 models.py 和 serializers.py 文件。


从我们的 todos / urls.py 文件中调用,我们有两条路线,因此有两个不同的视图。 我们将使用 ListAPIView 显示所有待办事项,并使用 RetrieveAPIView 显示单个模型实例。


精明的读者会注意到这里的代码有些冗余。 即使扩展的通用视图有所不同,我们实质上还是为每个视图重复使用 queryset 和 serializer_class。 在本书的后面,我们将学习有关解决此问题的视图集和路由器,并允许我们使用更少的代码来创建相同的 API 视图和 URL。


但是现在我们完成了! 我们的 API 已准备就绪,可以使用。 如您所见,Django REST Framework 和 Django 之间的唯一真正区别是,使用 Django REST Framework,我们需要添加 serializers.py 文件,而无需模板文件。 否则,urls.py 和 views.py 文件的行为类似。

Consuming the API

传统上使用 API 是一个挑战。 对于给定的 HTTP 响应或请求的正文和标头中包含的所有信息,根本没有很好的可视化效果。


取而代之的是,大多数开发人员使用命令行 HTTP 客户端(例如 cURL)(如上一章所述)或 HTTPie。


2012 年,第三方软件产品 Postman 投放市场,现在全球有数百万希望通过可视化,功能丰富的方式与 API 交互的开发人员使用。


但是 Django REST 框架最令人惊奇的事情之一是,它附带了功能强大的可浏览 API,我们可以立即使用它。 如果您发现需要使用 API 进行更多自定义,则可以使用 Postman 之类的工具。 但是通常内置的可浏览 API 绰绰有余。

Browsable API

现在让我们使用可浏览的 API 与我们的数据进行交互。 确保本地服务器正在运行。


(backend) $ python manage.py runserver
复制代码


然后导航到http://127.0.0.1:8000/api/以查看我们的工作 API 列表视图端点。



该页面显示了我们先前在数据库模型中创建的三个待办事项。 API 终结点称为集合,因为它显示多个项目。


我们的可浏览 API 可以做很多事情。 首先,让我们看一下原始的 JSON 视图,即实际通过互联网传输的视图。 单击右上角的“ GET”按钮,然后选择 JSON。



如果您返回http://127.0.0.1:8000/api/的列表视图页面,我们可以看到其他信息。 回想一下,HTTP 动词 GET 用于读取数据,而 POST 用于更新或创建数据。


在“列表待办事项”下显示 GET / api /,它告诉我们我们在此端点上执行了 GET。 下方显示的是 HTTP 200 OK,这是我们的状态代码,一切正常。 最重要的是,它下面显示允许:GET,HEAD,OPTIONS。 请注意,由于这是一个只读端点,因此不包括 POST,我们只能执行 GET。


我们还为每个模型制作了一个 DetailTodo 视图。 这称为实例,在http://127.0.0.1:8000/api/1/上可见。



您也可以导航至以下端点:


  • http://127.0.0.1:8000/api/2

  • http://127.0.0.1:8000/api/3

CORS

我们需要做的最后一步是跨源资源共享(CORS)。 每当客户端与不同域(mysite.com 与 yoursite.com)或端口(localhost:3000 与 localhost:8000)上托管的 API 进行交互时,都会存在潜在的安全问题。


具体来说,CORS 要求服务器包含特定的 HTTP 标头,以允许客户端确定是否以及何时应允许跨域请求。


我们的 Django API 后端将与专用前端通信,该前端位于用于本地开发的不同端口上,并在部署后位于另一个域上。


处理此问题的最简单方法(以及 Django REST 框架建议的一种方法)是使用中间件,该中间件将根据我们的设置自动包括适当的 HTTP 标头。


我们将使用的软件包是 django-cors-header,可以轻松将其添加到我们现有的项目中。


首先使用 Control + c 退出我们的服务器,然后使用 Pipenv 安装 django-cors-headers。


(backend) $ pipenv install django-cors-headers==3.1.1
复制代码


接下来,在三个位置更新我们的 settings.py 文件:


  • corsheaders添加到 INSTALLED_APPS

  • 在 MIDDLEWARE 中把 CorsMiddleware 添加到 CommonMiddleWare 的上方

  • 创建一个 CORS_ORIGIN_WHITELIST


# todo_project/settings.pyINSTALLED_APPS = [     'django.contrib.admin',     'django.contrib.auth',     'django.contrib.contenttypes',    'django.contrib.sessions',     'django.contrib.messages',     'django.contrib.staticfiles',      # 3rd party    'rest_framework',     'corsheaders', # new    # Local    'todos.apps.TodosConfig', ]
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', # new 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',]
# newCORS_ORIGIN_WHITELIST = ( 'http://localhost:3000', 'http://localhost:8000',)
复制代码


将 corsheaders.middleware.CorsMiddleware 出现在正确的位置非常重要。 由于中间件是从上到下加载的,因此它位于 MIDDLEWARE 设置中的 django.middleware.common.CommonMiddleware 之上。 另外请注意,我们已将两个域列入白名单:localhost:3000 和 localhost:8000。 前者是 React 的默认端口,下一章将在前端使用它。 后者是默认的 Django 端口。

测试

您应该始终为 Django 项目编写测试。 前期花费的少量时间将为您节省大量的时间和以后的调试错误。 让我们添加两个基本测试,以确认标题和正文内容的行为符合预期。


打开 todos / tests.py 文件,并添加以下内容:


# todos/tests.pyfrom django.test import TestCase from .models import Todo

class TodoModelTest(TestCase): @classmethod def setUpTestData(cls): Todo.objects.create(title='first todo', body='a body here')
def test_title_content(self): todo = Todo.objects.get(id=1) expected_object_name = f'{todo.title}' self.assertEquals(expected_object_name, 'first todo') def test_body_content(self): todo = Todo.objects.get(id=1) expected_object_name = f'{todo.body}' self.assertEquals(expected_object_name, 'a body here')
复制代码


它使用 Django 的内置 TestCase 类。 首先,我们在 setUpTestData 中设置数据,然后编写两个新测试。 然后使用 python manage.py test 命令运行测试。


(backend) $ python manage.py test ...Ran 2 tests in 0.002s

OK
复制代码


就是这样! 我们的后端现已完成。 确保服务器正在运行,因为我们将在下一章中使用它。


(backend) $ python manage.py runserver
复制代码

总结

只需最少的代码,Django REST Framework 便允许我们从头开始创建 Django API。 我们从传统 Django 需要的唯一组件是 models.py 文件和 urls.py 路由。 views.py 和 serializers.py 文件完全是 Django REST Framework 特有的。


与上一示例不同,我们没有为该项目构建任何网页,因为我们的目标只是创建一个 API。 但是,在将来的任何时候,我们都可以轻松实现! 只需添加一个新视图,URL 和一个模板即可公开我们现有的数据库模型。


在此示例中,重要的一点是我们添加了 CORS 标头,并且仅将域 localhost:3000 和 localhost:8000 明确设置为可以访问我们的 API。 第一次开始构建 API 时,很容易混淆正确设置 CORS 标头。


我们可以做更多的配置,以后再做,但最终,创建 Django API 的过程是建立模型,编写一些 URL 路由,然后添加 Django REST Framework 的序列化程序和视图所提供的一些魔术。


在下一章中,我们将构建一个 React 前端并将其连接到我们的 Todo API 后端。

发布于: 刚刚阅读数: 4
用户头像

宇宙古今无有穷期,一生不过须臾,当思奋争 2020.05.07 加入

🏆InfoQ写作平台-第二季签约作者 🏆 混迹于江湖,江湖却没有我的影子 热爱技术,专注于后端全栈,轻易不换岗 拒绝内卷,工作于软件工程师,弹性不加班 热衷分享,执着于阅读写作,佛系不水文

评论

发布
暂无评论
Django API 开发:一个 Todo 应用的后端_6月月更_宇宙之一粟_InfoQ写作社区