Django--004 DRF-Serializer

1. 简介

  • 定义
  • 在Django框架基础上进行二次开发,用于构建Restful API,简称DRF
  • 特性
  • 强大的Serializer序列化器,可以高效的进行序列化和反序列化操作;
  • 极为丰富的类视图、Mixin扩展类、ViewSet视图集;
  • 提供直观的WEB API界面;
  • 多种身份认证和权限认证;
  • 强大的排序、过滤、分页、搜索、限流等功能;
  • 可扩展性,插件丰富

2. 安装配置

  • 安装
pip install djangorestframework
  • 配置
# 可理解为子应用,在settings.py文件中设置即可
INSTALLED_APPS = [
    'rest_framework'
]

3. 序列化器(serializer)

3.1 序列化器

  • 序列化:将Django模型数据转化为json格式字符串(前段可接收的数据),为序列化
  • 反序列化:前段传过来的json格式数据,转化为Django模型类对象,为反序列化
  • 序列化器:具有序列化和反序列化的功能

3.2 代码

  • model.py
from django.db import models


class Projects(models.Model):
    # verbose_name -字段名,   help_text - api文档的中文名
    id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField(verbose_name='项目名称', max_length=64, unique=True, help_text='项目名称')
    leader = models.CharField(verbose_name='项目负责人', max_length=32, help_text='项目负责人')
    developer = models.CharField(verbose_name='开发人员', max_length=32, help_text='开发人员')
    tester = models.CharField(verbose_name='测试人员', max_length=32, help_text='测试人员')
    app_name = models.CharField(verbose_name='应用名称', max_length=32, help_text='应用名称')
    # null -字段允许为空, blank - 前端可不传参数, default - 默认值
    desc = models.CharField(verbose_name='简要描述', max_length=256, null=True, blank=True, default='', help_text='简要描述')

    class Meta:
        """
        表名
        """
        db_table = 'tb_projects'
        verbose_name = '项目信息'
        verbose_name_plural = verbose_name
        ordering = ['id']

    def __str__(self):
        """
        修改admin后台展示的项目名称
        """
        return self.name
  • serializer.py
  • 继承(serializers.Serializer)时, 需要重写 update 与 create 方法,因为Serializer 继承 BaseSerializer类,其中update 与 create 方法会直接raise
  • serializer.save()时会根据instance 有无,无则调用create,有则调用update,instance可认为是符合序列化结构的数据
# -*- coding: utf-8 -*-
# @File : serializers.py

from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from projects.models import Projects


# 自定义外部校验器
def is_unique_project_name(name):
    if '项目' not in name:
        raise serializers.ValidationError('项目名称中必须包含"项目"')


class ProjectsSerializers(serializers.Serializer):
    id = serializers.IntegerField(label='ID', read_only=True)
    name = serializers.CharField(label='项目名称', max_length=64, min_length=4, help_text='项目名称',
                                 validators=[UniqueValidator(queryset=Projects.objects.all(), message='项目名称不能重复'),
                                             is_unique_project_name],
                                 error_messages={'max_length': '项目名称不能超过64个字节', 'min_length': '项目名称不能少于4个字节'})
    leader = serializers.CharField(label='项目负责人', max_length=32, help_text='项目负责人', write_only=True)
    developer = serializers.CharField(label='开发人员', max_length=32, help_text='开发人员')
    tester = serializers.CharField(label='测试人员', max_length=32, help_text='测试人员')
    app_name = serializers.CharField(label='应用名称', max_length=32, help_text='应用名称')
    desc = serializers.CharField(label='项目概述', max_length=256, help_text='项目概述', allow_null=True, allow_blank=True,
                                 default='')

    def validate__name(self, value):
        if not value.endswith('项目'):
            raise serializers.ValidationError('项目名称必须以"项目"结尾')
        return value

        # ----多字段校验器

    def validate(self, attrs):
        """
        多字段校验器
        """
        if '张三' not in attrs['developer'] and '张三' not in attrs['tester']:
            raise serializers.ValidationError('"张三"必须是项目开发人员或测试人员')
        return attrs

    def create(self, validated_data):
        return Projects.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.name = validated_data['name']
        instance.leader = validated_data['leader']
        instance.developer = validated_data['developer']
        instance.tester = validated_data['tester']
        instance.app_name = validated_data['app_name']
        instance.desc = validated_data['desc']
        instance.save()
        return instance

  • views.py
from django.http import JsonResponse, Http404
from django.views import View
from projects.models import Projects
from projects.serializers import ProjectsSerializers
import json


class ProjectList(View):
    """"
    类视图
    """

    def get(self, request):
        projects= Projects.objects.all()
        # many=True: 输出querySet,返回多条数据
        serializer = ProjectsSerializers(instance=projects, many=True)
        return JsonResponse(serializer.data, safe=False, status=200)

    def post(self, request):
        """
        httpie模拟请求:http POST :8000/projects/ name='项目009' leader="zz" developer='李四'  tester='张三' \
                                      app_name='测试应用'  desc='demo desc'
        """
        # 1. 前端传入json数据转为python_data
        data = json.loads(request.body.decode('utf-8'), encoding='utf-8')
        # 2. 数据校验
        serializer = ProjectsSerializers(data=data)
        try:
            # 设置raise_exception=True后serializer.errors可以获取到报错信息
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            # 3. 校验失败则返回异常dict
            return JsonResponse(serializer.errors)
        # 3. 校验通过则调用序列化器的save方法(会调用序列化器的create方法)新建数据
        serializer.save()
        # 返回新建成功的这条数据
        return JsonResponse(serializer.data, safe=False, status=201)


class ProjectDetail(View):
    def get_object(self, pk):
        """
        根据id判断项目是否存在,存在则返回,不存在则返回404
        """
        try:
            return Projects.objects.get(id=pk)
        except Projects.DoesNotExist:
            raise Http404

    def get(self, request, pk):
        """
        httpie模拟请求:http  :8000/projects/12
        """
        project = self.get_object(pk)
        serializer = ProjectsSerializers(instance=project)
        return JsonResponse(serializer.data, safe=False)

    def put(self, request, pk):
        """
        httpie模拟请求:http PUT :8000/projects/12 name='项目0091' leader="张三" developer='李四' \
                                tester='王五' app_name='测试应用' app_version='1.0' desc='demo desc'
        """
        # 1.判断数据是否存在
        project = self.get_object(pk)
        # 2. 将前端数据反序列化为模型可解析的数据
        data = json.loads(request.body.decode('utf-8'), encoding='utf-8')
        # 同时存在反序列化和序列化时,同时传参会调用序列化器update方法
        serializer = ProjectsSerializers(instance=project, data=data)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            # 3. 校验失败则返回异常dict
            return JsonResponse(serializer.errors)
        # 4. 校验通过则更新
        # ----调用save方法会调用序列化器的update方法
        serializer.save()
        return JsonResponse(serializer.data, safe=False, status=201)

    def delete(self, request, pk):
        """
        httpie模拟请求:http DELETE :8000/projects/12
        """
        # 1. 判断数据是否存在
        project = self.get_object(pk)
        # 2. 删除
        project.delete()
        return JsonResponse(None, safe=False, status=204)

  • urls.py
# urls.py
from django.urls import path
from projects import views

urlpatterns = [
    path(r'projects/<int:pk>', views.ProjectDetail.as_view()),
    path(r'projects/', views.ProjectList.as_view()),
]

4. 模型序列化器(ModelSerializer)

4.1 模型序列化器

  • 功能与特点:
  • 功能同序列化器,但简化了序列化器的定义
  • 基于模型类生成一系列字段
  • 基于模型类自动为serializer生成validators,比如unique_together
  • 包含默认的create()和update()功能的实现
  • 关联字段序列化
  • PrimaryKeyRelatedField
  • StringRelatedField
  • SlugRelatedField

4.2 代码

  • 数据库模型
# projects/model.py

from django.db import models


class Projects(models.Model):
    # verbose_name -字段名,   help_text - api文档的中文名
    name = models.CharField(verbose_name='项目名称', max_length=64, help_text='项目名称', unique=True)
    leader = models.CharField(verbose_name='项目负责人', max_length=32, help_text='项目负责人')
    developer = models.CharField(verbose_name='开发人员', max_length=32, help_text='开发人员')
    tester = models.CharField(verbose_name='测试人员', max_length=32, help_text='测试人员')
    app_name = models.CharField(verbose_name='应用名称', max_length=32, help_text='应用名称')
    app_version = models.CharField(verbose_name='应用版本', max_length=32, help_text='应用版本')
    # null -字段允许为空, blank - 前端可不传参数, default - 默认值
    desc = models.TextField(verbose_name='项目概述', max_length=256, help_text='项目概述', blank=True, default='', null=True)

    class Meta:
        """
        表名
        """
        db_table = 'tb_projects'
        verbose_name = '项目'
        verbose_name_plural = '项目'

    def __str__(self):
        """
        修改admin后台展示的项目名称
        """
        return self.name

# interfaces/model.py 
from django.db import models


class Interfaces(models.Model):
    # verbose_name -字段名,   help_text - api文档的中文名
	id = models.AutoField(verbose_name='id主键', primary_key=True, help_text='id主键')
    name = models.CharField(verbose_name='接口名称', max_length=64, unique=True, help_text='接口名称')
    tester = models.CharField(verbose_name='测试人员', max_length=32, help_text='测试人员')
    desc = models.TextField(verbose_name='接口描述', max_length=256, help_text='接口概述', blank=True, default='', null=True)
    # 外键
    # CASCADE--父表删除后,子表也会被删除,null=True
    # SET_NULL--父表删除后,当前外键会被设置为None
    # SET_DEFAULT--父表删除后,子表需要设置默认值,null=True
    project = models.ForeignKey('projects.Projects', on_delete=models.CASCADE, related_name='interfaces', verbose_name='所属项目', help_text='所属项目')

    class Meta:
        db_table = 'tb_interfaces'
        verbose_name = '接口'
        verbose_name_plural = '接口'

    def __str__(self):
        return self.name
  • 模型序列化器
  • 继承(serializers.ModelSerializer)时,ModelSerializer已重写 update 与 create 方法,没有新的字段时不需要重写这2个方法
# projects/serializer.py

from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from projects.models import Projects


# 自定义外部校验器
def is_unique_project_name(name):
    if '项目' not in name:
        raise serializers.ValidationError('项目名称中必须包含"项目"')


class ProjectModelSerializer(serializers.ModelSerializer):
    """"""
    # 如果有自定义字段,则以自定义字段为准
    name = serializers.CharField(label='项目名称', max_length=64, help_text='项目名称',
                                    validators=[
                                        UniqueValidator(queryset=Projects.objects.all(), message='项目名称不能重复'),
                                        is_unique_project_name])

    # 可以额外定义数据库没有的字段

    # 父表默认不会生成子表字段序列化器具,需要指定
    # 父表默认不会生成子表字段序列化器具,需要指定
    # 字段名需要和从表model中related_name值一致
    # 父表和子表不能同时引入对方序列化器,否则会导致循环引用
    # from interfaces.serializers import InterfacesModelSerializer
    # interfaces = InterfacesModelSerializer(label='所拥有的接口', many=True)
    interfaces = serializers.StringRelatedField(label='拥有的所有接口名称', many=True)

    class Meta:
        # 指定参考哪个模型来创建
        model = Projects
        # 自定义序列化器字段
        # ---全部字段
        # fields = "__all__"
        # ---指定字段生成
        # fields = ('id', 'name', 'leader')
        # ---指定哪些字段不生成
        exclude = ('desc', 'app_version')
        # ---设置read_only=True属性
        read_only_fields = ('id', 'desc')

        # 定义序列化器各字段约束及提示等信息
        extra_kwargs = {
            'name': {
                'label': '项目名称',
                'max_length': 64,
                'min_length': 4,
                'write_only': False,
                'error_message': {'max_length': '最大长度不超过50字节'},
                'validators': [UniqueValidator(queryset=Projects.objects.all(), message='项目名称不能重复'),
                                                is_unique_project_name]
            },
            'leader': {
                'label': '项目负责人',
            }
        }

    # 自定义内部校验器,不需要在validators校验列表中添加
    # 执行顺序:先执行validators列表中校验器, 后执行内部字段校验器
    # ----单字段校验器
    def validate_name(self, value):
        if not value.endswith('项目'):
            raise serializers.ValidationError('项目名称必须以"项目"结尾')
        return value

    # ----多字段校验器
    def validate(self, attrs):
        if '张三' not in attrs['developer'] and '张三' not in attrs['tester']:
            raise serializers.ValidationError('"张三"必须是项目开发人员或测试人员')
        return attrs
# interfaces/serializer.py

from rest_framework import serializers
from interfaces.models import Interfaces
from projects.serializer import ProjectModelSerializer


class InterfaceModelSerializer(serializers.ModelSerializer):
    # 1. 数据库模型中的外键字段,默认会生成PrimaryKeyRelatedField序列化器字段,默认输出外键ID值
    # httpie模拟请求:http POST :8000/interfaces/ name='接口001' tester="吴用" desc='这是第一个测试接口' project=1
    project = serializers.PrimaryKeyRelatedField(help_text='所属项目', label='所属项目', queryset=Projects.objects.all())
    # 2. StringRelatedField 字段将被序列化为关联字符串表达形式(即__str__方法返回值),即ID对应的项目名称
    # project = serializers.StringRelatedField(help_text='项目名称')
    # 3. SlugRelatedField, 此字段将被序列化为关联对象的制定字段
    # project = serializers.SlugRelatedField(slug_field='leader', read_only=True)
    # 4. 使用关联字段的序列化器,输出关联字段序列化对象
    # 父表和子表不能同时引入对方序列化器,否则会导致循环引用
    # from projects.serializers import ProjectsModelSerializers
    # project = ProjectsModelSerializers(label='所属项目', read_only=True)

    class Meta:
        # 指定参考哪个模型来创建
        model = Interfaces
        fields = "__all__"
  • 视图
# projects/view.py

# -*-coding:utf-8 -*-

from django.http import HttpResponse, JsonResponse, Http404
from django.views import View
from projects.models import Projects
from projects.serializer import ProjectModelSerializer
import json


class ProjectList(View):
    """"
    类视图
    """
    def get(self, request):
        projects = Projects.objects.all()
        # many=True: 输出querySet,返回多条数据
        # serializer = ProjectSerializer(instance=projects, many=True)
        serializer = ProjectModelSerializer(instance=projects, many=True)

        return JsonResponse(serializer.data, safe=False, status=200)

    def post(self, request):
        """
        httpie模拟请求:http POST :8000/projects/ name='项目009' leader="zz" developer='李四' tester='王五' app_name='测试应用' app_version='1.0' desc='demo desc'
        """
        # 1. 前端传入json数据反序列化为模型数据
        data = json.loads(request.body.decode('utf-8'), encoding='utf-8')
        # 2. 数据校验
        serializer = ProjectModelSerializer(data=data)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            # 3. 校验失败则返回异常dict
            return JsonResponse(serializer.errors)
        serializer.save()   # 调用save方法会调用序列化器的create方法
        return JsonResponse(serializer.data, safe=False, status=201)


class ProjectDetail(View):
    def get_object(self, pk):
        try:
            return Projects.objects.get(id=pk)
        except Projects.DoesNotExist:
            raise Http404

    def get(self, request, pk):
        """
        httpie模拟请求:http  :8000/projects/12
        """
        project= self.get_object(pk)
        serializer = ProjectModelSerializer(instance=project)
        return JsonResponse(serializer.data, safe=False)

    def put(self, request, pk):
        """
        httpie模拟请求:http PUT :8000/projects/12 name='项目0091' leader="张三" developer='李四' tester='王五' app_name='测试应用' app_version='1.0' desc='demo desc'
        """
        # 1.判断数据是否存在
        project = self.get_object(pk)
        # 2. 将前端数据反序列化为模型数据
        data = json.loads(request.body.decode('utf-8'), encoding='utf-8')
        # 3. 数据合法性校验
        # serializer = ProjectSerializer(data=update_project_data)
        # 同时存在反序列化和序列化时,同时传参会调用序列化器update方法
        serializer = ProjectModelSerializer(instance=project, data=data)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            # 3. 校验失败则返回异常dict
            return JsonResponse(serializer.errors)
        serializer.save()  # 调用save方法会调用序列化器的update方法
        return JsonResponse(serializer.data, safe=False, status=201)

    def delete(self, request, pk):
        """
        httpie模拟请求:http DELETE :8000/projects/12
        """
        # 1. 判断数据是否存在
        project = self.get_object(pk)
        # 2. 删除
        project.delete()
        return JsonResponse(None, safe=False, status=204)
# interfaces/view.py

# -*-coding:utf-8 -*-

from django.http import HttpResponse, JsonResponse, Http404
from django.views import View
from interfaces.models import Interfaces
from interfaces.serializer import InterfaceModelSerializer
import json


class InterfaceList(View):
    """"
    类视图
    """
    def get(self, request):
        """
        httpie模拟请求:http :8000/interfaces/
        """
        interfaces = Interfaces.objects.all()
        serializer = InterfaceModelSerializer(instance=interfaces, many=True)
        return JsonResponse(serializer.data, safe=False, status=200)

    def post(self, request):
        """
        httpie模拟请求:http POST :8000/interfaces/ name='接口001' tester="吴用" desc='这是第一个测试接口' project_id=1
        """
        # 1. 前端传入json数据反序列化为模型数据
        data = json.loads(request.body.decode('utf-8'), encoding='utf-8')
        # 2. 数据校验
        serializer = InterfaceModelSerializer(data=data)
        try:
            serializer.is_valid(raise_exception=True)
        except Exception as e:
            # 3. 校验失败则返回异常dict
            return JsonResponse(serializer.errors)
        serializer.save()   # 调用save方法会调用序列化器的create方法
        return JsonResponse(serializer.data, safe=False, status=201)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 安装Elasticsearch和Python Elasticsearch客户端 - Elasticsearch安装可以参考官网的[安装文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html) - Python Elasticsearch客户端可以使用pip安装:`pip install elasticsearch` 2. 在Django项目中创建一个app,用于处理与Elasticsearch相关的逻辑。 3. 配置Elasticsearch连接信息,可以在Django的`settings.py`中添加以下配置: ``` ELASTICSEARCH_DSL = { 'default': { 'hosts': 'localhost:9200' }, } ``` 其中,`hosts`就是Elasticsearch的地址,这里使用默认的`localhost:9200`。 4. 创建Elasticsearch索引模板,可以在app目录下创建一个`search_indexes.py`文件,定义索引模板: ``` from elasticsearch_dsl import Document, Text, Date, Keyword class ArticleIndex(Document): title = Text() content = Text() pub_date = Date() tags = Keyword(multi=True) class Index: name = 'articles' ``` 其中,`ArticleIndex`是一个继承自`Document`的类,定义了索引的字段和类型。`Index`类中的`name`属性指定了索引的名称。 5. 在app目录下创建`serializers.py`文件,定义序列化器,将模型序列化为Elasticsearch索引模板: ``` from rest_framework import serializers from .models import Article from .search_indexes import ArticleIndex class ArticleIndexSerializer(serializers.ModelSerializer): class Meta: model = Article fields = ('id', 'title', 'content', 'pub_date', 'tags') def save(self, **kwargs): article = super().save(**kwargs) article_index = ArticleIndex(meta={'id': article.id}, **article.__dict__) article_index.save() return article ``` 其中,`ArticleIndexSerializer`继承自`ModelSerializer`,定义了序列化的模型和字段。在`save`方法中,先保存模型,再将模型数据序列化为Elasticsearch索引模板,最后保存到Elasticsearch中。 6. 在app目录下创建`views.py`文件,定义视图函数,实现Elasticsearch搜索功能: ``` from rest_framework.views import APIView from rest_framework.response import Response from elasticsearch_dsl import Q from .search_indexes import ArticleIndex from .serializers import ArticleIndexSerializer class ArticleSearchView(APIView): def get(self, request): query = request.query_params.get('q', '') s = ArticleIndex.search().query( Q('multi_match', query=query, fields=['title', 'content', 'tags']) ) response = [] for hit in s.execute().hits: serializer = ArticleIndexSerializer(data=hit.to_dict()) serializer.is_valid() response.append(serializer.data) return Response(response) ``` 其中,`ArticleSearchView`继承自`APIView`,定义了一个`get`方法,接收`q`参数作为搜索关键词。通过Elasticsearch DSL构建查询语句,搜索索引模板中的数据,最后将搜索结果序列化返回。 7. 在app目录下创建`urls.py`文件,定义路由: ``` from django.urls import path from .views import ArticleSearchView urlpatterns = [ path('search/', ArticleSearchView.as_view(), name='article_search'), ] ``` 其中,`search`路由对应了`ArticleSearchView`视图函数。 8. 在Django的`settings.py`中添加app,配置数据库信息: ``` INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'app_name', # 添加app ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'db_name', 'USER': 'db_user', 'PASSWORD': 'db_password', 'HOST': 'localhost', 'PORT': '3306', } } ``` 9. 在app目录下创建`models.py`文件,定义模型,使用Django ORM作为数据源: ``` from django.db import models class Article(models.Model): title = models.CharField(max_length=255) content = models.TextField() pub_date = models.DateTimeField(auto_now_add=True) tags = models.CharField(max_length=255, blank=True) def __str__(self): return self.title ``` 其中,`Article`是一个继承自`models.Model`的类,定义了文章的属性。 10. 在app目录下创建`admin.py`文件,注册模型到Django Admin中: ``` from django.contrib import admin from .models import Article admin.site.register(Article) ``` 11. 在Django的`urls.py`中添加app的路由: ``` from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('app_name.urls')), ] ``` 12. 启动Django开发服务器,访问`http://localhost:8000/admin/`,进入Django Admin,创建一些文章数据。 13. 访问`http://localhost:8000/api/search/?q=django`,可以看到搜索结果,其中包含关键词`django`的文章数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值