本笔记以 Django REST framework 官方教程为基础,使用截至目前(2021年12月)最新版本的 Python、Django 以及 Django REST framework,因此代码会略有不同。
官方教程地址
https://www.django-rest-framework.org/tutorial/1-serialization/
开发环境:
- Win10
- Windows Terminal
- Python 3.10.1
- Django 4.0
- djangorestframework 3.12.4
1. Serialization 序列化
1.1 创建虚拟环境并激活
为练习项目创建一个新的虚拟环境:
python3 -m venv test_env
激活虚拟环境:
./test_env/Scripts/Activate.ps1
在 test_env
中安装 Django、Django REST framework 和 pygments:
pip install django
pip install djangorestframework
pip install pygments
1.2 创建一个 Django 项目并在项目中创建一个 app
django-admin startproject rest_tutorial
cd .\rest_tutorial\
python manage.py startapp snippets
在 INSTALLED_APPS
中添加 snippets
和 rest_framework
:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'snippets.apps.SnippetsConfig'
]
1.3 创建模型
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()
line_numbers = 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)
class Meta:
ordering = ['created']
执行数据库迁移:
python manage.py makemigrations snippets
报错:Invalid template library specified. ImportError raised when trying to load 'rest_framework.templatetags.rest_framework': No module named 'pytz'
根据报错,安装 pytz
:
pip install pytz
再次执行迁移命令:
python manage.py makemigrations snippets
python manage.py migrate
1.4 创建序列化器
在 app snippets
的目录下,创建一个 serializers.py
文件
from rest_framework import serializers
from .models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'base_template': 'textarea.html'})
line_numbers = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
def create(self, validated_data):
# Create and return a new `Snippet` instance, given the validated data.
return Snippet.objects.create(**validated_data)
def update(self, instance, validated_data):
# Update and return an existing `Snippet` instance, given the validated data.
instance.title = validated_data.get('title', instance.title)
instance.code = validated_data.get('code', instance.code)
instance.line_numbers = validated_data.get('line_numbers', instance.line_numbers)
instance.language = validated_data.get('language', instance.language)
instance.style = validated_data.get('style', instance.style)
instance.save()
return instance
序列化器实例 SnippetSerializer
的前半部分定义了哪些字段需要进行序列化和反序列化;create()
和 update()
方法定义了在调用 serializer.save()
时如何创建和修改完整的 Snippet
实例。
序列化器类与 Django 表单类非常相似,并且在各个字段上包含类似的验证标志,例如 required
、max_length
和 default
。在某些情况下,字段标志还可以控制序列化的显示方式。上面的 {'base_template': 'textarea.html'}
标志相当于在 Django Form 类上使用 widget=widgets.Textarea
。
1.5 在 Django shell 中测试序列化器
启动 Django shell:
python manage.py shell
在 Django shell 中执行以下命令:
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
snippet = Snippet(code='foo = "bar"\n')
snippet.save()
snippet = Snippet(code='print("hello, world")\n')
snippet.save()
上述命令添加了两个 snippet
实例,下面使用 SnippetSerializer
来序列化 snippet
:
serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': '', 'code': 'print("hello, world")\n', 'line_numbers': False, 'language': 'python', 'style': 'friendly'}
content = JSONRenderer().render(serializer.data)
content
# b'{"id":2,"title":"","code":"print(\\"hello, world\\")\\n","line_numbers":false,"language":"python","style":"friendly"}'
要退出 Django shell ,可以执行以下命令:
quit()
1.6 使用 ModelSerializers
类重构序列化器
前面写的序列化器 SnippetSerializer
中很多内容跟 Snippet
模型都是重复的,下面使用 ModelSerializers
类对其进行重构: