PyCharm 2025.1 Help

使用 Django REST Framework 构建 API

启用 Django 插件

此功能依赖于 Django 插件,该插件默认情况下已捆绑并在 PyCharm 中启用。 如果相关功能不可用,请确保没有禁用该插件。

  1. 按 Ctrl+Alt+S 打开设置,然后选择 插件。

  2. 打开 已安装 选项卡,找到 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

设置项目

  1. 转到 文件 | 新建项目 ,或点击 新建项目 按钮位于 欢迎屏幕。 新建项目 对话框打开。

  2. 在 新建项目 对话框中,执行以下操作:

    • 指定项目类型为 Django。

    • 在 位置 字段中,提供项目位置的路径,并将项目名称设置为 api_tutorial_rental。

    • 选择项目的虚拟环境类型(我们将使用 项目虚拟环境)。

    • 展开 更多设置 部分并提供应用程序名称(rental)。

    新建项目对话框
  3. 当您点击 创建 时,PyCharm 将设置项目并在项目环境中安装 Django。

    Django REST framework 包需要手动安装。 通过点击左侧的图标打开 Python 包 工具窗口。 搜索 djangorestframework 包并安装最新版本。

    安装 'djangorestframework'
  4. 现在我们需要在 settings.py 中更新 INSTALLED_APPS:

    • 打开 随处搜索 (双击 Shift)。 转到 符号 选项卡并输入所需符号(变量、类等)的首字母以查找它,例如“insapp”。

    • 按 Enter 跳转到所需符号,并将 ‘rest_framework’ 添加到 INSTALLED_APPS。

    将 ‘rest_framework’ 添加到 ‘INSTALLED_APPS’

创建序列化器

通常,序列化器用于将 Django 模型实例或查询集“翻译”成其他格式,通常是 JSON 或 XML,以便它们可以在 HTTP 响应的主体中发送。 序列化器还提供反序列化功能,当从 HTTP 请求中解析、验证并转换为模型实例的文本数据时使用。

序列化和反序列化过程对于任何 API 都至关重要,而 Django REST framework 可以完全接管这些过程。 借助其 ModelSerializer 类,我们可以仅用两行代码为任何模型生成一个序列化器。

编写基于模型的序列化器

  1. 使用 随处搜索 或 项目 工具窗口(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 字段提供了选项。

  2. 现在让我们运行迁移。 打开 PyCharm 的 manage.py 控制台(Ctrl+Alt+R )并执行以下命令:

    • makemigrations - 扫描您的模型以查找任何更改,并创建新的迁移文件以反映这些更改在数据库结构中的变化。

    • migrate - 将迁移文件应用到数据库,更新其架构以匹配模型的当前状态。

    运行迁移
  3. 现在我们需要在 租赁 目录中创建 serializers.py。 右键点击 项目 工具窗口中的目录(Alt+1 ),转到 新建 | Python 文件 ,并将文件名指定为“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']
    将代码添加到 'serializers.py'

    正如您所见, OfferSerializer 继承自 Django REST framework 提供的 ModelSerializer ,并且仅用两行代码定义。 在第 6 行,我们指定了基础模型(在第 2 行从 rental/models 导入),而第 7 行包含要序列化的模型字段列表。

使用序列化器保存数据

让我们使用序列化器将数据添加到数据库中。

  1. 通过点击左侧的相应图标打开 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()
    在 Python 控制台中使用序列化器

    我们创建了两个 Offer 模型实例,并使用内置的 save() 方法将它们保存到数据库中。

  2. 现在让我们打开数据库。 您的项目包含 db.sqlite3 ,可以通过 项目 工具窗口或使用 随处搜索 打开。 当您第一次打开数据库时,PyCharm 会将其注册为项目的数据源。 数据源与驱动程序 窗口将会打开。

    点击 测试连接。 如果您看到提示需要安装、更新或切换数据库驱动程序的警告,请执行所需操作。 然后点击 OK 完成将数据源添加到项目的操作。

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

    Rental_offer 表

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

    Rental_offer 数据库内容

    如您所见,现在数据库表中有两条记录。 我们没有为除 text 之外的任何字段提供值,因此使用了模型定义中的默认值。

提供 REST API 逻辑

编写基于函数的视图

现在我们希望 API 能够根据传入的请求自动添加租赁报价。

  1. 让我们开始在 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)
    'rental/views.py' 中的代码

    我们添加了一个名为 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 的错误信息。

  2. 如果我们能够获取任何特定报价的信息、编辑该信息以及从数据库中删除报价,那也会很有用。 让我们添加另一个视图并将其命名为 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)
    'rental/views.py' 中的代码

    此视图接受三种方法(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 端点

  1. 让我们从在应用程序目录中创建 urls.py 并填入以下代码开始:

    from django.urls import path from rental import views urlpatterns = [ path('offers/', views.offer_list), path('offers/<int:pk>/', views.offer_detail), ]

    我们为两个视图定义了两个端点。

  2. 将 rental/urls .py 包含到现有项目的 urls.py 文件中:

    from django.urls import path,include urlpatterns = [ path('', include('rental.urls')), ]
  3. 让我们打开 端点 工具窗口。 如果您之前没有使用过它,可以在左侧菜单中找到。

    打开端点工具窗口

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

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

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

    HTTP 客户端选项卡

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

    响应体保存到文件
  6. 让我们提交一个 DELETE 请求以删除第二个报价(DELETE http://localhost:8000/offers/2/ ),然后提交另一个请求以获取可用报价的列表(GET http://localhost:8000/offers/)。 现在只有一个报价可用。

    DELETE 后的响应体
  7. Django REST framework 的另一个功能是其可浏览的 API。 在浏览器中打开 http://localhost:8000/offers/ (如有需要,编辑端口号),您将进入一个页面,在该页面中可以查看可用报价列表并添加新报价。

    浏览器中的页面

实现通用基于类的视图

谈到 Django REST framework 的惊人功能时,不得不提到通用基于类的视图。

  1. 让我们使用它们重写 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

    现在每个视图只有三行代码! 您只需关注选择正确的通用类进行继承。

  2. 由于我们不再使用基于功能的视图,因此需要更新 rental/urls.py。

    urlpatterns = [ path('offers/', views.OfferList.as_view()), path('offers/<int:pk>/', views.OfferDetails.as_view()), ]
  3. 让我们尝试提交无效数据以查看 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 文件。

    400 错误请求响应
  4. 如您所见,报价未被添加,因为我们在 size 中指定了错误的值。 根据 Offer 模型,当卧室数量超过 3 时,我们应该使用 MBR。 让我们编辑请求并再次提交。

    请求响应

启用身份验证和权限

目前,任何知道端点地址的人都可以添加、编辑和删除报价。 在现实世界中,这种情况并不正常。 通常,您希望能够控制谁可以对您的 API 执行哪些操作。 这可以通过实现身份验证和权限来实现。

引入用户

  1. 首先,我们需要引入用户的概念。 让我们从向 Offer 模型添加 author 字段开始:

    author = models.ForeignKey('auth.User', related_name='offers', on_delete=models.CASCADE)

    此字段具有 ForeignKey 类型,这意味着它用于表示报价与创建它们的用户之间的关系。

  2. 由于我们更新了模型,因此需要重置数据库并重新创建其中的 rental_offer 表,现在包含 author 字段。 为此,请执行以下步骤:

    • 打开 manage.py 控制台(Ctrl+Alt+R ),并依次运行以下命令:

      > flush > migrate rental zero
    • 在 rental/migrations 目录中,删除所有迁移,仅保留 __init__.py。

    • 然后继续在 manage.py 控制台中操作:

      > makemigrations > migrate
  3. 为了确保您已准备好继续,请转到 数据库 工具窗口并打开 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']
    引入用户 'serializer.py'
  4. 我们还需要在 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
    引入用户 'views.py'
  5. 将以下用户端点添加到 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()), ]
    引入用户 'urls.py'

设置身份验证为必需

现在我们需要确保只有经过身份验证的用户才能通过 API 添加报价。

  1. 更新 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
    设置身份验证为必需 'views.py'
  2. 为了确保一切按预期工作,让我们运行一个 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 响应。

    尝试在没有身份验证的情况下发出请求
  3. 让我们创建用户。 转到 manage.py 控制台并运行 createsuperuser 命令。 记住您提供的用户名和密码。

  4. 在继续下一步之前,您需要一个 Base64 编码的字符串,该字符串由用户名和密码通过单个冒号连接而成。 例如,我们创建了用户名为 ‘admin’,密码为 ‘pass123’ 的用户(仅作为示例;在实际情况下,您应始终使用更强的密码)。 打开 Python 控制台并运行以下命令,将 ‘admin:pass123’ 替换为您的用户凭据:

    >>> import base64 >>> base64.b64encode(b'admin:pass123')
    创建管理员用户
  5. 现在让我们运行相同的请求,但带有 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 响应。

详细说明权限

目前,任何经过身份验证的用户都可以编辑任何报价。 让我们设置权限,使得报价只能由其作者编辑。

  1. 创建 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.user

    IsAuthorOrReadOnly 类是从 Django REST framework 的 BasePermission 类派生的。 如果请求方法是 SAFE_METHODS 中的一种(即 GET、 HEAD 和 OPTIONS ),则无条件授予权限。 否则,请求用户必须是报价的作者才能获得权限。

  2. 转到 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
    详细说明权限 'views.py'
  3. 现在通过在 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 ,响应详情中显示“您无权执行此操作”。

    尝试违反权限
  4. 然后尝试使用管理员的凭据执行相同操作:

    PUT http://localhost:8000/offers/1/ Authorization: Basic YWRtaW46cGFzczEyMw== Content-Type: application/json {"text":"A small modern flat. Very central location."}

    您应该会收到 200 OK。

  5. 让我们检查可浏览的 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')), ]
    详细说明权限 'urls.py'

    现在在浏览器中更新页面。 您应该会在右上角看到 登录。 点击它并输入之前创建的用户之一的凭据,以便能够对报价执行操作。

结论

通过完成本教程,您已经学会了实现 Django REST framework 的以下功能:

  • 用于基于模型创建序列化器的 ModelSerializer。

  • 用于以简洁且符合惯用方式编写 API 逻辑的通用基于类的视图。

  • 用于轻松可视化可用端点和数据的可浏览 API。

  • 用于配置用户权限的 Django 身份验证系统。

最后修改日期: 2025年 4月 23日