文档章节

Django REST framework的各种技巧——5.搜索

duoduo3_69
 duoduo3_69
发布于 2016/02/01 19:21
字数 883
阅读 248
收藏 1

restframework内置了一些搜索功能,可以快速的实现搜索

Django REST framework的各种技巧【目录索引】

写在上面

所有的代码都是在下面的两个版本来做的

django==1.8.8
djangorestframework==3.2.5 

查询

我们经常要做一些查询的东东,大体有两种,如下图: 查询

  1. 多字段模糊搜索
  2. 单字段相等搜索

restframework通过 filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter) 来很轻松的完成了这个工作。

文档

讲解

DjangoFilterBackend对应filter_fields属性,做相等查询 SearchFilter对应search_fields,对应模糊查询

两者都可以采用filter中使用的 外键__属性的方式来做查询

class CoursesView(ListCreateAPIView):

    filter_backends = (SchoolPermissionFilterBackend, filters.DjangoFilterBackend, filters.SearchFilter)
    permission_classes = (IsAuthenticated, ModulePermission)
    queryset = Course.objects.filter(is_active=True).order_by('-id')
    filter_fields = ('term',)
    search_fields = ('name', 'teacher', 'school__name')
    module_perms = ['course.course']

    def get_serializer_class(self):
        if self.request.method in SAFE_METHODS:
            return CourseFullMessageSerializer
        else:
            return CourseSerializer

    def get_queryset(self):
        return Course.objects.select_related('school', ).filter(
                is_active=True, school__is_active=True, term__is_active=True).order_by('-id')

机制是这样的,首先view调用get_queryset拿到queryset,然后在filter_backends用取到所有的backend进行filter,因此你可以写出很多通用的filter_backend然后组合调用,因为django的queryset是只有真正做list(list(qs))或者get(qs2)或者for in的时候才会真正hit数据库,所以这种拼接是没有任何问题的。

class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
        
class GenericAPIView(views.APIView):        

    def filter_queryset(self, queryset):
        """
        Given a queryset, filter it with whichever filter backend is in use.

        You are unlikely to want to override this method, although you may need
        to call it either from a list view, or from a custom `get_object`
        method if you want to apply the configured filtering backend to the
        default queryset.
        """
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

实现一个filter class

我真正想说的是filter,因为默认的filter_field相关的东西文档说的非常详细,儿filter class你可能需要一番尝试。

首先看view, 当使用filter_class时就不要写filter_fields了,因为对应的Class中有一个Meta Class的fields属性代替了filter_fields。

class SchoolsView(ListCreateAPIView):

    permission_classes = (IsAuthenticated, ModulePermission)
    filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter)
    filter_class = SchoolFilter
    search_fields = ('name', 'contact')
    module_perms = ['school.school']

看一个省市区的model

class BaseLocation(TimeStampedModel):
    is_active = models.BooleanField(default=True, db_index=True)

    class Meta:
        abstract = True

    def __unicode__(self):
        return self.name


class Province(BaseLocation):
    name = models.CharField(max_length=128, db_index=True)


class City(BaseLocation):
    province = models.ForeignKey(Province)
    name = models.CharField(max_length=255, db_index=True)


class District(BaseLocation):
    city = models.ForeignKey(City)
    name = models.CharField(max_length=255, db_index=True)

school model

class School(TimeStampedModel):
    MIDDLE_SCHOOL = 1
    COLLEGE = 2
    school_choices = (
        (MIDDLE_SCHOOL, u"中学"),
        (COLLEGE, u"高校")
    )
    category = models.SmallIntegerField(
        choices=school_choices, db_index=True, default=MIDDLE_SCHOOL)
    name = models.CharField(max_length=255, db_index=True)
    city = models.ForeignKey(City)
    ...
    is_active = models.BooleanField(default=True, db_index=True)

基础filter见下面的filter,是用来做父类继承的,因为Meta class中要写一个model。

解释下面的两行,等号左边的city对应Meta中fields的city,name="city"是指Filter Meta class中对应Model的属性,lookup_type是指对应的外键属性。其实下面这两行翻译过来是model.objects.filter(city__name = fields中city变量传来的值, city__province__name=fields中province变量传来的值)

city = django_filters.Filter(name="city", lookup_type='name') province = django_filters.Filter(name="city", lookup_type='province__name')

# -*- coding: utf-8 -*-
import django_filters

class CityFilter(django_filters.FilterSet):

    city = django_filters.Filter(name="city", lookup_type='name')
    province = django_filters.Filter(name="city", lookup_type='province__name')
    # need to include Meta filed
    class Meta:
        fields = ['city', 'province']


class DistrictFilter(django_filters.FilterSet):

    district = django_filters.Filter(name="district", lookup_type='name')
    city = django_filters.Filter(name="district", lookup_type='city__name')
    province = django_filters.Filter(name="district", lookup_type='city__province__name')

    # need to include Meta filed
    class Meta:
        fields = ['city', 'province', 'district']

上面view中用到的SchoolFilter

class SchoolFilter(CityFilter):

    class Meta:
        model = School
        fields = ['category', 'city', 'province']

注意

search fileds使用like做的,所以存在效率问题,如果有并发什么的需求,请接入其他搜索

© 著作权归作者所有

duoduo3_69
粉丝 89
博文 57
码字总数 83746
作品 0
青岛
程序员
私信 提问
加载中

评论(0)

Django REST framework的各种技巧【目录索引】

为了防止各位看同学不好找,在这边丢了个目录过来,因为以后可能继续写 目录 [Django REST framework的各种技巧——1.基础讲解][1] [Django REST framework的各种技巧——2.serializer][2] ...

duoduo3_69
2016/02/01
628
1
Django REST framework的各种技巧【目录索引】

为了防止各位看同学不好找,在这边丢了个目录过来,因为以后可能继续写 目录 Django REST framework的各种技巧——1.基础讲解 Django REST framework的各种技巧——2.serializer Django RES...

D咄咄
2017/11/29
0
0
Django REST framework的各种技巧——4.Generic View

generic view是django神奇的地方,而restframework遵循了这个powerful的机制 Django REST framework的各种技巧【目录索引】 写在上面 所有的代码都是在下面的两个版本来做的 一个之前的blog,...

D咄咄
2017/11/29
0
0
Django REST framework的各种技巧——5.搜索

restframework内置了一些搜索功能,可以快速的实现搜索 Django REST framework的各种技巧【目录索引】 写在上面 所有的代码都是在下面的两个版本来做的 查询 我们经常要做一些查询的东东,大...

D咄咄
2017/11/29
0
0
Django REST framework的各种技巧——6.异常处理

restframework内置了基本的异常处理,然而并不够用 Django REST framework的各种技巧【目录索引】 异常处理应该考虑的事情 异常时为了保持api的一致,应该返回json error_code 给开发看的err...

D咄咄
2017/11/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

数组foreach()遍历中的传递引用

在PHP的foreach ($arr as $k => $v) 的遍历中,每一轮的遍历,都发生了以下事情 $k = currentKey($arrCopy); //将副本数组本轮次的键的值分配给$k,比如下标0,1,2等;$v = currentVal($arrCo...

vinci321
今天
140
0
将文件从Docker容器复制到主机 - Copying files from Docker container to host

问题: I'm thinking of using Docker to build my dependencies on a Continuous Integration (CI) server, so that I don't have to install all the runtimes and libraries on the agent......

技术盛宴
今天
103
0
略谈分布式系统中的容器设计模式

本文作者:zytan_cocoa 略谈分布式系统中的容器设计模式 谭中意 2020/3/5 前言:云原生(Cloud Native)不仅仅是趋势,更是现在进行时,它是构建现代的,可弹性伸缩的,快速迭代的计算网络服...

百度开发者中心
03/11
133
0
elasticsearch 第三讲

es的详细介绍 SearchTemplate tmdb 表示的是模板名称 dmdb1 表示的是当前的索引 脚本方式编辑 ##编辑模板POST _scripts/tmdb{ "script": { "lang": "mustache", "source": { ......

鸡蛋炒馒头
今天
209
0
IDEA新建springMVC项目,启动后访问Controller报404

IDEA新建springMVC项目,启动后可以访问到默认的index.jsp,但是访问controller就报404 查看web.xml配置 spingmvc.xml配置 都没有问题 请求的url也和定义的@RequestMapping一致。也没有问题。...

vicky_dimi
今天
316
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部