admin 管理员组文章数量: 886993
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_modelUser = 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.titleclass Meta:ordering = ['-create_date']verbose_name = "Article"verbose_name_plural = "Articles"
对应的序列化器如下:
class ArticleSerializer(serializers.ModelSerializer):class Meta:model = Articlefields = '__all__'
一个实际的需求,假设我现在要查询文章的list,但不需要所有的字段。
假设我的get请求如下:
[GET] /?fields=title,author # 查询所有文章的标题,作者
难道要为不同的请求配置不同的序列化器吗?比如再写一个精简版的序列化器,字段只有title和author。
#精简序列化版
class ArticleSerializerLite(serializers.ModelSerializer):class Meta:model = Articlefields = ('id', 'title','author',)
不同的查询url就要配置不同的序列化器,代码简直繁琐到无法想象。
下面我们来实现一个可以动态修改fields的序列化器。
通过阅读官方文档,可知初始化序列化程序后,可以使用.fields
属性访问序列化程序上设置的字段字典。通过访问和修改此属性,可以动态修改序列化程序。直接修改fields参数可以让您做一些有趣的事情,比如在运行时更改序列化程序字段的参数,而不是在声明序列化程序时。
# 实现一个动态修改fields的序列化器
class DynamicFieldsModelSerializer(serializers.ModelSerializer):"""A ModelSerializer that takes an additional `fields` argument thatcontrols which fields should be displayed."""def __init__(self, *args, **kwargs):# Don't pass the 'fields' arg up to the superclassfields = 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 = Articlefields = '__all__'
实际使用时,解析get请求的query参数,打包为一个元组作为序列化器的参数即可。
UserSerializer(user, fields=('title','author'))
2. 实现RESTful风格的信息过滤
现在我们对数据有一些过滤要求,比如要查询标题中包含了“django”且公开发布的所有文章。
[GET] =django&status=p
2.1 方法一:重写GenericsAPIView或viewset的get_queryset方法
此方法不依赖于任何第三方包, 只适合于需要过滤的字段比较少的模型。比如这里我们需要对文章author进行过滤,我们只需要修改ArticleList视图函数类即可。
# blog/views.py
from rest_framework import genericsclass ArticleList(generics.ListCreateAPIView):serializer_class = ArticleSerializerdef 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
这里可以参考一篇知乎教程:
django-filter库包含一个DjangoFilterBackend类,该类支持REST框架的高度可定制的字段过滤,自定义需要过滤的字段非常方便, 还可以对每个字段指定过滤方法(比如模糊查询和精确查询)。
具体使用方式如下:
- 安装django-filter
pip install django-filter
- 把django_filters添加到INSTALLED_APPS
INSTALLED_APPS = [...,django_filters,
]
- 自定义FilterSet类。这里我们自定义了按标题关键词和文章状态进行过滤。
# blog/filters.py(新建)import django_filters
from .models import Articleclass ArticleFilter(django_filters.FilterSet):q = django_filters.CharFilter(field_name='title', lookup_expr='icontains') #icontains表示模糊查询(包含),并且忽略大小写class Meta:model = Articlefields = ('title', 'status')
- 将自定义FilterSet类加入到View类或ViewSet,另外还需要将DjangoFilterBackend设为过滤后台,如下所示:
# New for django-filter
from django_filters import rest_framework
from .filters import ArticleFilterclass ArticleList(generics.ListCreateAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializer# new: filter backends and classesfilter_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
,得到只包含发表了的文章。
本文标签: Django后端开发学习笔记(7)使用动态修改fields的序列化器实现指定字段的查询以及RESTful风格的信息过滤
版权声明:本文标题:Django后端开发学习笔记(7)使用动态修改fields的序列化器实现指定字段的查询以及RESTful风格的信息过滤 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1732360539h1535087.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论