我在这里使用的方法并非是官方使用的方案,但仍然可以实现,如果想使用官方的方法,请到文末查看官方文档中的使用方式
问题背景
在Web应用当中,尤其是后台管理应用,经常遇到的一个场景是,需要根据用户的输入条件,在数据库中查询相应数据并展示。 那让我们看看在Django中如何处理?
先看看官网的介绍
https://docs.djangoproject.com/en/1.11/topics/db/queries/
官网介绍的很详细, 我就不重复粘贴复制了, 在这里只记录一下一个典型的使用场景.
场景描述
有一个关于书本信息的数据表, 包括书本的书名,价格,出版社,ISBN,作者。Model定义如下:
class Book(models.Model):name = models.CharField(max_length=48)isbn = models.IntegerField(primary_key=True, unique=True)author = models.CharField(max_length=24)press = models.CharField(max_length=48)price = models.PositiveIntegerField(default=0)
在书本管理后台,需要实现根据用户输入的作者信息,进行模糊查询。 前端通过ajax POST将表单信息传送给后台。Django在收到请求之后,在view当中调用如下函数就可以进行数据库的查找过滤操作呢。 其中icontains表示忽略大小写的模糊查询。
def filter_books(objects, request):filter_author = request.POST['author']if (filter_author):objects = objects.filter(author__icontains=filter_author)return objects
Django支持的查询方式有很多, 具体请查看以下官网介绍:
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#field-lookups
一切看起来都不错,有什么不妥?
目前看起来确实没有什么不妥,但是当定义的model多了, 要查询的表单多了之后, 相关的代码片段就变成了下面这样:
def filter_libooks(objects, request):filter_status = request.POST['status']filter_uuid = request.POST['uuid']filter_isbn = request.POST['isbn']filter_name = request.POST['name']if (filter_status):objects = objects.filter(status=filter_status)if (filter_isbn):objects = objects.filter(book__isbn__contains=filter_isbn)if (filter_name):objects = objects.filter(book__name__contains=filter_name)if (filter_uuid):objects = objects.filter(uuid_contains=filter_uuid)return objectsdef filter_books(objects, request):filter_author = request.POST['author']filter_press = request.POST['press']filter_isbn = request.POST['isbn']filter_name = request.POST['name']if (filter_author):objects = objects.filter(author__contains=filter_author)if (filter_press):objects = objects.filter(press__contains=filter_press)if (filter_isbn):objects = objects.filter(isbn__contains=filter_isbn)if (filter_name):objects = objects.filter(name__contains=filter_name)return objects
代码重复的好像有点多, 虽然粘贴复制并不废什么功夫, 但是看起来心情就不是特别美丽。在这个时候, django_filters 就闪亮登场呢。
安装
pip install djangoresframeworkpip install djangopip install django-filter
配置
后台注册
INSTALLED_APPS = ["""其他注册应用"""'rest_framework.apps.RestFrameworkConfig','django_filters',]
应用
model.py
from django.db import modelsclass Book(models.Model):id = models.BigAutoField(primary_key=True)name = models.CharField(max_length=48)isbn = models.CharField(max_length=100)author = models.CharField(max_length=24)press = models.CharField(max_length=48)price = models.PositiveIntegerField(default=0)class Meta:db_table = "BookInfo"verbose_name = "BookInfo"verbose_name_plural = verbose_name
ModelSerializer.py
from rest_framework import serializersfrom .models import Bookclass Book_serializers(serializers.ModelSerializer):class Meta:model = Bookfields = '__all__'
ModelPagination.py
# -*- coding: utf-8 -*-# @Time : 2021/1/25 上午12:18# @Author : void bug# @FileName: BooksPagination.py# @Software: PyCharmfrom rest_framework.pagination import PageNumberPaginationclass BooksPagination(PageNumberPagination):page_size = 4 # 表示每页的默认显示数量page_size_query_param = 'page_size' # 表示url中每页数量参数page_query_param = 'p' # 表示url中的页码参数max_page_size = 100000e100000 # 表示每页最大显示数量,做限制使用,避免突然大量的查询数据,数据库崩溃
ModelView.py
from django_filters.rest_framework import DjangoFilterBackendfrom rest_framework import viewsetsfrom .BooksPagination import BooksPaginationfrom .models import Bookfrom .serializer import Book_serializersclass BooksView(viewsets.ModelViewSet):"""图书查询"""queryset = Book.objects.all()serializer_class = Book_serializerspagination_class = BooksPagination# 筛选配置filter_backends = [DjangoFilterBackend] #应用筛选器filter_fields = ('name', 'author', 'isbn', 'press') # 筛选字段,其中括号内为应用筛选的字段
urls.py
from django.urls import path, includefrom .views import BooksViewfrom rest_framework import routersMy_Views = routers.DefaultRouter()My_Views.register('Book', BooksView, basename="BookInfo")urlpatterns = [path('', include(My_Views.urls)),]
应用截图
筛选前
筛选后
进阶使用
- 我们在使用时,进场遇到说用到的in,exact 等查询操作,及比较高级的筛选,我们到现在为止我们只能实现说精确的查询,但是无法满足说比较高级的查询操作,我们现在开始一些进阶
- 相关的操作请参照以下说明
Django QuerySet常用的字段查询
contains就属于字段查询。
- contains:包含,用来进行相似查询
- icontains:同contains,只是忽略大小写
- exact:精确匹配
- iexact:同exact,忽略大小写
- in:指定某个集合,比如Post.objects.filter(id__in=[1,2,3]),相当于SELECT * FROM blog_post WHERE IN (1,2,3)
- gt:大于某值
- gte:大于等于某值
- lt:小于某值
- lte:小于等于某值
- startswith:以某个字符串开头,与contains类似,只是会产生LIKE
- istartswith:同startswith,忽略大小写
- endswith:以某个字符串结尾
- iendswith:同endswith,忽略大小写
- range:范围查询,多用于时间范围,如Post.objects.filter(created_time_range=(‘2020-06-01’,’2020-06-28’))
那么我们应该如何进行修改呢
我们对 ModelView.py 进行一点修改即可
class UserViewSets(ModelViewSet):queryset = UserModels.objects.all()serializer_class = UserListSerializerspagination_class = BasePaginationfilter_backends = [DjangoFilterBackend]filter_fields = {"UserName": ['exact', 'lt', 'gt', "in", "contains"], "phone": ['exact', 'lt', 'gt', "in", "contains"]}
我们现在看下运行结果
- 特别说明,我们使用 in 操作时,使用,(逗号)进行分割
总结
官方文档

