Django REST Framework (DRF) 入门教程:快速构建 API – wiki基地

“`markdown

Django REST Framework (DRF) 入门教程:快速构建 API

Django REST Framework (DRF) 是一个强大而灵活的工具包,用于构建 Web API。它基于 Django,提供了序列化、身份验证、权限控制、限流、版本控制等众多功能,极大地简化了 API 开发过程。本文将带你一步步从零开始,使用 DRF 快速构建一个功能完备的 API。

1. 准备工作

在开始之前,确保你已经安装了以下软件:

  • Python: Python 3.7 或更高版本是 DRF 的推荐版本。
  • pip: Python 的包管理工具。
  • Django: Django 框架本身。

如果你还没有安装 Django,可以使用以下命令安装:

bash
pip install django

2. 创建 Django 项目和应用

首先,创建一个新的 Django 项目:

bash
django-admin startproject tutorial
cd tutorial

然后,创建一个 Django 应用,例如 “snippets”,用于存放我们的 API 代码:

bash
python manage.py startapp snippets

3. 安装 Django REST Framework

使用 pip 安装 DRF:

bash
pip install djangorestframework

4. 配置 Django 项目

tutorial/settings.py 文件中进行以下配置:

  • 'rest_framework' 添加到 INSTALLED_APPS 中。

python
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # 添加 DRF
'snippets', # 添加 snippets 应用
]

5. 定义模型 (Model)

snippets/models.py 中定义一个简单的 Snippet 模型,用于存储代码片段:

“`python
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])

class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default=”)
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default=’python’, max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default=’friendly’, max_length=100)

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()

class Meta:
    ordering = ['created']

def __str__(self):
    return self.title or "Snippet {}".format(self.id)

“`

这个模型包含以下字段:

  • created: 创建时间,自动添加。
  • title: 代码片段的标题。
  • code: 代码片段的内容。
  • linenos: 是否显示行号。
  • language: 编程语言。
  • style: 代码高亮样式。
  • owner: 代码片段的拥有者,使用 Django 的 User 模型。
  • highlighted: 代码片段的 HTML 高亮版本。

执行数据库迁移:

bash
python manage.py makemigrations snippets
python manage.py migrate

6. 创建序列化器 (Serializer)

序列化器负责将模型实例转换为 JSON 等数据格式,并将 JSON 数据转换为模型实例。在 snippets/serializers.py 中创建 SnippetSerializer

“`python
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
from django.contrib.auth.models import User

class SnippetSerializer(serializers.HyperlinkedModelSerializer): # 使用 HyperlinkedModelSerializer,包含 URL 链接
owner = serializers.ReadOnlyField(source=’owner.username’)
highlight = serializers.HyperlinkedIdentityField(view_name=’snippet-highlight’, format=’html’)

class Meta:
    model = Snippet
    fields = ['url', 'id', 'highlight', 'owner',
              'title', 'code', 'linenos', 'language', 'style']

class UserSerializer(serializers.HyperlinkedModelSerializer):
snippets = serializers.HyperlinkedRelatedField(many=True, view_name=’snippet-detail’, read_only=True)

class Meta:
    model = User
    fields = ['url', 'id', 'username', 'snippets']

“`

  • SnippetSerializer 用于序列化 Snippet 模型。
  • UserSerializer 用于序列化 User 模型。
  • HyperlinkedModelSerializer 创建包含 URL 链接的序列化数据,更符合 RESTful API 的规范。
  • ReadOnlyField 表示只读字段,owner 字段从 owner.username 获取数据。
  • HyperlinkedIdentityField 创建一个指向特定视图的 URL 链接,这里用于高亮显示代码。
  • HyperlinkedRelatedField 创建一个指向相关模型的 URL 链接,这里用于显示用户的所有代码片段。

7. 创建视图 (View)

视图处理 HTTP 请求,并返回响应。DRF 提供了多种视图类,简化了 API 开发。我们使用 ModelViewSetAPIView 来创建视图。在 snippets/views.py 中添加以下代码:

“`python
from rest_framework import generics, permissions, renderers, viewsets
from django.contrib.auth.models import User
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
from snippets.permissions import IsOwnerOrReadOnly

@api_view([‘GET’])
def api_root(request, format=None):
return Response({
‘users’: reverse(‘user-list’, request=request, format=format),
‘snippets’: reverse(‘snippet-list’, request=request, format=format)
})

class SnippetViewSet(viewsets.ModelViewSet): # 使用 ModelViewSet
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly]

@action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
def highlight(self, request, *args, **kwargs):
    snippet = self.get_object()
    return Response(snippet.highlighted)

def perform_create(self, serializer):
    serializer.save(owner=self.request.user)

class UserViewSet(viewsets.ReadOnlyModelViewSet): # 使用 ReadOnlyModelViewSet
queryset = User.objects.all()
serializer_class = UserSerializer
“`

  • @api_view 装饰器用于创建基于函数的 API 视图,这里用于根 API 视图。
  • reverse 函数用于生成 URL,便于 API 之间的导航。
  • SnippetViewSet 使用 ModelViewSet,它提供了所有 CRUD 操作的默认实现,包括创建、读取、更新和删除。
  • UserViewSet 使用 ReadOnlyModelViewSet,只提供读取操作。
  • permission_classes 指定了访问权限,IsAuthenticatedOrReadOnly 表示只有认证用户才能创建、更新和删除代码片段,其他用户只能读取。
  • IsOwnerOrReadOnly 是一个自定义权限,只有代码片段的拥有者才能更新和删除它。
  • @action 装饰器创建一个自定义行为 highlight,用于高亮显示代码。
  • perform_create 方法用于在创建代码片段时,自动设置 owner 字段为当前用户。

8. 创建自定义权限 (Permission)

创建一个自定义权限,确保只有代码片段的拥有者才能更新和删除它。在 snippets/permissions.py 中添加以下代码:

“`python
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
“””
自定义权限,只允许代码片段的拥有者编辑。
“””

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

    # 只有代码片段的拥有者才允许写操作。
    return obj.owner == request.user

“`

9. 配置 URL 路由

snippets/urls.py 中配置 URL 路由:

“`python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views

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

router = DefaultRouter()
router.register(r’snippets’, views.SnippetViewSet)
router.register(r’users’, views.UserViewSet)

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

urlpatterns = [
path(”, include(router.urls)),
path(‘api-auth/’, include(‘rest_framework.urls’, namespace=’rest_framework’)), # 添加登录认证支持
path(”, views.api_root),
]
“`

  • DefaultRouter 会自动生成 API 的 URL 路由。
  • router.register 用于注册视图集。
  • rest_framework.urls 提供了登录认证支持。

tutorial/urls.py 中包含 snippets 应用的 URL:

“`python
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path(‘admin/’, admin.site.urls),
path(”, include(‘snippets.urls’)), # 包含 snippets 应用的 URL
]
“`

10. 添加代码高亮

snippets/models.py 中添加 save 方法,用于生成代码片段的 HTML 高亮版本:

“`python
from django.db import models
from pygments.lexers import get_all_lexers, get_lexer_by_name
from pygments.styles import get_all_styles
from pygments import highlight
from pygments.formatters.html import HtmlFormatter

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])

class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default=”)
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default=’python’, max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default=’friendly’, max_length=100)

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()

class Meta:
    ordering = ['created']

def __str__(self):
    return self.title or "Snippet {}".format(self.id)

def save(self, *args, **kwargs):
    """
    使用 pygments 库创建一个 HTML 高亮版本的代码片段。
    """
    lexer = get_lexer_by_name(self.language)
    linenos = 'table' if self.linenos else False
    options = {'title': self.title} if self.title else {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                              full=True, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super().save(*args, **kwargs)

“`

11. 创建超级用户

创建一个超级用户,用于登录管理界面:

bash
python manage.py createsuperuser

12. 运行开发服务器

启动 Django 开发服务器:

bash
python manage.py runserver

13. 测试 API

现在,你可以使用浏览器或 API 客户端(例如 Postman)测试 API。

  • 访问 http://127.0.0.1:8000/ 查看根 API 视图。
  • 访问 http://127.0.0.1:8000/snippets/ 查看代码片段列表。
  • 访问 http://127.0.0.1:8000/users/ 查看用户列表。
  • 访问 http://127.0.0.1:8000/admin/ 登录管理界面,管理代码片段和用户。

14. 添加 API 认证

DRF 提供了多种认证方式,包括基本认证、Session 认证、OAuth 认证等。这里我们使用 Session 认证,它与 Django 的用户认证系统集成在一起。

首先,确保你在 snippets/urls.py 中包含了 rest_framework.urls

python
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # 添加登录认证支持
path('', views.api_root),
]

现在,访问 API 时,DRF 会自动添加登录表单,让你进行认证。

15. 添加 Browsable API

DRF 提供了 Browsable API,它是一个交互式的 API 浏览器,方便开发者测试和调试 API。 它默认启用,无需额外配置。 访问API端点时,如果请求的 Accept 头包含 text/html (例如,通过浏览器访问), DRF 将返回 Browsable API 界面,而不是 JSON 数据。

总结

本文详细介绍了如何使用 Django REST Framework 快速构建 API。我们从创建 Django 项目和应用开始,然后安装 DRF、定义模型、创建序列化器、创建视图、配置 URL 路由、添加代码高亮和 API 认证。通过这个教程,你应该能够掌握 DRF 的基本概念和使用方法,并能够构建自己的 API。

进阶学习

  • 自定义序列化器: 学习如何创建自定义序列化器,处理更复杂的数据结构和业务逻辑。
  • 自定义视图: 学习如何创建自定义视图,实现更高级的 API 功能。
  • 使用不同的认证方式: 了解 DRF 提供的各种认证方式,并选择适合你的场景的认证方式。
  • 使用版本控制: 学习如何使用 DRF 的版本控制功能,管理 API 的不同版本。
  • 使用测试框架: 学习如何使用 DRF 的测试框架,编写单元测试和集成测试,保证 API 的质量。

DRF 是一个功能强大的框架,掌握它可以极大地提高 API 开发效率。希望本文能帮助你入门 DRF,并在实际项目中灵活运用。
“`

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部