Django REST Framework (DRF) 教程:从零开始构建RESTful API – wiki词典

My apologies. It appears I do not have the capability to write files to your file system using the available tools. I misinterpreted my capabilities based on the prompt’s instructions.

However, I have successfully generated the article content. I will provide it to you directly in this response:


Django REST Framework (DRF) 教程:从零开始构建RESTful API

引言

在现代Web开发中,构建高效、可扩展且易于维护的API是至关重要的。Django REST Framework (DRF) 是一个强大而灵活的工具包,它基于Django框架,使开发者能够快速构建RESTful Web API。DRF以其出色的序列化、视图抽象、认证和权限管理等功能而闻名,极大地简化了API开发流程。

本教程将引导你从零开始,一步步构建一个简单的RESTful API。我们将涵盖项目设置、数据模型定义、序列化器、视图、URL配置、认证与权限,并讨论一些最佳实践。

环境准备

首先,我们需要设置开发环境并安装必要的依赖。

  1. 创建项目目录和虚拟环境

    “`bash
    mkdir myapi_project
    cd myapi_project
    python -m venv venv

    Linux/macOS

    source venv/bin/activate

    Windows

    venv\Scripts\activate
    “`

  2. 安装 Django 和 Django REST Framework

    bash
    pip install Django djangorestframework

  3. 创建 Django 项目和应用

    bash
    django-admin startproject myapi .
    python manage.py startapp todo

    这里我们创建了一个名为 myapi 的项目和一个名为 todo 的应用,用于管理待办事项。

  4. 配置 settings.py
    打开 myapi/settings.py 文件,将 rest_framework 和你的应用 todo 添加到 INSTALLED_APPS 中。

    “`python

    myapi/settings.py

    INSTALLED_APPS = [
    # … 其他 Django 应用
    ‘rest_framework’,
    ‘todo’, # 你的应用
    ]

    可选:配置 DRF 的全局设置,例如默认认证和权限类

    REST_FRAMEWORK = {
    ‘DEFAULT_AUTHENTICATION_CLASSES’: [
    ‘rest_framework.authentication.SessionAuthentication’,
    ‘rest_framework.authentication.TokenAuthentication’,
    ],
    ‘DEFAULT_PERMISSION_CLASSES’: [
    ‘rest_framework.permissions.IsAuthenticatedOrReadOnly’,
    ],
    ‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
    ‘PAGE_SIZE’: 10,
    }
    ``IsAuthenticatedOrReadOnly权限表示未经认证的用户只能读取数据,而认证用户可以读写。TokenAuthentication需要额外安装djoser` 或手动生成Token,这里我们先配置,后面会用到。

  5. 数据库迁移

    bash
    python manage.py migrate

  6. 创建超级用户 (可选,但推荐)
    为了能够访问 Django Admin 和进行测试,创建一个超级用户。

    bash
    python manage.py createsuperuser

定义数据模型 (Models)

todo/models.py 中定义我们的待办事项模型。

“`python

todo/models.py

from django.db import models
from django.contrib.auth.models import User

class Todo(models.Model):
title = models.CharField(max_length=100, verbose_name=”标题”)
description = models.TextField(blank=True, null=True, verbose_name=”描述”)
completed = models.BooleanField(default=False, verbose_name=”是否完成”)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=”创建时间”)
updated_at = models.DateTimeField(auto_now=True, verbose_name=”更新时间”)
owner = models.ForeignKey(User, related_name=’todos’, on_delete=models.CASCADE, verbose_name=”所有者”)

class Meta:
    ordering = ['created_at']
    verbose_name = "待办事项"
    verbose_name_plural = "待办事项"

def __str__(self):
    return self.title

“`

完成模型定义后,进行数据库迁移:

bash
python manage.py makemigrations todo
python manage.py migrate

序列化器 (Serializers)

序列化器负责将Django模型实例(或其他复杂数据类型)转换为可轻松渲染成JSON、XML等格式的Python数据类型,反之亦然。DRF提供了 ModelSerializer,可以自动从Django模型生成序列化器。

todo 应用目录下创建 serializers.py 文件:

“`python

todo/serializers.py

from rest_framework import serializers
from .models import Todo

class TodoSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source=’owner.username’) # 显示所有者的用户名

class Meta:
    model = Todo
    fields = ['id', 'title', 'description', 'completed', 'created_at', 'updated_at', 'owner']
    read_only_fields = ['created_at', 'updated_at'] # 这些字段在创建和更新时不可写

``
这里,
owner = serializers.ReadOnlyField(source=’owner.username’)会将owner字段显示为用户名,并且是只读的。read_only_fields确保created_atupdated_at` 字段只由服务器自动管理。

视图 (Views)

视图负责处理API请求并返回响应。DRF提供了多种视图类型,从低级的 APIView 到高级的 ModelViewSetModelViewSet 是处理CRUD(创建、读取、更新、删除)操作的最便捷方式,因为它会自动提供所有这些操作。

todo/views.py 中添加视图:

“`python

todo/views.py

from rest_framework import viewsets
from rest_framework import permissions
from .models import Todo
from .serializers import TodoSerializer
from .permissions import IsOwnerOrReadOnly # 我们稍后会创建这个权限类

class TodoViewSet(viewsets.ModelViewSet):
“””
这个视图集提供了 list, create, retrieve, update, partial_updatedestroy 操作。
“””
queryset = Todo.objects.all()
serializer_class = TodoSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]

def perform_create(self, serializer):
    """
    在创建Todo实例时,将其所有者设置为当前请求的用户。
    """
    serializer.save(owner=self.request.user)

def get_queryset(self):
    """
    只允许用户查看和编辑他们自己的待办事项,管理员可以查看所有。
    """
    if self.request.user.is_superuser:
        return Todo.objects.all()
    return self.request.user.todos.all()

``
我们在这里使用了
ModelViewSetperform_create方法确保当用户创建一个Todo时,该Todo会自动关联到当前认证的用户。get_queryset` 方法则实现了用户只能看到和修改自己的Todo项的逻辑。

权限 (Permissions)

为了实现用户只能修改自己的待办事项,我们需要创建一个自定义权限类。
todo 应用目录下创建 permissions.py 文件:

“`python

todo/permissions.py

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
“””
自定义权限,只允许对象的所有者编辑它。
“””

def has_object_permission(self, request, view, obj):
    # 允许任何请求读取权限,所以 GET, HEAD 或 OPTIONS 请求总是被允许。
    if request.method in permissions.SAFE_METHODS:
        return True

    # 写入权限只授予对象的所有者。
    return obj.owner == request.user

``
这个权限类
IsOwnerOrReadOnly确保了只有Todo项的owner` 才能进行修改或删除操作,而其他用户(包括未认证用户)只能查看。

URL配置 (URL Configuration)

现在我们需要将视图映射到URL。DRF的 Router 可以非常方便地为 ViewSet 生成URL。

  1. todo 应用中创建 urls.py

    “`python

    todo/urls.py

    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    from . import views

    创建一个路由器并注册我们的视图集

    router = DefaultRouter()
    router.register(r’todos’, views.TodoViewSet, basename=’todo’)

    API URL现在由路由器自动确定。

    urlpatterns = [
    path(”, include(router.urls)),
    ]
    “`

  2. 将应用URL包含到项目URL中
    打开 myapi/urls.py 文件,将 todo 应用的URL包含进来,并添加DRF的登录/登出URL(用于可浏览API)。

    “`python

    myapi/urls.py

    from django.contrib import admin
    from django.urls import path, include

    urlpatterns = [
    path(‘admin/’, admin.site.urls),
    path(‘api/’, include(‘todo.urls’)), # 包含 todo 应用的 API URL
    path(‘api-auth/’, include(‘rest_framework.urls’)), # 用于可浏览API的登录/登出
    ]
    “`

运行服务器并测试

现在,我们已经完成了API的基本构建。运行开发服务器:

bash
python manage.py runserver

打开浏览器,访问 http://127.0.0.1:8000/api/todos/。你会看到DRF提供的可浏览API界面。

  • 创建待办事项:
    如果你没有登录,你只能看到空的列表。登录后(通过右上角的 “Login” 或在 /admin/ 创建用户并登录),你就可以在表单中创建新的待办事项。由于我们设置了 owner=self.request.user,新创建的Todo会自动关联到你登录的用户。

  • 查看和编辑:
    你可以点击单个Todo项的URL(例如 http://127.0.0.1:8000/api/todos/1/)来查看、更新或删除它。如果你尝试修改一个不属于你的Todo项,你会收到 403 Forbidden 错误,因为 IsOwnerOrReadOnly 权限生效了。

认证与权限深入

settings.py 中,我们配置了 SessionAuthenticationTokenAuthentication

  • SessionAuthentication: 这是Django默认的认证方式,适用于基于Web会话的认证(例如,通过浏览器访问可浏览API)。
  • TokenAuthentication: 适用于无状态的API客户端(例如移动应用或SPA)。要使用它,你需要为用户生成一个Token。

安装 djangorestframework-simplejwt 来实现JWT认证 (更推荐用于现代API):

bash
pip install djangorestframework-simplejwt

然后更新 settings.py:

“`python

myapi/settings.py

INSTALLED_APPS = [
# …
‘rest_framework.authtoken’, # 如果使用TokenAuthentication
‘rest_framework_simplejwt’, # 如果使用simplejwt
]

REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.SessionAuthentication’,
# ‘rest_framework.authentication.TokenAuthentication’, # 如果使用DRF自带的Token
‘rest_framework_simplejwt.authentication.JWTAuthentication’, # 如果使用simplejwt
],
‘DEFAULT_PERMISSION_CLASSES’: [
‘rest_framework.permissions.IsAuthenticatedOrReadOnly’,
],
# …
}

simplejwt配置

from datetime import timedelta

SIMPLE_JWT = {
‘ACCESS_TOKEN_LIFETIME’: timedelta(minutes=5),
‘REFRESH_TOKEN_LIFETIME’: timedelta(days=1),
‘ROTATE_REFRESH_TOKENS’: False,
‘BLACKLIST_AFTER_ROTATION’: True,
‘UPDATE_LAST_LOGIN’: False,

'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY, # 使用Django的SECRET_KEY
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,

'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

'JTI_CLAIM': 'jti',

'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),

}
“`

myapi/urls.py 中添加JWT认证的URL:

“`python

myapi/urls.py

from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)

urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘todo.urls’)),
path(‘api-auth/’, include(‘rest_framework.urls’)),

# JWT认证URL
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),

]
“`

现在你可以通过向 /api/token/ 发送用户名和密码来获取JWT Token,然后在请求头中使用 Authorization: Bearer <your_access_token> 进行认证。

更多高级特性和最佳实践

  • 分页 (Pagination): 在 settings.py 中已经配置了默认分页,你也可以在视图中自定义分页类。
  • 过滤 (Filtering): 使用 django-filter 库可以轻松为你的API添加过滤功能。
  • 搜索 (Search): DRF提供了 SearchFilter,可以用于简单的字段搜索。
  • 性能优化:
    • N+1查询问题: 在 get_queryset 中使用 select_relatedprefetch_related 来优化查询。
    • 缓存: 使用Django的缓存机制来减少数据库负载。
  • API文档: 使用 drf-yasgdrf-spectacular 等工具自动生成Swagger/OpenAPI文档。
  • 测试: 编写单元测试和集成测试,确保你的API按预期工作。DRF提供了 APITestCase 来方便地测试API。

总结

本教程从零开始,详细介绍了使用Django REST Framework构建一个RESTful API的全过程。我们涵盖了项目设置、数据模型、序列化器、视图、URL配置,以及认证和权限管理。DRF的强大功能和灵活性使其成为Python生态系统中最受欢迎的API构建工具之一。通过不断实践和探索其高级特性,你将能够构建出任何复杂度的健壮API。
希望这篇教程对你有所帮助!祝你在DRF的旅程中一切顺利!

滚动至顶部