使用 Django REST Framework 构建 API
启用 Django 插件
此功能依赖于 Django 插件,该插件默认情况下已捆绑并在 PyCharm 中启用。 如果相关功能不可用,请确保您未禁用该插件。
按下 Ctrl+Alt+S 打开设置,然后选择 。
打开 已安装 选项卡,找到 Django 插件,并选中插件名称旁边的复选框。
在本教程中,我们将使用 Django REST framework 创建一个租赁平台 API。
在开始之前
确保满足以下前提条件:
您使用的是 PyCharm 2023.3 或更高版本。 如果您尚未拥有 PyCharm,请从 此页面下载。 要安装 PyCharm,请根据您的平台遵循相关说明。
对 RESTful API 概念的基本理解。
具备 Python 和 Django 的使用经验(您可以从 Django 教程 开始)。
本教程基于以下假设创建:
Python 3.11
Django 5.1
Django REST framework 3.15.2
设置项目
转到 ,或点击 新项目 按钮位于 欢迎屏幕。 新项目 对话框打开。
在 新建项目 对话框中,执行以下操作:
指定项目类型为 Django。
在 位置 字段中,提供项目位置的路径,并将项目名称设置为 api_tutorial_rental。
选择项目的虚拟环境类型(我们将使用 项目虚拟环境)。
展开 更多设置 部分并提供应用程序名称(rental)。

当您点击 创建 时,PyCharm 将设置项目并在项目环境中安装 Django。
Django REST framework 包需要手动安装。 通过点击左侧的图标打开 Python 包 工具窗口。 搜索 djangorestframework 包并安装最新版本。

现在我们需要在 settings.py 中更新
INSTALLED_APPS:打开 Search Everywhere (双击 Shift)。 转到 符号 选项卡并输入所需符号(变量、类等)的首字母以查找它,例如“insapp”。
按 Enter 跳转到所需符号,并将
‘rest_framework’添加到INSTALLED_APPS。

创建序列化器
通常,序列化器用于将 Django 模型实例或查询集“翻译”成其他格式,通常是 JSON 或 XML,以便它们可以在 HTTP 响应的主体中发送。 序列化器还提供反序列化功能,当从 HTTP 请求中解析、验证并转换为模型实例的文本数据时使用。
序列化和反序列化过程对于任何 API 都至关重要,而 Django REST framework 可以完全接管这些过程。 借助其 ModelSerializer 类,我们可以仅用两行代码为任何模型生成一个序列化器。
编写基于模型的序列化器
使用 Search Everywhere 或 项目 工具窗口(Alt+1 )打开 rental/models.py ,并将以下代码复制到编辑器中:
from django.db import models SIZE_CHOICES = [ ('ST', 'Studio'), ('1BR', '1 bedroom'), ('2BR', '2 bedrooms'), ('3BR', '3 bedrooms'), ('MBR', '3+ bedrooms'), ] TYPE_CHOICES = [ ('H', 'house'), ('APT', 'apartment'), ] class Offer(models.Model): created = models.DateTimeField(auto_now_add=True) address = models.CharField(max_length=100, blank=True, default='') size = models.CharField(choices=SIZE_CHOICES, default='1BR', max_length=100) type = models.CharField(choices=TYPE_CHOICES, default='APT', max_length=100) price = models.PositiveIntegerField(default=0) sharing = models.BooleanField(default=False) text = models.TextField(default='') class Meta: ordering = ['created']请注意,
Offer模型的所有字段都有默认值,这意味着我们可以在不提供任何字段值的情况下创建一个实例。 此外,我们为size和type字段提供了选项。现在让我们运行迁移。 打开 PyCharm 的 manage.py 控制台(Ctrl+Alt+R )并执行以下命令:
makemigrations- 扫描您的模型以查找任何更改,并创建新的迁移文件以反映这些更改在数据库结构中的变化。migrate- 将迁移文件应用到数据库,更新其架构以匹配模型的当前状态。

现在我们需要在 租赁 目录中创建 serializers.py。 右键点击 项目 工具窗口中的目录(Alt+1 ),转到 ,并将文件名指定为“serializers”。

新创建的文件将在编辑器中打开。 用以下代码填充它:
from rest_framework import serializers from rental.models import Offer class OfferSerializer(serializers.ModelSerializer): class Meta: model = Offer fields = ['id', 'address', 'size', 'type', 'price', 'sharing', 'text']
正如您所见,
OfferSerializer继承自 Django REST framework 提供的ModelSerializer,并且仅用两行代码定义。 在第 6 行,我们指定了基础模型(在第 2 行从 rental/models 导入),而第 7 行包含要序列化的模型字段列表。
使用序列化器保存数据
让我们使用序列化器将数据添加到数据库中。
通过点击左侧的相应图标打开 Python 控制台,并在其中运行以下代码:
from rental.models import Offer offer = Offer(text='A cozy space in "loft" style.\nPerfect for young couples') offer.save() offer = Offer(text='A warm house for a big family') offer.save()
我们创建了两个
Offer模型实例,并使用内置的save()方法将它们保存到数据库中。现在让我们打开数据库。 您的项目包含 db.sqlite3 ,可以通过 项目 工具窗口或使用 Search Everywhere 打开。 当您第一次打开数据库时,PyCharm 会将其注册为项目的数据源。 数据源和驱动程序 窗口将会打开。
点击 测试连接。 如果您看到提示需要安装、更新或切换数据库驱动程序的警告,请执行所需操作。 然后点击 确定 完成将数据源添加到项目的操作。

当 数据库 工具窗口打开时,展开 数据库 数据源的结构,直到看到 rental_offer 表。

点击它以在编辑器中浏览其内容。

如您所见,现在数据库表中有两条记录。 我们没有为除
text之外的任何字段提供值,因此使用了模型定义中的默认值。
提供 REST API 逻辑
编写基于函数的视图
现在我们希望 API 能够根据传入的请求自动添加租赁报价。
让我们开始在 rental/views.py 中创建 API 的逻辑。 打开文件并填入以下代码:
from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response from rental.models import Offer from rental.serializers import OfferSerializer @api_view(['GET', 'POST']) def offer_list(request): if request.method == 'GET': offers = Offer.objects.all() serializer = OfferSerializer(offers, many=True) return Response(serializer.data) elif request.method == 'POST': serializer = OfferSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
我们添加了一个名为
offer_list的基于函数的视图。 它将用于提供可用租赁报价的信息,以及向数据库添加新报价。 以下是其内容:@api_view(第 7 行)是 Django REST framework 的基于函数视图的装饰器。GET和POST是此视图接受的方法。如果请求方法是
GET,则会创建一个包含数据库中所有报价的查询集(第 10 行)并进行序列化(第 11 行)。 在这种情况下,响应的主体包含关于所有可用报价的 JSON 格式数据。 响应以默认状态码(200 OK)发送。如果请求方法是
POST,则使用OfferSerializer从请求中反序列化数据(第 14 行)。 如果数据验证成功(第 15 行),它将被保存到数据库中(第 16 行)。 响应包含保存的数据,并具有状态码201 Created(第 17 行)。如果验证失败,API 将返回带有状态
400 Bad Request的错误信息。
如果我们能够获取任何特定报价的信息、编辑该信息以及从数据库中删除报价,那也会很有用。 让我们添加另一个视图并将其命名为
offer_detail:@api_view(['GET', 'PUT', 'DELETE']) def offer_detail(request, pk): try: offer = Offer.objects.get(pk=pk) except Offer.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) if request.method == 'GET': serializer = OfferSerializer(offer) return Response(serializer.data) elif request.method == 'PUT': serializer = OfferSerializer(offer, data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) elif request.method == 'DELETE': offer.delete() return Response(status=status.HTTP_204_NO_CONTENT)
此视图接受三种方法(
GET、PUT和DELETE),其工作原理如下:首先,它会检查数据库中是否存在 ID 在
pk参数中指定的报价(第 23 行)。 如果不存在,则返回404 Not Found。对于
GET请求,API 会序列化报价数据(第 28 行)并在响应主体中返回。对于
PUT请求,API 会将数据库中的报价数据与请求主体中的数据合并后进行序列化(第 32 行)。 如果验证成功(第 33 行),更新后的报价将保存到数据库中(第 34 行),并在响应主体中返回(第 35 行)。 否则,错误信息将以400 Bad Request状态返回。最后,对于
DELETE请求,API 会删除该报价并返回204 No Content。
现在我们已经定义了 API 的逻辑,只剩下最后一步就可以使用我们的 API 了。 我们需要定义 Django URLs,也称为 API 端点。
定义和测试 API 端点
让我们从在应用程序目录中创建 urls.py 并填入以下代码开始:
from django.urls import path from rental import views urlpatterns = [ path('offers/', views.offer_list), path('offers/<int:pk>/', views.offer_detail), ]我们为两个视图定义了两个端点。
将 rental/urls .py 包含到现有项目的 urls.py 文件中:
from django.urls import path,include urlpatterns = [ path('', include('rental.urls')), ]让我们打开 端点 工具窗口。 如果您之前没有使用过它,可以在左侧菜单中找到。

工具窗口显示所有可用的端点和方法。

在测试 API 之前,请确保 Django 服务器正在运行。 在项目创建时,PyCharm 会自动设置运行配置。 只需从窗口标题中的 运行 小部件启动它。 请注意在打开的 运行 工具窗口中显示的服务器地址(通常是 localhost)和端口号。

让我们回到 端点 工具窗口。 在列表中选择 /offers/ ,并切换到底部的 HTTP 客户端 选项卡。 如有需要,编辑端口号,然后点击 提交请求。

PyCharm 运行请求并将响应体保存到文件中。 您可以向上滚动以查看响应,或者点击链接在编辑器中打开文件。

让我们提交一个
DELETE请求以删除第二个报价(DELETE http://localhost:8000/offers/2/),然后提交另一个请求以获取可用报价的列表(GET http://localhost:8000/offers/)。 现在只有一个报价可用。
Django REST framework 的另一个功能是其可浏览的 API。 在浏览器中打开 http://localhost:8000/offers/ (如有需要,编辑端口号),您将进入一个页面,在该页面中可以查看可用报价列表并添加新报价。

实现通用基于类的视图
谈到 Django REST framework 的惊人功能时,不得不提到通用基于类的视图。
让我们使用它们重写 rental/views.py 中的代码:
from rest_framework import generics from rental.models import Offer from rental.serializers import OfferSerializer class OfferList(generics.ListCreateAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer class OfferDetails(generics.RetrieveUpdateDestroyAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer现在每个视图只有三行代码! 您只需关注选择正确的通用类进行继承。
由于我们不再使用基于功能的视图,因此需要更新 rental/urls.py。
urlpatterns = [ path('offers/', views.OfferList.as_view()), path('offers/<int:pk>/', views.OfferDetails.as_view()), ]让我们尝试提交无效数据以查看 API 验证的工作方式。
转到 端点 工具窗口。 现在有额外的
OPTIONS和PATCH方法,这些方法来自通用视图。 从端点列表中选择 /offers/ ,然后点击 在编辑器中打开。 PyCharm 创建了一个 .http 文件并将端点复制到其中。 以 JSON 格式提供请求体并提交请求。POST http://localhost:8000/offers/ Content-Type: application/json { "address": "", "size": "8BR", "type": "H", "price": 1000000, "sharing": true, "text": "A spacious villa for a large family." }
在打开的 服务 工具窗口中,您会注意到响应的状态为
400 Bad Request。 点击链接以打开包含响应的 JSON 文件。
如您所见,报价未被添加,因为我们在
size中指定了错误的值。 根据Offer模型,当卧室数量超过 3 时,我们应该使用MBR。 让我们编辑请求并再次提交。
启用身份验证和权限
目前,任何知道端点地址的人都可以添加、编辑和删除报价。 在现实世界中,这种情况并不正常。 通常,您希望能够控制谁可以对您的 API 执行哪些操作。 这可以通过实现身份验证和权限来实现。
引入用户
首先,我们需要引入用户的概念。 让我们从向
Offer模型添加author字段开始:author = models.ForeignKey('auth.User', related_name='offers', on_delete=models.CASCADE)此字段具有
ForeignKey类型,这意味着它用于表示报价与创建它们的用户之间的关系。由于我们更新了模型,因此需要重置数据库并重新创建其中的 rental_offer 表,现在包含
author字段。 为此,请执行以下步骤:打开 manage.py 控制台(Ctrl+Alt+R ),并依次运行以下命令:
> flush > migrate rental zero在 rental/migrations 目录中,删除所有迁移,仅保留 __init__.py。
然后继续在 manage.py 控制台中操作:
> makemigrations > migrate
为了确保您已准备好继续,请转到 数据库 工具窗口并打开 rental_offer 表。 它应该有 author_id 列。
然后打开 rental/serializers.py 并添加
UserSerializer。 我们将使用 Django 的内置身份验证系统,因此我们将导入现有的User模型,并更新OfferSerializer以符合新添加的author字段:from rest_framework import serializers from rental.models import Offer from django.contrib.auth.models import User class OfferSerializer(serializers.ModelSerializer): author = serializers.ReadOnlyField(source='author.username') class Meta: model = Offer fields = ['id', 'address', 'size', 'type', 'price', 'sharing', 'text', 'author'] class UserSerializer(serializers.ModelSerializer): offers = serializers.PrimaryKeyRelatedField(many=True, queryset=Offer.objects.all()) class Meta: model = User fields = ['id', 'username', 'offers']
我们还需要在 rental/views.py 中定义两个新视图:一个用于管理所有用户的列表,另一个用于用户详细信息。 这里也应该导入
User模型,并且不要忘记从 serializers.py 导入新创建的UserSerializer。 此外,更新OfferList类以覆盖默认的perform_create()方法,以便在创建报价时传递额外的author字段。from rest_framework import generics from rental.models import Offer from rental.serializers import OfferSerializer, UserSerializer from django.contrib.auth.models import User class OfferList(generics.ListCreateAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer def perform_create(self, serializer): serializer.save(author=self.request.user) class OfferDetails(generics.RetrieveUpdateDestroyAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer class UserList(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer class UserDetails(generics.RetrieveAPIView): queryset = User.objects.all() serializer_class = UserSerializer
将以下用户端点添加到 rental/urls.py:
from django.urls import path from rental import views urlpatterns = [ path('offers/', views.OfferList.as_view()), path('offers/<int:pk>/', views.OfferDetails.as_view()), path('users/', views.UserList.as_view()), path('users/<int:pk>/', views.UserDetails.as_view()), ]
设置身份验证为必需
现在我们需要确保只有经过身份验证的用户才能通过 API 添加报价。
更新
OfferList和OfferDetails视图的以下属性以设置权限。 经过身份验证的用户将能够添加和编辑报价,而其他人将只能查看它们:from rest_framework import generics from rental.models import Offer from rental.serializers import OfferSerializer, UserSerializer from django.contrib.auth.models import User from rest_framework import permissions class OfferList(generics.ListCreateAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def perform_create(self, serializer): serializer.save(author=self.request.user) class OfferDetails(generics.RetrieveUpdateDestroyAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] class UserList(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer class UserDetails(generics.RetrieveAPIView): queryset = User.objects.all() serializer_class = UserSerializer
为了确保一切按预期工作,让我们运行一个
POST请求,而不进行身份验证:POST http://localhost:8000/offers/ Content-Type: application/json { "address": "", "size": "1BR", "type": "APT", "price": 350000, "sharing": false, "text": "A small modern flat. Central location." }您应该会收到一个
403 Forbidden响应。
让我们创建用户。 转到 manage.py 控制台并运行
createsuperuser命令。 记住您提供的用户名和密码。在继续下一步之前,您需要一个 Base64 编码的字符串,该字符串由用户名和密码通过单个冒号连接而成。 例如,我们创建了用户名为 ‘admin’,密码为 ‘pass123’ 的用户(仅作为示例;在实际情况下,您应始终使用更强的密码)。 打开 Python 控制台并运行以下命令,将 ‘admin:pass123’ 替换为您的用户凭据:
>>> import base64 >>> base64.b64encode(b'admin:pass123')
现在让我们运行相同的请求,但带有
Authorization标头。POST http://localhost:8000/offers/ Authorization: Basic YWRtaW46cGFzczEyMw== Content-Type: application/json { "address": "", "size": "1BR", "type": "APT", "price": 350000, "sharing": false, "text": "A small modern flat. Central location." }您应该会收到一个
201 Created响应。
详细说明权限
目前,任何经过身份验证的用户都可以编辑任何报价。 让我们设置权限,使得报价只能由其作者编辑。
创建 rental/permissions.py 并填入以下代码:
from rest_framework import permissions class IsAuthorOrReadOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): return request.method in permissions.SAFE_METHODS or obj.author == request.userIsAuthorOrReadOnly类是从 Django REST framework 的BasePermission类派生的。 如果请求方法是SAFE_METHODS中的一种(即GET、HEAD和OPTIONS),则无条件授予权限。 否则,请求用户必须是报价的作者才能获得权限。转到 views.py ,导入新创建的权限,并更新
permission_classes中的OfferDetails:from rest_framework import generics from rental.models import Offer from rental.serializers import OfferSerializer, UserSerializer from django.contrib.auth.models import User from rest_framework import permissions from rental.permissions import IsAuthorOrReadOnly class OfferList(generics.ListCreateAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def perform_create(self, serializer): serializer.save(author=self.request.user) class OfferDetails(generics.RetrieveUpdateDestroyAPIView): queryset = Offer.objects.all() serializer_class = OfferSerializer permission_classes = [ permissions.IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly ] class UserList(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer class UserDetails(generics.RetrieveAPIView): queryset = User.objects.all() serializer_class = UserSerializer
现在通过在 manage.py 控制台中运行
createsuperuser创建另一个用户(我们将使用 ‘jetbrains:jet123’)。 然后提交以下请求以更新 ID 为 1 的报价(由admin用户创建):PUT http://localhost:8000/offers/1/ Authorization: Basic amV0YnJhaW5zOmpldDEyMw== Content-Type: application/json {"text":"A small modern flat. Very central location."}您应该会收到
403 Forbidden,响应详情中显示“您无权执行此操作”。
然后尝试使用管理员的凭据执行相同操作:
PUT http://localhost:8000/offers/1/ Authorization: Basic YWRtaW46cGFzczEyMw== Content-Type: application/json {"text":"A small modern flat. Very central location."}您应该会收到
200 OK。让我们检查可浏览的 API 中是否存在身份验证。 在浏览器中打开 http://localhost:8000/offers/1/ (如有需要,编辑端口号)。 与
POST方法相关的表单不再存在,DELETE按钮也消失了。 我们需要启用登录页面,以便能够在可浏览的 API 中执行此类操作。转到项目的 urls.py 并按如下方式更新:
from django.urls import path, include urlpatterns = [ path('', include('rental.urls')), path('api-auth/', include('rest_framework.urls')), ]
现在在浏览器中更新页面。 您应该会在右上角看到 登录。 点击它并输入之前创建的用户之一的凭据,以便能够对报价执行操作。
结论
通过完成本教程,您已经学会了实现 Django REST framework 的以下功能:
用于基于模型创建序列化器的
ModelSerializer。用于以简洁且符合惯用方式编写 API 逻辑的通用基于类的视图。
用于轻松可视化可用端点和数据的可浏览 API。
用于配置用户权限的 Django 身份验证系统。