簡體   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