繁体   English   中英

在Django中搜索多个型号

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM