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

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

现在需要在 settings.py 中更新
INSTALLED_APPS:打开 随处搜索 (连按两次 Shift)。 转到 符号 选项卡,键入目标符号(变量、类等)的首字母来查找它,例如,“insapp”。
按 Enter 跳转到所需符号,并将
‘rest_framework’添加到INSTALLED_APPS。

创建序列化器
一般而言,序列化器用于将 Django 模型实例或查询集“转换”为其他格式,通常是 JSON 或 XML,以便将其发送到 HTTP 响应的正文中。 序列化器还提供反序列化功能:对来自 HTTP 请求的文本数据进行解析、验证,并将其转换为模型实例。
序列化与反序列化过程对任何 API 都至关重要,Django REST 框架可以完全接管这项工作。 借助其 ModelSerializer 类,我们只需两行代码即可为任意模型生成序列化器。
编写基于模型的序列化器
使用 随处搜索 或 项目 工具窗口(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- 将迁移文件应用到数据库,更新其架构,使其与模型的当前状态匹配。

现在需要在 rental 目录中创建 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 框架提供的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 ,可从 项目 工具窗口打开,或使用 随处搜索 打开。 首次打开数据库时,PyCharm 会将其注册为项目数据源。 将打开 数据源和驱动程序 窗口。
点击 测试连接。 如果看到需要安装、更新或切换数据库驱动程序的警告,请执行相应操作。 然后点击 确定 ,完成将数据源添加到项目。

打开 数据库 工具窗口后,展开 db 数据源的结构,直到看到 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 框架中用于基于函数的视图的装饰器。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),其工作方式如下:首先,它会检查在
pk参数中指定 ID 的房源是否存在于数据库中(第 23 行)。 如果不存在,则返回404 Not Found。对于
GET请求,API 会序列化该房源的数据(第 28 行),并在响应正文中返回。对于
PUT请求,API 会序列化数据库中的房源数据,并与请求正文中的数据合并(第 32 行)。 如果验证成功(第 33 行),则将更新后的房源保存到数据库(第 34 行),并在响应正文中返回(第 35 行)。 否则,将返回错误信息,并附带400 Bad Request状态。最后,对于
DELETE请求,API 会删除该房源并返回204 No Content。
现在我们已定义 API 的逻辑,只剩最后一步即可使用我们的 API。 我们需要定义 Django URL,也称为 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 框架的另一项功能是其可浏览 API。 在浏览器中打开 http://localhost:8000/offers/ (如有需要,请编辑端口号)会转到一个页面,您可以在该页面查看可用房源列表并添加新房源。

实现通用类视图
当谈到 Django REST 框架的精彩功能时,不得不提通用类视图。
让我们使用它们重写 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 执行哪些操作。 这可以通过实现身份验证与权限来实现。
引入用户
首先,我们需要引入用户的概念。 首先,将
author字段添加到Offer模型: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 框架的BasePermission类。 如果请求方法属于SAFE_METHODS之一(即GET、HEAD和OPTIONS),则无条件授予权限。 否则,请求用户必须是该房源的作者才能获得权限。转到 views.py ,导入新创建的权限,并在
OfferDetails中更新permission_classes: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,且响应详细信息中包含 “您无权执行此操作”。
然后使用 admin 的凭据重试相同的操作:
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 框架的以下功能:
用于基于模型创建序列化器的
ModelSerializer。通用类视图,以简洁且惯用的方式编写 API 逻辑。
可浏览 API,便于可视化可用端点和数据。
Django 身份验证系统,用于配置用户权限。