Django:如何通过「参数包含字段部分值」过滤QuerySet?
如何用包含模型字段值的查询参数过滤Django的Place对象
首先提个小细节:你定义的Place模型里CharField必须指定max_length,否则Django会抛出错误,修正后的模型如下:
class Place(models.Model): name = models.CharField(max_length=255) # 必填max_length参数
回到你的核心需求:你有一批带后缀的查询字符串(比如Starbucks Pike Place),需要找出所有Place对象,使得查询字符串包含该对象的name字段值(比如匹配到name="Starbucks"的记录)。下面给你几种实用的实现方式:
方法一:简单遍历法(适合数据量小的场景)
这种方法直观易懂,不需要复杂的ORM操作,直接遍历就能实现:
# 假设你的查询参数列表是这样的 query_strings = [ "Starbucks Pike Place", "McDonald's Sand Lake Road", "Another Starbucks Out There" ] matched_places = [] # 遍历所有Place对象 for place in Place.objects.all(): # 转成小写实现不区分大小写匹配,不需要的话可以去掉.lower() place_name = place.name.lower() # 检查当前Place的name是否存在于任意一个查询字符串中 for query in query_strings: if place_name in query.lower(): matched_places.append(place) break # 匹配到就跳出循环,避免重复添加 # 去重(因为可能多个查询字符串匹配同一个Place) matched_places = list(set(matched_places))
方法二:用Q对象构建ORM查询(适合数据量中等的场景)
如果不想遍历所有对象,可以用Django的Q对象构建OR查询条件,直接在数据库层面过滤:
from django.db.models import Q query_strings = [ "Starbucks Pike Place", "McDonald's Sand Lake Road", "Another Starbucks Out There" ] # 初始化空的查询条件 q_conditions = Q() # 遍历每个查询字符串,收集匹配的name条件 for query in query_strings: # 先获取所有Place的name,检查是否在当前查询字符串里 for place_name in Place.objects.values_list('name', flat=True): if place_name in query: q_conditions |= Q(name=place_name) # 执行查询并去重 matched_places = Place.objects.filter(q_conditions).distinct()
方法三:利用数据库字符串函数(适合数据量大的场景)
如果你的数据库支持特定的字符串定位函数,可以直接在ORM中调用,查询效率会更高:
PostgreSQL(用STRPOS函数)
from django.db.models import Func, Value, Q class StrPos(Func): function = 'STRPOS' output_field = models.IntegerField() query_strings = [ "Starbucks Pike Place", "McDonald's Sand Lake Road", "Another Starbucks Out There" ] q_conditions = Q() for query in query_strings: # STRPOS(query, name) > 0 表示name是query的子串 q_conditions |= Q(name__isnull=False, strpos=StrPos(Value(query), 'name') > 0) matched_places = Place.objects.filter(q_conditions).distinct()
MySQL(用LOCATE函数)
把上面的StrPos类改成:
class Locate(Func): function = 'LOCATE' output_field = models.IntegerField()
然后用Locate(Value(query), 'name') > 0即可。
SQLite(用INSTR函数)
改成:
class Instr(Func): function = 'INSTR' output_field = models.IntegerField()
使用Instr(Value(query), 'name') > 0。
注意事项
- 如果需要忽略大小写的匹配,在方法一、二中可以统一转成小写;在方法三中,需要用数据库的大小写不敏感函数(比如PostgreSQL的
strpos(lower(query), lower(name)))。 - 如果你的
Place表数据量很大,方法一的遍历效率会很低,优先选择方法二或三。
内容的提问来源于stack exchange,提问作者akwataip
相关产品推荐
相关产品推荐

