【Django-ninja】django ninja中使用查询过滤器FilterSchema

Django ORM中过滤器

filter的基本用法

filter() 是 QuerySet 对象的一个方法,用于从数据库中过滤数据。它接受一个或多个关键字参数,每个参数都表示一个查询条件,它们之间是 AND 关系。

以下是 filter() 方法的基本用法示例:

python 复制代码
from myapp.models import MyModel

# 查询所有 name 字段值为 'John' 的记录
results = MyModel.objects.filter(name='John')

# 查询所有 age 大于等于 25 的记录
results = MyModel.objects.filter(age__gte=25)

# 多个条件的 AND 关系
results = MyModel.objects.filter(name='John', age__gte=25)

# 使用 OR 条件,使用 Q 对象
from django.db.models import Q
results = MyModel.objects.filter(Q(name='John') | Q(age__gte=25))

上述示例中,MyModel 是一个数据库模型,filter() 方法用于根据指定的查询条件过滤数据库中的记录。其中:
2. (1) name='John' 表示查询 name 字段等于 'John' 的记录。

  1. (2) age__gte=25 表示查询 age 字段大于等于 25 的记录。

  2. (3) 多个条件之间是 AND 关系,即同时满足所有条件。

  3. (4) 使用 Q 对象可以实现 OR 关系,其中 Q(name='John') | Q(age__gte=25) 表示查询 name 字段等于 'John' 或 age 字段大于等于 25 的记录。

**Django中的常用过滤器

基本查询过滤器:**

  • exact: 等于,例如 field__exact=value
  • iexact: 不区分大小写的等于,例如 field__iexact=value
  • contains: 包含,例如 field__contains=value
  • icontains: 不区分大小写的包含,例如 field__icontains=value
  1. 范围查询过滤器:

    • gt: 大于,例如 field__gt=value
    • lt: 小于,例如 field__lt=value
    • gte: 大于等于,例如 field__gte=value
    • lte: 小于等于,例如 field__lte=value
  2. 空值查询过滤器:

    • isnull: 是否为空,例如 field__isnull=True
  3. IN 查询过滤器:

    • in: 在某个列表中,例如 field__in=[value1, value2]
  4. 日期查询过滤器:

    • date: 根据日期进行查询,例如 pub_date__date=some_date, pub_date__contains="2024-01"
  5. 时间查询过滤器:

    • time: 根据时间进行查询,例如 pub_time__time=some_time
  6. 外键查询过滤器:

    • ForeignKeyField__fieldname: 对于外键关系,可以使用 __ 来查询相关字段,例如 author__name__icontains=value
  7. 组合查询过滤器:

    • &(与)和 |(或):可以使用 &| 符号来组合多个查询条件,例如 Q(field1=value1) | Q(field2=value2)

2. django-ninja过滤器FilterSchema的用法

为什么已经有了Django ORM中的filter函数,还有整出个Django-ninja过滤器呢?

因为一般来说,从客户端用户发来一个请求,往往会带有很多查询参数。通过查询参数,在数据库中查找对应的记录。这些查询参数往往也并不是固定的。

如果我们直接通过手写代码构造filter需要的过滤条件,代码会相当丑陋,变得很难维护。

django-nina过滤器FilterSchema的作用就是对用户查询条件到数据库查询条件这一个过程的封装。

Django ORM的filter关心数据库的数据,而Django Ninja的过滤器关心用户与我们网站互动的方式。

2.1 基础用法

python 复制代码
from ninja import FilterSchema, Field
from typing import Optional


class BookFilterSchema(FilterSchema):
    name: Optional[str] = None
    author: Optional[str] = None
    created_after: Optional[datetime] = None
python 复制代码
@api.get("/books")
def list_books(request, filters: BookFilterSchema = Query(...)):
    books = Book.objects.all()
    books = filters.filter(books)
    return books

2.2 一个稍微复杂一点的用法

自定义的过滤器继承FilterSchema。

  1. filter_title_list方法用于处理title_list参数
python 复制代码
class BookFilterSchema(FilterSchema):
    """ 过滤器用于从用户的请求参数,转化为查询的过滤条件。
    1. 默认使用类pub_date, title等字段进行过滤
    2. 如果不能满足条件,可以使用自定义的函数对某一个参数编写函数进行过滤,函数名称使用filter_开头
    3. 如果还不能满足要求,可以使用custom_expression定义一个完整的过滤查询器。这时候其他内置的
        查询条件都会被忽略掉。
    """
    pub_date: date = Field(None)  # 默认值为None,不使用这个过滤器
    # title__in: List[str] = Field(None, alias="titles")
    title: str = Field(None)
    title_list: str = Field(None)  # 传输参数
    search: Optional[str] = Field(None, q=['title__icontains',
                                           'pub_date__date'])

    def custom_expression(self) -> Q:
        """ 该函数如果定义了,将会被用作这个过滤器的自定义条件。其他所有的都会被忽略。"""
        q = Q()
        if self.title_list:
            titles = self.title_list.split(",")
            q = q & Q(title__in=titles)
        if self.title:
            q = q & Q(title=self.title)
        if self.pub_date:
            q = q & Q(pub_date=self.pub_date)
        if self.search:
            # sq = Q(title__icontains=self.search) | Q(pub_date__contains = Value(self.search, output_field=CharField()))
            sq = Q(title__icontains=self.search) | Q(pub_date__contains=self.search)
            q = q | sq
        return q

    def filter_title_list(self, value: str) -> Q:
        """自定义的过滤器函数,对传入的title_list字段转换成查询语句。
        title_list会使用','进行切割,生产过滤条件。"""
        if value:
            titles = value.split(",")
            return Q(title__in=titles)
        else:
            return Q()

@demo_api.get("/filter")
def events(request, filters: BookFilterSchema = Query(...)):  #
    books = Book.objects.all()
    print(filters.custom_expression())
    books = filters.filter(books)
    return ResponseSchema(data=books)

2.3 POST请求同时使用Path, Query, Body的示例

post请求可以包含Path,Query, Body等多个输入。下面的示例给出了继承Schema规整化这些输入。如果需要将相应的输入应用成过滤器,需要继承FilterSchema,编写相应的过滤方法。

python 复制代码
import datetime 

from ninja import NinjaAPI, Schema, UploadedFile, Form, File, Query, FilterSchema, Router, Path, Body


class DogSchema(Schema):
    # name: str
    dog_type: str
    age: int


class PathDate(Schema):
    year: int
    month: int
    day: int

    def value(self):
        return datetime.date(self.year, self.month, self.day)


@demo_api.post("/dog_mix_post/{year}/{month}/{day}")
def dog_mix_post(request, path: Path[PathDate], dog_item: DogSchema = Query(...), dog_item_body: DogSchema = Body(...)):
    """ name是路径参数;item是请求参数。"""
    return {"path": path.value(),
            "query": dog_item.dict(),
            "body": dog_item_body}
相关推荐
天水幼麟2 分钟前
python学习笔记(深度学习)
笔记·python·学习
巴里巴气5 分钟前
安装GPU版本的Pytorch
人工智能·pytorch·python
wt_cs26 分钟前
银行回单ocr api集成解析-图像文字识别-文字识别技术
开发语言·python
_WndProc1 小时前
【Python】Flask网页
开发语言·python·flask
互联网搬砖老肖1 小时前
Python 中如何使用 Conda 管理版本和创建 Django 项目
python·django·conda
深栈解码1 小时前
JMM深度解析(三) volatile实现机制详解
java·后端
张家宝68371 小时前
ambari
后端
测试者家园1 小时前
基于DeepSeek和crewAI构建测试用例脚本生成器
人工智能·python·测试用例·智能体·智能化测试·crewai
StephenCurryFans1 小时前
Spring AI vs LangChain4j:Java AI开发框架完整对比指南 🚀
后端·spring
程序员辉哥1 小时前
学会在Cursor中使用Rules生成代码后可以躺平了吗?
前端·后端