11# 过滤条件
22
3- SQLAlchemy CRUD Plus 支持 30+ 种过滤操作符,用于构建复杂的查询条件。
4-
5- ## 基础用法
6-
7- ``` python
8- # 使用过滤条件查询
9- users = await user_crud.select_models(
10- session,
11- name = " 张三" , # 等于
12- age__gt = 18 , # 大于
13- email__like = " %@qq.com" # 模糊匹配
14- )
15- ```
16-
17- ## 比较操作符
3+ 过滤条件通过关键字参数传入:` 字段名__操作符=值 ` 。没有操作符时表示等于,例如 ` name='张三' ` 。
184
195``` python
20- # 数值比较
216users = await user_crud.select_models(
227 session,
23- age__gt = 30 , # 大于 30
24- age__ge = 18 , # 大于等于 18
25- age__lt = 65 , # 小于 65
26- age__le = 60 , # 小于等于 60
27- id__eq = 1 , # 等于 1
28- status__ne = 0 # 不等于 0
8+ name__like = ' %张%' ,
9+ age__ge = 18 ,
10+ is_active = True
2911)
3012```
3113
32- ## 范围操作符
33-
34- ``` python
35- # 包含查询
36- users = await user_crud.select_models(
37- session,
38- id__in = [1 , 2 , 3 , 4 , 5 ], # ID 在列表中
39- status__not_in = [0 , - 1 ], # 状态不在列表中
40- age__between = [18 , 65 ] # 年龄在 18-65 之间
41- )
42- ```
14+ ## 常用操作符
4315
44- ## 字符串操作符
16+ | 类型 | 操作符 | 示例 | 说明 |
17+ | --- | --- | --- | --- |
18+ | 等值 | 无 / ` __eq ` | ` name='张三' ` 、` id__eq=1 ` | 等于 |
19+ | 比较 | ` __gt ` / ` __ge ` | ` age__gt=18 ` | 大于 / 大于等于 |
20+ | 比较 | ` __lt ` / ` __le ` | ` age__le=60 ` | 小于 / 小于等于 |
21+ | 不等 | ` __ne ` | ` status__ne=0 ` | 不等于 |
22+ | 集合 | ` __in ` / ` __not_in ` | ` id__in=[1, 2] ` | 在 / 不在列表中 |
23+ | 范围 | ` __between ` | ` age__between=[18, 65] ` | 闭区间范围 |
24+ | 字符串 | ` __like ` / ` __not_like ` | ` name__like='%张%' ` | LIKE / NOT LIKE |
25+ | 字符串 | ` __ilike ` / ` __not_ilike ` | ` name__ilike='%admin%' ` | 忽略大小写匹配 |
26+ | 字符串 | ` __startswith ` | ` email__startswith='admin' ` | 前缀匹配 |
27+ | 字符串 | ` __endswith ` | ` email__endswith='@example.com' ` | 后缀匹配 |
28+ | 字符串 | ` __contains ` | ` bio__contains='Python' ` | 包含 |
29+ | 空值 | ` __is ` / ` __is_not ` | ` deleted_at__is=None ` | IS / IS NOT |
4530
46- ``` python
47- # 字符串匹配
48- users = await user_crud.select_models(
49- session,
50- name__like = ' %张%' , # 包含"张"
51- name__not_like = ' %test%' , # 不包含"test"
52- name__ilike = ' %ADMIN%' , # 不区分大小写包含
53- email__startswith = ' admin' , # 以"admin"开头
54- email__endswith = ' @qq.com' , # 以"@qq.com"结尾
55- bio__contains = ' 程序员' , # 包含"程序员"
56- )
57- ```
31+ ## OR 条件
5832
59- ## 空值检查
33+ 使用特殊键 ` __or__ ` 表示 OR。外层其他条件仍然是 AND。
6034
6135``` python
62- # NULL 值处理
63- users = await user_crud.select_models(
64- session,
65- deleted_at__is = None , # 为 NULL
66- profile_id__is_not = None , # 不为 NULL
67- )
68- ```
69-
70- ## OR 条件查询
71-
72- ### 同字段多值
73-
74- ``` python
75- # 邮箱域名为 gmail.com 或 qq.com 的用户
76- users = await user_crud.select_models(
77- session,
78- __or__ = {
79- ' email__endswith' : [' @gmail.com' , ' @qq.com' ]
80- }
81- )
82- ```
83-
84- ### 不同字段条件
85-
86- ``` python
87- # 名字包含"张"或邮箱以admin开头的用户
36+ # 名称包含“张”,或邮箱以 admin 开头。
8837users = await user_crud.select_models(
8938 session,
9039 __or__ = {
@@ -94,192 +43,76 @@ users = await user_crud.select_models(
9443)
9544```
9645
97- ### 复杂 OR 条件
46+ 同一个字段需要多个 OR 值时,传列表:
9847
9948``` python
100- # 多种条件组合
10149users = await user_crud.select_models(
10250 session,
103- is_active = True , # 必须是活跃用户
51+ is_active = True ,
10452 __or__ = {
105- ' level__ge' : 5 , # 等级大于等于5
106- ' is_vip' : True , # 或者是VIP
107- ' total_spent__gt' : 1000 # 或者消费大于1000
53+ ' email__endswith' : [' @gmail.com' , ' @qq.com' ]
10854 }
10955)
11056```
11157
112- ## 操作符参考
113-
114- ### 比较操作符
115-
116- | 操作符 | 说明 | 示例 |
117- | --------| ------| ----------------|
118- | ` __gt ` | 大于 | ` age__gt=18 ` |
119- | ` __ge ` | 大于等于 | ` age__ge=18 ` |
120- | ` __lt ` | 小于 | ` age__lt=65 ` |
121- | ` __le ` | 小于等于 | ` age__le=65 ` |
122- | ` __eq ` | 等于 | ` id__eq=1 ` |
123- | ` __ne ` | 不等于 | ` status__ne=0 ` |
124-
125- ### 包含操作符
126-
127- | 操作符 | 说明 | 示例 |
128- | -------------| -------| ------------------------|
129- | ` __in ` | 在列表中 | ` id__in=[1,2,3] ` |
130- | ` __not_in ` | 不在列表中 | ` id__not_in=[1,2,3] ` |
131- | ` __between ` | 在范围内 | ` age__between=[18,65] ` |
132-
133- ### 字符串操作符
134-
135- | 操作符 | 说明 | 示例 |
136- | ----------------| -------------| -----------------------------|
137- | ` __like ` | 模糊匹配 | ` name__like='%张%' ` |
138- | ` __not_like ` | 模糊不匹配 | ` name__not_like='%test%' ` |
139- | ` __ilike ` | 不区分大小写模糊匹配 | ` name__ilike='%ZHANG%' ` |
140- | ` __not_ilike ` | 不区分大小写模糊不匹配 | ` name__not_ilike='%TEST%' ` |
141- | ` __startswith ` | 开头匹配 | ` email__startswith='admin' ` |
142- | ` __endswith ` | 结尾匹配 | ` email__endswith='@qq.com' ` |
143- | ` __contains ` | 包含 | ` name__contains='张' ` |
144-
145- ### 空值操作符
146-
147- | 操作符 | 说明 | 示例 |
148- | ------------| -------| ---------------------------|
149- | ` __is ` | 为空检查 | ` deleted_at__is=None ` |
150- | ` __is_not ` | 不为空检查 | ` deleted_at__is_not=None ` |
151-
152- ## 实际应用示例
153-
154- ### 用户搜索功能
58+ ## 组合示例
15559
15660``` python
157- async def search_users (
158- session : AsyncSession,
159- keyword : str = None ,
160- age_min : int = None ,
161- age_max : int = None ,
162- is_active : bool = None
163- ):
164- filters = {}
61+ async def search_users (session : AsyncSession, keyword : str | None = None ):
62+ filters = {' is_active' : True }
16563
166- # 关键词搜索(姓名或邮箱)
16764 if keyword:
16865 filters[' __or__' ] = {
16966 ' name__like' : f ' % { keyword} % ' ,
17067 ' email__like' : f ' % { keyword} % '
17168 }
17269
173- # 年龄范围
174- if age_min is not None :
175- filters[' age__ge' ] = age_min
176- if age_max is not None :
177- filters[' age__le' ] = age_max
178-
179- # 状态筛选
180- if is_active is not None :
181- filters[' is_active' ] = is_active
182-
183- return await user_crud.select_models(session, ** filters)
70+ return await user_crud.select_models(
71+ session,
72+ ** filters,
73+ limit = 20
74+ )
18475```
18576
186- ### 高级筛选
187-
18877``` python
189- # 查找活跃的高级用户
190- users = await user_crud.select_models(
78+ users = await user_crud.select_models_order(
19179 session,
192- is_active = True ,
80+ sort_columns = ' created_at' ,
81+ sort_orders = ' desc' ,
19382 created_at__ge = ' 2024-01-01' ,
194- __or__ = {
195- ' level__ge' : 5 ,
196- ' is_vip' : True ,
197- ' total_orders__gt' : 10
198- }
83+ age__between = [18 , 65 ],
84+ status__not_in = [' blocked' , ' deleted' ]
19985)
20086```
20187
202- ## 复合主键支持
203-
204- SQLAlchemy CRUD Plus 自动检测模型主键,支持单个主键和复合主键。
88+ ## 复合主键
20589
206- ### 复合主键模型
90+ CRUDPlus 会自动识别单主键和复合主键。复合主键查询、更新、删除时用元组传入 ` pk ` 。
20791
20892``` python
20993class UserRole (Base ):
21094 __tablename__ = ' user_roles'
21195
212- # 复合主键
21396 user_id: Mapped[int ] = mapped_column(primary_key = True )
21497 role_id: Mapped[int ] = mapped_column(primary_key = True )
215- assigned_at: Mapped[datetime] = mapped_column(DateTime)
21698```
21799
218- ### 复合主键操作
219-
220100``` python
221- # 创建
222- user_role_data = UserRoleCreate(user_id = 1 , role_id = 2 )
223- user_role = await user_role_crud.create_model(session, user_role_data)
224-
225- # 查询(使用元组)
226101user_role = await user_role_crud.select_model(session, pk = (1 , 2 ))
227102
228- # 更新
229103await user_role_crud.update_model(
230104 session,
231105 pk = (1 , 2 ),
232- obj = {" assigned_at " : datetime.now() }
106+ obj = {' role_name ' : ' admin ' }
233107)
234108
235- # 删除
236109await user_role_crud.delete_model(session, pk = (1 , 2 ))
237-
238- # 批量查询
239- user_roles = await user_role_crud.select_models(session, user_id = 1 )
240110```
241111
242112## 性能建议
243113
244- ### 索引优化
245-
246- ``` python
247- # 为常用查询字段创建索引
248- class User (Base ):
249- __tablename__ = ' users'
250-
251- email: Mapped[str ] = mapped_column(String(100 ), unique = True , index = True )
252- is_active: Mapped[bool ] = mapped_column(default = True , index = True )
253- created_at: Mapped[datetime] = mapped_column(DateTime, index = True )
254-
255- # 复合索引
256- __table_args__ = (
257- Index(' idx_user_active_created' , ' is_active' , ' created_at' ),
258- )
259- ```
260-
261- ### 查询优化技巧
262-
263- ``` python
264- # 使用 exists 检查存在性(更高效)
265- exists = await user_crud.exists(session, email = " test@example.com" )
266-
267- # 使用 limit 限制结果集
268- recent_users = await user_crud.select_models(
269- session,
270- created_at__ge = datetime.now() - timedelta(days = 7 ),
271- limit = 100
272- )
273-
274- # 避免前缀通配符(低效)
275- # 不推荐: name__like='%张%'
276- # 推荐: name__like='张%'
277- ```
278-
279- ## 注意事项
280-
281- 1 . ** 参数命名** : 主键参数使用 ` pk ` ,避免与常见字段名 ` id ` 混淆
282- 2 . ** 自动主键检测** : 支持各种主键类型,包括字符串主键和复合主键
283- 3 . ** 性能考虑** : 为常用过滤字段创建数据库索引
284- 4 . ** OR 查询** : 过多 OR 条件可能影响性能,合理使用
285- 5 . ** 通配符** : 避免以通配符开头的 LIKE 查询
114+ - 常用过滤字段应建立索引,例如 ` email ` 、` status ` 、` created_at ` 。
115+ - ` exists() ` 比查询整条记录更适合做存在性检查。
116+ - 列表查询务必配合 ` limit ` ,避免一次加载过多数据。
117+ - ` LIKE '%keyword%' ` 通常无法有效利用普通索引;能用前缀匹配时优先 ` LIKE 'keyword%' ` 。
118+ - OR 条件过多时,建议评估 SQL 执行计划。
0 commit comments