[英]Search in multiple models in Django
我在 Django 中有许多不同的型号,我想在所有型号中搜索关键字。 例如,如果您搜索“blah”,我想显示所有带有“blah”的产品,所有带有“blah”的发票,最后是所有其他带有“blah”的型号。
我可以单独开发一个视图并在所有模型中进行搜索,但这不是一个好主意。
这种情况的最佳做法是什么?
我遇到过几次这种情况,一种解决方案是使用 model 管理器,并为单词和多词查询创建不同的搜索方法。 以下面的示例模型为例: 每个模型都有自己的自定义 Model Manager,具有两种独立的查询方法。 search
将针对所有字段查询单词搜索,而search_and
将查询搜索词列表中的每个词,使用reduce
function。两者都使用Q
对象来完成多字段查找。
from functools import reduce
from django.db.models import Q
class ProductQuerySet(models.QuerySet):
def search(self, query=None):
qs = self
if query is not None:
or_lookup = (Q(product_name__icontains=query) |
Q(description__icontains=query) |
Q(category__icontains=query))
qs = qs.filter(or_lookup, active=True, released=True).distinct()
return qs
def search_and(self, query=None):
qs = self
if query is not None:
or_lookup = reduce(lambda x, y: x & y, [(Q(product_name__icontains=word) |
Q(description__icontains=word) |
Q(category__icontains=word)) for word in query])
qs = qs.filter(or_lookup, active=True, released=True).distinct()
return qs
class ProductManager(models.Manager):
def get_queryset(self):
return ProductQuerySet(self.model, using=self._db)
def search(self, query=None):
return self.get_queryset().search(query=query)
def search_and(self, query=None):
return self.get_queryset().search_and(query=query)
class Product(models.Model):
product_name = models.CharField(max_length=200)
description = models.CharField(max_length=240, blank=True, null=True)
category = models.CharField(max_length=100, choices=CATEGORY)
objects = ProductManager()
def __str__(self):
return self.product_name
class ProfileQuerySet(models.QuerySet):
def search(self, query=None):
qs = self
if query is not None:
or_lookup = (Q(full_name__icontains=query) |
Q(job_title__icontains=query) |
Q(function__icontains=query))
qs = qs.filter(or_lookup, active=True, released=True).distinct()
return qs
def search_and(self, query=None):
qs = self
if query is not None:
or_lookup = reduce(lambda x, y: x & y, [(Q(full_name__icontains=word) |
Q(job_title__icontains=word) |
Q(function__icontains=word)) for word in query])
qs = qs.filter(or_lookup, active=True, released=True).distinct()
return qs
class ProfileManager(models.Manager):
def get_queryset(self):
return ProfileQuerySet(self.model, using=self._db)
def search(self, query=None):
return self.get_queryset().search(query=query)
def search_and(self, query=None):
return self.get_queryset().search_and(query=query)
class Profile(models.Model):
full_name = models.CharField(max_length=200)
job_title = models.CharField(max_length=240, blank=True, null=True)
function = models.CharField(max_length=100, choices=FUNCTION)
objects = ProfileManager()
def __str__(self):
return self.full_name
现在在搜索视图中使用这些,您可以根据需要指向任意多个 model 经理,它可以查询任意多个字段。 使用上面的示例模型,下面是一个示例视图。 它根据术语数(1 个或多于 1 个)将一个或多个搜索术语传递给相应的 model 管理器方法。
def application_search(request):
data = dict()
if 'query' in request.GET:
query_list = request.GET.get("query", None).split()
if query_list:
try:
if len(query_list) > 1:
products = Product.objects.search_and(query=query_list)
profiles = Profile.objects.search_and(query=query_list)
else:
products = Product.objects.search(query=query_list[0])
profiles = Profile.objects.search(query=query_list[0])
except:
# Throw exception or log error here
try:
queryset_chain = chain(products, profiles) # combines querysets into one
results = sorted(queryset_chain, key=lambda instance: instance.id, reverse=True) #sorts results by ID
except:
results = None
data['results'] = render_to_string('pages/my_search_result_page.html', {'results': results})
return JsonResponse(data)
此视图中的query
实际上是通过 AJAX 传递到后端的,但是您可以根据您的需要和模板设计进行不同的操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.