IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Django后端开发学习笔记(7)使用动态修改fields的序列化器实现指定字段的查询以及RESTful风格的信息过滤 -> 正文阅读

[Python知识库]Django后端开发学习笔记(7)使用动态修改fields的序列化器实现指定字段的查询以及RESTful风格的信息过滤

参考教程
【1】Django REST Framework教程(9): 过滤(filter)与排序

【2】Django-filter,让过滤如此简单

【3】DRF文档:Dynamically modifying fields

1. 使用动态修改fields的序列化器实现指定字段的查询

依然沿用之前的博客案例,文章的模型如下:

# blog/models.py
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model

User = get_user_model()

class Article(models.Model):
    """Article Model"""
    STATUS_CHOICES = (
        ('p', _('Published')),
        ('d', _('Draft')),
    )

    title = models.CharField(verbose_name=_('Title (*)'), max_length=90, db_index=True)
    body = models.TextField(verbose_name=_('Body'), blank=True)
    author = models.ForeignKey(User, verbose_name=_('Author'), on_delete=models.CASCADE, related_name='articles')
    status = models.CharField(_('Status (*)'), max_length=1, choices=STATUS_CHOICES, default='s', null=True, blank=True)
    create_date = models.DateTimeField(verbose_name=_('Create Date'), auto_now_add=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-create_date']
        verbose_name = "Article"
        verbose_name_plural = "Articles"

对应的序列化器如下:

class ArticleSerializer(serializers.ModelSerializer):

    class Meta:
        model = Article
        fields = '__all__'

一个实际的需求,假设我现在要查询文章的list,但不需要所有的字段。
假设我的get请求如下:

[GET]     https://api.example.com/v1/articles/?fields=title,author # 查询所有文章的标题,作者

难道要为不同的请求配置不同的序列化器吗?比如再写一个精简版的序列化器,字段只有title和author。

#精简序列化版
class ArticleSerializerLite(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('id', 'title','author',)

不同的查询url就要配置不同的序列化器,代码简直繁琐到无法想象。

下面我们来实现一个可以动态修改fields的序列化器。

通过阅读官方文档,可知初始化序列化程序后,可以使用.fields属性访问序列化程序上设置的字段字典。通过访问和修改此属性,可以动态修改序列化程序。直接修改fields参数可以让您做一些有趣的事情,比如在运行时更改序列化程序字段的参数,而不是在声明序列化程序时。

# 实现一个动态修改fields的序列化器
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # 正常地实例化父类
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # 删除fields参数中未指定的任何字段
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

# 文章的序列化器继承动态fields序列化器
class ArticleSerializer(DynamicFieldsModelSerializer):

    class Meta:
        model = Article
        fields = '__all__'

实际使用时,解析get请求的query参数,打包为一个元组作为序列化器的参数即可。

UserSerializer(user, fields=('title','author'))

2. 实现RESTful风格的信息过滤

现在我们对数据有一些过滤要求,比如要查询标题中包含了“django”且公开发布的所有文章。

[GET]     https://api.example.com/v1/articles?title=django&status=p 

2.1 方法一:重写GenericsAPIView或viewset的get_queryset方法

此方法不依赖于任何第三方包, 只适合于需要过滤的字段比较少的模型。比如这里我们需要对文章author进行过滤,我们只需要修改ArticleList视图函数类即可。

# blog/views.py
from rest_framework import generics

class ArticleList(generics.ListCreateAPIView):
    serializer_class = ArticleSerializer

    def get_queryset(self):
        keyword = self.request.query_params.get('q')
        if not keyword:
            queryset = Article.objects.all()
        else:
            queryset = Article.objects.filter(title=keyword)
        return queryset

当一个模型需要过滤的字段很多且不确定时(比如文章状态、正文等等), 重写get_queryset方法将变得非常麻烦,更好的方式是借助django-filter这个第三方库实现过滤。

方法二:使用django-filter

这里可以参考一篇知乎教程:https://zhuanlan.zhihu.com/p/110060840

django-filter库包含一个DjangoFilterBackend类,该类支持REST框架的高度可定制的字段过滤,自定义需要过滤的字段非常方便, 还可以对每个字段指定过滤方法(比如模糊查询和精确查询)。

具体使用方式如下:

  1. 安装django-filter
pip install django-filter
  1. 把django_filters添加到INSTALLED_APPS
INSTALLED_APPS = [
    ...,
    django_filters,
]
  1. 自定义FilterSet类。这里我们自定义了按标题关键词和文章状态进行过滤。
# blog/filters.py(新建)

import django_filters
from .models import Article

class ArticleFilter(django_filters.FilterSet):
    q = django_filters.CharFilter(field_name='title', lookup_expr='icontains') #icontains表示模糊查询(包含),并且忽略大小写

    class Meta:
        model = Article
        fields = ('title', 'status')
  1. 将自定义FilterSet类加入到View类或ViewSet,另外还需要将DjangoFilterBackend设为过滤后台,如下所示:
# New for django-filter
from django_filters import rest_framework
from .filters import ArticleFilter

class ArticleList(generics.ListCreateAPIView):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

    # new: filter backends and classes
    filter_backends = (rest_framework.DjangoFilterBackend,)
    filter_class = ArticleFilter

    # associate request.user with author.
    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

发送GET请求到/v1/articles?page=2&q=django&status=p,得到只包含发表了的文章。

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 11:50:39  更:2021-09-03 11:52:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 12:41:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码