我在这里使用的方法并非是官方使用的方案,但仍然可以实现,如果想使用官方的方法,请到文末查看官方文档中的使用方式
问题背景
在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 objects
def 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 djangoresframework
pip install django
pip install django-filter
配置
后台注册
INSTALLED_APPS = [
"""
其他注册应用
"""
'rest_framework.apps.RestFrameworkConfig',
'django_filters',
]
应用
model.py
from django.db import models
class 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 serializers
from .models import Book
class Book_serializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = '__all__'
ModelPagination.py
# -*- coding: utf-8 -*-
# @Time : 2021/1/25 上午12:18
# @Author : void bug
# @FileName: BooksPagination.py
# @Software: PyCharm
from rest_framework.pagination import PageNumberPagination
class 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 DjangoFilterBackend
from rest_framework import viewsets
from .BooksPagination import BooksPagination
from .models import Book
from .serializer import Book_serializers
class BooksView(viewsets.ModelViewSet):
"""
图书查询
"""
queryset = Book.objects.all()
serializer_class = Book_serializers
pagination_class = BooksPagination
# 筛选配置
filter_backends = [DjangoFilterBackend] #应用筛选器
filter_fields = ('name', 'author', 'isbn', 'press') # 筛选字段,其中括号内为应用筛选的字段
urls.py
from django.urls import path, include
from .views import BooksView
from rest_framework import routers
My_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 = UserListSerializers
pagination_class = BasePagination
filter_backends = [DjangoFilterBackend]
filter_fields = {"UserName": ['exact', 'lt', 'gt', "in", "contains"], "phone": ['exact', 'lt', 'gt', "in", "contains"]}
我们现在看下运行结果
- 特别说明,我们使用 in 操作时,使用,(逗号)进行分割
总结
官方文档