曦远 (DealiAxy)一份私人的文字刊物

StarBlog
返回文章列表折页手记阅读全文
Django

Introduction to Django-Filter and How to Implement Tricky Requirements

Django-Filter is a very useful third-party library that makes great use of Django ORM's features. You can extend existing APIs with very little code to implement various filtering functions~ Scenario Part of the Model definition code. You can see that the requirement model includes these three fields: keyword keyword, region region, and requirement status require_status class Require(models.Model): Requirement keyword =

曦远 (DealiAxy)约 14 分钟
目录9 个章节

Django-Filter is a very useful third-party library that makes great use of Django ORM's features. You can extend existing APIs with very little code to implement various filtering functions~

Scenario

Part of the Model definition code. You can see that the requirement model includes these three fields: keyword keyword, region region, and requirement status require_status

class Require(models.Model):
    """需求"""
    keyword = models.CharField('需求关键字', max_length=1000, blank=True)
    region = models.ForeignKey(Region, verbose_name='落地实施区域', null=True, on_delete=models.SET_NULL)
    require_status = models.IntegerField('需求进行状态', choices=RequireStatusChoice.choices)

Next is the ViewSet code. In DRF, after simple route configuration you can get the requirement list, but real-world scenarios definitely require more than this

class RequireViewSet(viewsets.ModelViewSet):
    """需求记录"""
    serializer_class = RequireSerializer
    queryset = Require.objects.all()

The product needs many features. For this requirement module specifically, we need:

  • Search requirements by keyword
  • Filter requirements by implementation region
  • Filter requirements by requirement progress status

If we were using Java, we'd definitely have to dutifully write a few extra lines of code to implement this. But! Life is short, I use Python!

How could we Python users possibly yield to implementing such a simple feature? When it's time to be lazy, we must be lazy. If there's no way to be lazy, we still have to force ourselves to be lazy hhh~

Simple Usage of Django-Filter

Let's see how we implement this with Django-Filter. First, install Django-Filter:

pip install django-filter

Add it to settings.py:

INSTALLED_APPS = [
    ...
    'django_filters',
]

Then just configure it in the ViewSet:

from django_filters.rest_framework import DjangoFilterBackend

class RequireViewSet(viewsets.ModelViewSet):
    """需求记录"""
    serializer_class = RequireSerializer
    queryset = Require.objects.all()
    filter_backends = [DjangoFilterBackend, SearchFilter]
    # 参与分类筛选的字段
    filter_fields = ['require_status', 'region']
    # 参与搜索的字段: search=关键词
    search_fields = ['keyword']

After configuration, you can filter and search on top of the original API. Assume the endpoint is: http://127.0.0.1/require/

http://127.0.0.1/require/?search=关键词

Filter by Region

http://127.0.0.1/require/?region=1

Filter by Requirement Status

http://127.0.0.1/require/?require_status=2

The result is perfect. Just simple configuration can implement so many features. That's the benefit of being lazy (standing on the shoulders of giants). These CRUD features don't really involve much technical skill anyway—the authors of the framework and third-party libraries have already implemented them for us, so we can just use them~

But then the frontend folks came up with a new requirement: the requirement status require_status needs to filter requirements with multiple statuses at once, for example filtering requirements with status numbers 2-9 at the same time... This is a pain. Django-Filter only supports one by default. What to do...

But don't worry. I believe no problem can stump my Stack Overflow, so I searched a bunch of keywords, tried four or five methods provided by helpful netizens, and sure enough found the best solution...

Filtering Multiple Values at Once

First, define a custom Filter. Here I use commas to split each parameter. The code is as follows:

from django_filters import Filter,FilterSet

class ListFilter(Filter):
    def filter(self, qs, value):
        if not value:
            return qs
        # For django-filter versions < 0.13, use lookup_type instead of lookup_expr
        self.lookup_expr = 'in'
        values = value[0:1000].split(',')
        return super(ListFilter, self).filter(qs, values)

class RequireStatusFilter(FilterSet):
    require_statuses = ListFilter(field_name='require_status')
    class Meta:
        from apps.require.models import Require
        model = Require
        fields = ['require_statuses', 'region']

Then modify our ViewSet. You can see that filter_fields is no longer needed, because it's already defined in RequireStatusFilter

class RequireViewSet(viewsets.ModelViewSet):
    """需求记录"""
    serializer_class = RequireSerializer
    queryset = Require.objects.all()
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filter_class = RequireStatusFilter
    search_fields = ['keyword']

How to Use

Absolutely delightful

http://127.0.0.1/require/?region=1&require_status=1,2,3,4,5,6,7,8,9

Gossip

Finally, a bit of gossip: today the father of Python tweeted that he joined Microsoft, and the father of Delphi/C#/TypeScript posted congratulations in the comments, hahaha

References

_EOF_

Introduction to Django-Filter and How to Implement Tricky Requirements

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

轻量级消息队列Django-Q轻度体验

前言 最近做的这个项目(基于Django),需要做个功能,实现定时采集车辆定位。 这让我想起来几年前那个OneCat项目,当时我用的是Celery这个很重的组件 Celery实在是太重了,后来我做公众号采集平台的时候,又接触了Django-RQ和Django-Q这俩,前者是对RQ的封装,让RQ和Django更好的结合在一起;后者是一个全新的「多进程任务队列」组件,相比起celery很轻量,当时使用

2022-08-31 · Django · 约 1 分钟

给Django的Admin添加自定义Action-并移除需要选择对象的限制

前言 不得不说,Django的Admin真的给开发带来很多便利,这不,我又来折腾了,这次是添加自定义的action 这个自定义的Action可以看看官方文档的介绍,很详细,不再赘述。 https://docs.djangoproject.com/en/3.0/ref/contrib/admin/actions/ 界面效果 Django默认的添加完action是要选择下面的对象才能提交的,不过我不需

2022-08-26 · Django · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…