简体   繁体   English

在Django中搜索多个型号

[英]Search in multiple models in Django

I have many different models in Django and I want to search for a keyword in all of them.我在 Django 中有许多不同的型号,我想在所有型号中搜索关键字。 For example, if you searched "blah", I want to show all of the products with "blah", all of the invoices with "blah", and finally all of the other models with "blah".例如,如果您搜索“blah”,我想显示所有带有“blah”的产品,所有带有“blah”的发票,最后是所有其他带有“blah”的型号。

I can develop a view and search in all of the models separately, but it's not a good idea.我可以单独开发一个视图并在所有模型中进行搜索,但这不是一个好主意。

What is the best practice for this situation?这种情况的最佳做法是什么?

I've run into this situation a few times and one solution is to use model managers, and create distinct search methods for single and multi-word queries.我遇到过几次这种情况,一种解决方案是使用 model 管理器,并为单词和多词查询创建不同的搜索方法。 Take the following example models below: Each has its own custom Model Manager, with two separate query methods.以下面的示例模型为例: 每个模型都有自己的自定义 Model Manager,具有两种独立的查询方法。 search will query single-word searches against all fields, while search_and will query each word in a list of search words, using the reduce function. Both use Q objects to accomplish multi-field lookups. 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

Now to use these in a search view, which you can point at as many model managers as you like, which can query as many fields as you like.现在在搜索视图中使用这些,您可以根据需要指向任意多个 model 经理,它可以查询任意多个字段。 Using the example models above, here's a sample view, below.使用上面的示例模型,下面是一个示例视图。 It passes the search term or terms to the appropriate model manager method, based on the count of terms (either 1 or more than 1).它根据术语数(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)

The query in this view is actually being passed to the backend via AJAX, but you may do it differently based on your needs and template design.此视图中的query实际上是通过 AJAX 传递到后端的,但是您可以根据您的需要和模板设计进行不同的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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