введение
Что такое сериализаторы? Официальный веб-сайт выглядит так: «Сериализаторы позволяют преобразовывать сложные данные, такие как наборы запросов и экземпляры моделей, в собственные типы данных Python, которые затем можно легко преобразовать в JSON, XML или другие типы контента». Или в формате xml.
По последним исследованиям, по личному мнению, сериализаторы имеют следующие функции:
- Сериализировать набор запросов и экземпляр модели и т. д., преобразовать их в формат json и вернуть пользователю (интерфейс API).
- Проверка данных постинга и патча/помещения.
— Обработка пост- и патч-данных.
(В последующем контенте патч будет использоваться для обозначения патча/патча, блогер считает, что патч ближе к обновлению)
Короче говоря, для get роль сериализаторов отражена в первом пункте, но если это другие запросы, сериализаторы могут играть роль 2 или 3!
Эта статья относительно длинная, поэтому я кратко представлю основное содержание с картинкой.
serializers.fieild
Мы знаем, что в django форма также имеет много полей, и сериализаторы на самом деле выполняют такую функцию в drf. Давайте сначала кратко разберемся с несколькими часто используемыми полями.
1. Общие поля
CharField, BooleanField, IntegerField, DateTimeField используются очень часто, поля внешних ключей добавим позже!
# 举例子
mobile = serializers.CharField(max_length=11, min_length=11)
age = serializers.IntegerField(min_value=1, max_value=100)
# format可以设置时间的格式,下面例子会输出如:2018-1-24 12:10
pay_time = serializers.DateTimeField(read_only=True,format='%Y-%m-%d %H:%M')
is_hot = serializers.BooleanField()
Разница в том, что в django форма делает акцент на проверке отправленной формы, а поле сериализатора не только играет решающую роль в проверке данных, но также играет важную роль в сериализации данных и их возврате.Важная роль! !
Мы видим, что разные поля могут использовать разные ключевые параметры, кроме того, есть несколько очень полезных параметров.
2. Параметр основных аргументов
read_only: True означает, что пользователи не могут загружать файлы сами по себе и могут использоваться только для вывода API.Если для поля установлено значение read_only=True, проверка данных не требуется, и они будут возвращены только после сериализации и возврата поля.Приведу простой пример: когда пользователь делает покупки, когда пользователь размещает заказ, обязательно будет сгенерирован номер заказа, и этот номер заказа должен быть заполнен фоновой логикой, а не пользователем.Если не установить read_only =True, тогда он сообщит об ошибке при проверке.
order_sn = serializers.CharField(readonly=True)
write_only: соответствует read_onlyrequired: Как следует из названия, это обязательное поле.
allow_null/allow_blank: разрешить ли NULL/пусто.error_messages: При возникновении ошибки отображается сообщение.
name = serializers.CharField(required=True, min_length=6,
error_messages={
'min_length': '名字不能小于6个字符',
'required': '请填写名字'})
label: настройки отображения поля, такие как label='Verification Code'help_text: добавьте текст подсказки в указанное поле, эти два поля более полезны для страницы API.style: Укажите тип поля, которое может быть более абстрактным. См. следующий пример:
# 在api页面,输入密码就会以*显示
password = serializers.CharField(
style={'input_type': 'password'})
# 会显示选项框
color_channel = serializers.ChoiceField(
choices=['red', 'green', 'blue'],
style={'base_template': 'radio.html'})
Также есть очень полезный параметр валидаторов, о котором мы упомянем позже!
3. HiddenField
Значение HiddenField не зависит от ввода, но должно быть установлено значение по умолчанию. Пользователь не должен публиковать данные, и они не будут возвращены пользователю в явном виде. Чаще всего используется user!!
Когда мы заходим в систему, мы выполняем некоторые операции Допустим, пользователь добавляет определенный курс в закладки, тогда фон должен автоматически идентифицировать пользователя, а затем пользователю нужно только опубликовать id курса, тогда для такой функции мы сотрудничаем с CurrentUserDefault() выполнить.
# 这样就可以直接获取到当前用户
user = serializers.HiddenField(
default=serializers.CurrentUserDefault())
save instance
Этот заголовок является небольшим названием официального документа. Я думаю, что это очень полезно. На первый взгляд, он установлен для поста и патча. Да, эта часть функции специально разработана для этих двух видов запросов. Если бы только простой получить запрос, то установка предыдущего поля может удовлетворить это требование.
мы вviewа такжеmixinsКак упоминалось в сообщении в блоге, запрос публикации соответствует методу создания, а запрос исправления соответствует методу обновления.Упомянутые здесь метод создания и метод обновления относятся к методам в определенном классе в миксинах. Давайте посмотрим на исходный код, вы можете увидеть другой блог для конкретного анализа исходного кода.mixins:
# 只截取一部分
class CreateModelMixin(object):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
class UpdateModelMixin(object):
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
Видно, что и create, и update прописали строчку: serializer.save(), затем, что эта строчка делала, анализируем исходный код.
# serializer.py
def save(self, **kwargs):
# 略去一些稍微无关的内容
···
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
···
else:
self.instance = self.create(validated_data)
···
return self.instance
Очевидно, что операция serializer.save вызывает метод создания или обновления сериализатора, а не в миксинах! ! ! Давайте посмотрим на блок-схему (в качестве примера возьмем пост)
Столько всего сказано, что же нам делать! Перегрузите эти два метода! !Если ваш вьюсет содержит post, то вам нужно перегрузить метод create, если он содержит patch, то вам нужно перегрузить метод update.
# 假设现在是个博客,有一个创建文章,与修改文章的功能, model为Article。
class ArticleSerializer(serializers.Serializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault())
name = serializers.CharField(max_length=20)
content = serializers.CharField()
def create(self, validated_data):
# 除了用户,其他数据可以从validated_data这个字典中获取
# 注意,users在这里是放在上下文中的request,而不是直接的request
user = self.context['request'].user
name = validated_data['name ']
content = validated_data['content ']
return Article.objects.create(**validated_data)
def update(self, instance, validated_data):
# 更新的特别之处在于你已经获取到了这个对象instance
instance.name = validated_data.get('name')
instance.content = validated_data.get('content')
instance.save()
return instance
Некоторым может быть любопытно, как система узнает, нужно ли нам вызывать метод create сериализатора или метод update.Из метода save() видно, что решение основано на:
if self.instance is not None:pass
Тогда создание и обновление наших миксинов уже настроено для разработчиков,
# CreateModelMixin
serializer = self.get_serializer(data=request.data)
# UpdateModelMixin
serializer = self.get_serializer(instance, data=request.data, partial=partial)
То есть экземпляр получается методом get_object() в обновлении, а затем передается сериализатору, а сериализатор определяет, какой метод вызывать, в зависимости от того, передан экземпляр или нет!
Пользовательская логика проверки проверки
отдельная проверка
Выше мы упомянули поле, которое может играть определенную роль в проверке, но очевидно, что оно имеет большие ограничения.Для простого примера, нам нужно судить о нашем номере мобильного телефона.Если мы используем CharField(max_length=11, min_length=11), это только гарантирует, что мы вводим 11 символов, тогда нам нужно настроить!
mobile_phone = serializers.CharField(max_length=11, min_length=11)
def validate_mobile_phone(self, mobile_phone):
# 注意参数,self以及字段名
# 注意函数名写法,validate_ + 字段名字
if not re.match(REGEX_MOBILE, mobile):
# REGEX_MOBILE表示手机的正则表达式
raise serializers.ValidationError("手机号码非法")
return mobile_phone
Конечно, сюда можно добавить много логики, например, она также может определять, есть ли у мобильника изначально база данных и так далее.
Совместная проверка
Приведенный выше метод проверки может проверять только одно поле.Если два поля объединяются для проверки, мы можем перегрузить метод validate().
start = serializers.DateTimeField()
finish = serializers.DateTimeField()
def validate(self, attrs):
# 传进来什么参数,就返回什么参数,一般情况下用attrs
if data['start'] > data['finish']:
raise serializers.ValidationError("finish must occur after start")
return attrs
Этот метод очень полезен. Здесь мы также можем работать с некоторыми полями только для чтения. Мы упомянули пример в read_only, генерация номера заказа, мы можем сгенерировать номер заказа на этом шаге, а затем добавить его в словарь attrs.
order_sn = serializers.CharField(readonly=True)
def validate(self, attrs):
# 调用一个方法生成order_sn
attrs['order_sn'] = generate_order_sn()
return attrs
Данный метод используется в сериализаторе моделей для удаления поля write_only.Это поле только проверяется, но не существует в указанной модели, то есть не может сохранить( ), его можно удалить здесь!
Validators
валидаторы могут напрямую воздействовать на поле, на данный момент это похоже на отдельный валидатор
def multiple_of_ten(value):
if value % 10 != 0:
raise serializers.ValidationError('Not a multiple of ten')
class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])
Конечно, хорошие функции есть и у валидаторов, предоставляемых drf: UniqueValidator, UniqueTogetherValidator и т.д. UniqueValidator: указывает, что объект уникален, например, имя пользователя может существовать только уникально:
username = serializers.CharField(
max_length=11,
min_length=11,
validators=[UniqueValidator(queryset=UserProfile.objects.all())
)
UniqueTogetherValidator: Комбинация уникальна. Например, если пользователь добавляет курс в закладки, он не может действовать только в одном поле. Мы устанавливаем его в мета.
class Meta:
validators = [
UniqueTogetherValidator(
queryset=UserFav.objects.all(),
fields=('user', 'course'),
message='已经收藏'
)]
ModelSerializer
много говорил о Serializer.На данный момент я по-прежнему настоятельно рекомендую использовать ModelSerializer, потому что в большинстве случаев мы разрабатываем на основе полей модели.
выгода:
ModelSerializer перегрузил методы создания и обновления, которые могут напрямую создавать и обновлять данные из сообщения или исправления. Если нет дополнительных требований, методы создания и обновления могут быть перегружены. ModelSerializer устанавливает поле fields в Meta, и система автоматически сопоставляет его, избавляя от необходимости писать поле для каждого поля.
class UserDetailSerializer(serializers.ModelSerializer):
"""
用户详情序列化
"""
class Meta:
model = User
fields = ("name", "gender", "birthday", "email", "mobile")
# fields = '__all__': 表示所有字段
# exclude = ('add_time',): 除去指定的某些字段
# 这三种方式,存在一个即可
ModelSerializer необходимо решить 2 проблемы:
1. Поле не принадлежит указанной модели, оно доступно только для записи и должно быть передано пользователем, но мы не можем его сохранить(), потому что ModelSerializer основан на Model, и это поле не соответствует Модель.На данный момент нам нужно перегрузить валидацию!
Например, когда пользователь регистрируется, нам нужно заполнить проверочный код.Этот проверочный код нужно только проверить и не нужно сохранять в Модели пользователя:
def validate(self, attrs):
del attrs["code"]
return attrs
2, поле не принадлежит указанной модели, оно только для чтения, его нужно только сериализовать и передать пользователю, а в этой модели такого поля нет! Нам нужно использовать SerializerMethodField.
Предположим, необходимо вернуть, как долго пользователь заходил на сайт, такие данные, как количество дней, в течение которых пользователь заходил, невозможно сохранить, обычно записывается момент времени, когда пользователь заходил, а затем, когда пользователь получает эти данные мы вычисляем и возвращаем в него.
class UserSerializer(serializers.ModelSerializer):
days_since_joined = serializers.SerializerMethodField()
# 方法写法:get_ + 字段
def get_days_since_joined(self, obj):
# obj指这个model的对象
return (now() - obj.date_joined).days
class Meta:
model = User
Конечно, это использование SerializerMethodField относительно просто, и позже будут более сложные ситуации.
Сериализаторы на внешних ключах
Сказав так много, я, наконец, должен изучить внешние ключи~
На самом деле поле внешнего ключа тоже относительно простое.Если мы используем сериализаторы.Serializer напрямую, то можно напрямую использовать PrimaryKeyRelatedField.
Предположим, что есть курс вводного обучения python (курс), и его категория — python (cadogory).
# 指定queryset
category = serializers.PrimaryKeyRelatedField(queryset=CourseCategory.objects.all(), required=True)
ModelSerializer проще, просто передайте сопоставление напрямую
Но это только то, что пользователь получает только id категории внешнего ключа, и не может получить подробную информацию.Если вы хотите получить конкретную информацию, вам нужно вложить сериализаторы
category = CourseCategorySerializer()
Примечание: В приведенных выше двух методах внешние ключи получаются в прямом направлении. Ниже описано, как получить их в обратном направлении. Например, нам нужно получить, какие курсы доступны в категории python. Во-первых, в модели курса нужно установить related_name во внешнем ключе
class Course(model.Model):
category = models.ForeignKey(CourseCategory, related_name='courses')
# 反向取课程,通过related_name
# 一对多,一个类别下有多个课程,一定要设定many=True
courses = CourseSerializer(many=True)
Пишем здесь, наши внешние ключи в основном готовы! Есть еще одна небольшая проблема: во второй задаче, которую ModelSerializer нужно решить выше, на самом деле другая ситуация, то есть поле принадлежит указанной модели, но релевантные данные не могут быть получены.
Предположим, что это многоуровневый классификационный курс, например, язык программирования --> python --> вводный курс обучения python, язык программирования и python относятся к категории, другой относится к курсу, категория языка программирования является иностранным ключ к категории python и принадлежность к той же модели, метод реализации:
parent_category = models.ForeignKey('self', null=True, blank=True,
verbose_name='父类目别',
related_name='sub_cat')
Теперь, если вы получаете курс по языку программирования, очевидно, вы не можете получить курс для начала работы с python напрямую, потому что они не имеют отношения внешнего ключа. SerializerMethodField() также может решить эту проблему, если соответствующая логика реализована в пользовательском методе!
courses = SerializerMethodField()
def get_courses(self, obj):
all_courses = Course.objects.filter(category__parent_category_id=obj.id)
courses_serializer = CourseSerializer(all_course, many=True,
context={'request': self.context['request']})
return courses_serializer.data
Приведенный выше пример выглядит немного странно, потому что мы вкладываем сериализатор в SerializerMethodField(), нам нужно его сериализовать самим, и тогда мы можем получить данные json из данных.
Вы можете увидеть, что прошедшие параметры: QuerySet, многие = истинные несколько объектов, контекст контекста. Этот контекст очень критичен. Если запрос не передается ему, во время сериализации поля снимков и файлов не будут префиксированы доменными именами, то есть, то есть только будут похожие на / носители / IMG ... Действительно
послесловие
На этом обзор сериализаторов закончен, если что-то не так, укажите! Далее я продолжу писать статьи, связанные с drf~~
CSDN: http://blog.csdn.net/l_vip/article/details/79156113