做网站来钱快,微信营销平台,wordpress导航菜单制作,做标签这个网站刷单安全吗概述
本教程将介绍如何创建一个简单的粘贴板代码高亮 Web API。在此过程中#xff0c;它将介绍构成 REST 框架的各种组件#xff0c;让你全面了解所有组件是如何组合在一起的。
本教程相当深入#xff0c;因此在开始学习之前#xff0c;你可能需要先吃一块饼干#xff0…概述
本教程将介绍如何创建一个简单的粘贴板代码高亮 Web API。在此过程中它将介绍构成 REST 框架的各种组件让你全面了解所有组件是如何组合在一起的。
本教程相当深入因此在开始学习之前你可能需要先吃一块饼干再喝一杯你最喜欢的啤酒。如果你只想快速了解概况那就去看看快速入门文档吧。
注意本文代码基于入门教程的代码继续如果有不明白的地方建议先看入门教程的代码。
安装依赖
# 之前已经安装的
pip install django
pip install djangorestframework# 需要新安装的
pip install pygments创建新的应用
完成后我们就可以创建一个应用程序用来创建一个简单的 Web API。
python manage.py startapp snippets注册新的应用
INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.contrib.contenttypes,django.contrib.sessions,django.contrib.messages,django.contrib.staticfiles,quickstart,snippets,rest_framework,
]创建模型
在本教程中我们将首先创建一个用于存储代码片段的简单片段模型。继续编辑 snippets/models.py 文件。注良好的编程实践包括注释。虽然您可以在本教程代码的存储库版本中找到注释但我们在此省略了它们以专注于代码本身。
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_stylesLEXERS [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(verbose_name创建时间, auto_now_addTrue)title models.CharField(verbose_name标题, max_length100, blankTrue, default)code models.TextField(verbose_name代码)linenos models.BooleanField(verbose_name开启行号, defaultFalse)language models.CharField(verbose_name编程语言, choicesLANGUAGE_CHOICES, defaultpython, max_length100)style models.CharField(verbose_name代码样式, choicesSTYLE_CHOICES, defaultfriendly, max_length100)class Meta:# 根据创建时间升序ordering [created]我们还需要为片段模型创建初始迁移并首次同步数据库。
python manage.py makemigrations snippets
python manage.py migrate snippets创建序列化类
要开始使用 Web API我们首先需要提供一种将片段实例序列化和反序列化为 json 等表示形式的方法。我们可以通过声明与 Django 的表单非常相似的序列化器来实现这一点。在片段目录中创建一个名为 serializers.py 的文件并添加以下内容。
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICESclass SnippetSerializer(serializers.Serializer):代码片段序列化类# 主键id serializers.IntegerField(read_onlyTrue)# 标题title serializers.CharField(requiredFalse, allow_blankTrue, max_length100)# 代码code serializers.CharField(style{base_template: textarea.html})# 是否开启行号linenos serializers.BooleanField(requiredFalse)# 编程语言language serializers.ChoiceField(choicesLANGUAGE_CHOICES, defaultpython)# 代码样式style serializers.ChoiceField(choicesSTYLE_CHOICES, defaultfriendly)def create(self, validated_data):根据验证数据创建并返回一个新的 Snippet 实例。return Snippet.objects.create(**validated_data)def update(self, instance, validated_data):根据验证数据更新并返回现有的 Snippet 实例。instance.title validated_data.get(title, instance.title)instance.code validated_data.get(code, instance.code)instance.linenos validated_data.get(linenos, instance.linenos)instance.language validated_data.get(language, instance.language)instance.style validated_data.get(style, instance.style)instance.save()return instance序列化器类的第一部分定义了序列化/反序列化的字段。create() 和 update() 方法定义了在调用 serializer.save() 时如何创建或修改完整的实例。
序列化器类与 Django 表单类非常相似包括各种字段的类似验证标志如 required、max_length 和 default。
字段标志还可以控制序列化器在某些情况下的显示方式例如渲染为 HTML 时。上面的 {‘base_template’: ‘textarea.html’} 标志相当于在 Django 表单类上使用 widgetwidgets.Textarea。这对于控制如何显示可浏览 API 尤为有用我们将在本教程稍后部分看到这一点。
实际上我们还可以通过使用 ModelSerializer 类来节省时间稍后我们将看到这一点但现在我们将保持序列化器定义的明确性。
序列化类的用法
在进一步了解之前我们先熟悉一下如何使用新的序列化器类。让我们进入 Django shell。
python manage.py shell好了在我们完成一些导入后让我们创建几个代码片段来使用。
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParsersnippet Snippet(codefoo bar\n)
snippet.save()snippet Snippet(codeprint(hello, world)\n)
snippet.save()现在我们有了几个片段实例可以使用。让我们看看如何将其中一个实例序列化。
serializer SnippetSerializer(snippet)
serializer.data
# {id: 2, title: , code: print(hello, world)\n, linenos: False, language: python, style: friendly}至此我们已将模型实例转化为 Python 本地数据类型。为了最终完成序列化过程我们将数据渲染为 json。
content JSONRenderer().render(serializer.data)
content
# b{id: 2, title: , code: print(\\hello, world\\)\\n, linenos: false, language: python, style: friendly}反序列化与此类似。首先我们将数据流解析为 Python 原生数据类型…
import iostream io.BytesIO(content)
data JSONParser().parse(stream)…然后我们将这些本地数据类型还原成一个完全填充的对象实例。
serializer SnippetSerializer(datadata)
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([(title, ), (code, print(hello, world)\n), (linenos, False), (language, python), (style, friendly)])
serializer.save()
# Snippet: Snippet object请注意API 与使用表单是多么相似。当我们开始编写使用序列化器的视图时这种相似性会变得更加明显。
我们还可以序列化查询集而不是模型实例。为此我们只需在序列化器参数中添加 manyTrue 标志即可。
serializer SnippetSerializer(Snippet.objects.all(), manyTrue)
serializer.data
# [OrderedDict([(id, 1), (title, ), (code, foo bar\n), (linenos, False), (language, python), (style, friendly)]), OrderedDict([(id, 2), (title, ), (code, print(hello, world)\n), (linenos, False), (language, python), (style, friendly)]), OrderedDict([(id, 3), (title, ), (code, print(hello, world)), (linenos, False), (language, python), (style, friendly)])]使用模型序列化类
我们的 SnippetSerializer 类正在复制 Snippet 模型中包含的大量信息。如果我们能让代码更简洁一些就更好了。
就像 Django 提供表单类和 ModelForm 类一样REST 框架也包括序列化器类和模型序列化器类。
让我们看看如何使用 ModelSerializer 类重构序列化器。再次打开文件 snippets/serializers.py用以下代码替换 SnippetSerializer 类。
class SnippetSerializer(serializers.ModelSerializer):class Meta:model Snippetfields [id, title, code, linenos, language, style]序列化器有一个很好的特性那就是你可以通过打印序列化器实例的表示来检查它的所有字段。使用 python manage.py shell 打开 Django shell然后尝试以下操作
from snippets.serializers import SnippetSerializer
serializer SnippetSerializer()
print(repr(serializer))
# SnippetSerializer():
# id IntegerField(labelID, read_onlyTrue)
# title CharField(allow_blankTrue, max_length100, requiredFalse)
# code CharField(style{base_template: textarea.html})
# linenos BooleanField(requiredFalse)
# language ChoiceField(choices[(Clipper, FoxPro), (Cucumber, Gherkin), (RobotFramework, RobotFramework), (abap, ABAP), (ada, Ada)...
# style ChoiceField(choices[(autumn, autumn), (borland, borland), (bw, bw), (colorful, colorful)...请务必记住ModelSerializer 类并没有什么特别神奇的功能它们只是创建序列化类的快捷方式
自动确定的字段集。create() 和 update() 方法的简单默认实现。
完整代码如下
from rest_framework import serializers
from snippets.models import Snippetclass SnippetSerializer(serializers.ModelSerializer):class Meta:model Snippetfields [id, title, code, linenos, language, style]使用我们的序列化器编写常规 Django 视图
让我们看看如何使用新的 Serializer 类编写 API 视图。目前我们不会使用 REST 框架的任何其他功能我们只会把视图写成普通的 Django 视图。
编辑 snippets/views.py 文件添加以下内容。
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer我们 API 的根将是一个视图它支持列出所有现有片段或创建新片段。
csrf_exempt
def snippet_list(request):List all code snippets, or create a new snippet.if request.method GET:snippets Snippet.objects.all()serializer SnippetSerializer(snippets, manyTrue)return JsonResponse(serializer.data, safeFalse)elif request.method POST:data JSONParser().parse(request)serializer SnippetSerializer(datadata)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data, status201)return JsonResponse(serializer.errors, status400)请注意由于我们希望从没有 CSRF 标记的客户端向该视图进行 POST因此需要将视图标记为 csrf_exempt。这并不是你通常想要做的事情REST 框架视图实际上使用了比这更合理的行为但对于我们现在的目的来说这已经足够了。
我们还需要一个与单个片段相对应的视图用于检索、更新或删除片段。
csrf_exempt
def snippet_detail(request, pk):Retrieve, update or delete a code snippet.try:snippet Snippet.objects.get(pkpk)except Snippet.DoesNotExist:return HttpResponse(status404)if request.method GET:serializer SnippetSerializer(snippet)return JsonResponse(serializer.data)elif request.method PUT:data JSONParser().parse(request)serializer SnippetSerializer(snippet, datadata)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data)return JsonResponse(serializer.errors, status400)elif request.method DELETE:snippet.delete()return HttpResponse(status204)完整代码如下
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializercsrf_exempt
def snippet_list(request):列出所有代码片段或创建一个新片段。# 查询所有的代码if request.method GET:snippets Snippet.objects.all()serializer SnippetSerializer(snippets, manyTrue)return JsonResponse(serializer.data, safeFalse)# 新增代码elif request.method POST:data JSONParser().parse(request)serializer SnippetSerializer(datadata)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data, status201)return JsonResponse(serializer.errors, status400)csrf_exempt
def snippet_detail(request, pk):检索、更新或删除代码片段。try:snippet Snippet.objects.get(pkpk)except Snippet.DoesNotExist:return HttpResponse(status404)# 根据ID获取代码if request.method GET:serializer SnippetSerializer(snippet)return JsonResponse(serializer.data)# 根据ID更新代码elif request.method PUT:data JSONParser().parse(request)serializer SnippetSerializer(snippet, datadata)if serializer.is_valid():serializer.save()return JsonResponse(serializer.data)return JsonResponse(serializer.errors, status400)# 根据ID删除代码elif request.method DELETE:snippet.delete()return HttpResponse(status204)配置路由
最后我们需要将这些视图连接起来。创建 snippets/urls.py 文件
from django.urls import path
from snippets import viewsurlpatterns [path(, views.snippet_list),path(int:pk/, views.snippet_detail),
]我们还需要对 tutorial/urls.py 文件中的 urlconf 根目录进行布线以包含我们的片段应用程序的 URL。
from django.urls import include, path
from rest_framework import routersfrom quickstart import views# 创建子路由
router routers.DefaultRouter()
router.register(rusers, views.UserViewSet)
router.register(rgroups, views.GroupViewSet)# 使用自动 URL 路由为我们的应用程序接口布线。
# 此外我们还提供了可浏览 API 的登录 URL。
urlpatterns [path(, include(router.urls)),path(api-auth/, include(rest_framework.urls, namespacerest_framework)),path(snippets/, include(snippets.urls)),
]urlpatterns router.urls值得注意的是有几种边缘情况我们目前还没有处理好。如果我们发送了畸形的 json或者请求使用了视图无法处理的方法那么我们最终会收到 500 服务器错误 的响应。不过现在这样也可以。
测试我们的接口
新增代码片段
(venv) PS D:\tmp\drf_demo http http://127.0.0.1:8000/snippets/ codeabc
HTTP/1.1 201 Created
Content-Length: 98
Content-Type: application/json
Cross-Origin-Opener-Policy: same-origin
Date: Sun, 07 Jan 2024 04:30:19 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.12.0
X-Content-Type-Options: nosniff
X-Frame-Options: DENY{code: abc,id: 1,language: python,linenos: false,style: friendly,title:
}请求所有代码片段
(venv) PS D:\tmp\drf_demo http http://127.0.0.1:8000/snippets/
HTTP/1.1 200 OK
Content-Length: 100
Content-Type: application/json
Cross-Origin-Opener-Policy: same-origin
Date: Sun, 07 Jan 2024 04:30:35 GMT
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.12.0
X-Content-Type-Options: nosniff
X-Frame-Options: DENY[{code: abc,id: 1,language: python,linenos: false,style: friendly,title: }
](venv) PS D:\tmp\drf_demo总结
到目前为止我们做得还不错我们已经有了一个序列化 API感觉与 Django 的表单 API 和一些常规的 Django 视图非常相似。
目前我们的 API 视图除了提供 json 响应外并没有做什么特别的事情而且我们还想清理一些错误处理的边缘情况但这已经是一个正常运行的 Web API 了。
我们将在本教程的第二部分看看如何开始改进。