【问题标题】:Simple search in DjangoDjango中的简单搜索
【发布时间】:2010-04-06 11:43:04
【问题描述】:

我有一个非常简单的博客应用程序,我想向它添加一个非常简单的搜索功能。

我的模型有 3 个关键字段。

class BlogPost(models.Model):
    title = models.CharField(max_length=100) # the title
    intro = models.TextField(blank=True, null=True) # an extract
    content = models.TextField(blank=True, null=True) # full post

我不需要谷歌。我不想搜索 cmets(无论如何都保存在 Disqus 上)。我只想要一组按日期排序、关键字过滤的帖子。

我在 Google 上找到的关于某种形式的“django”和“搜索”的所有内容都带有极其复杂的 Haystack+后端解决方案。我不需要所有这些。我不想在低使用率功能上占用更多资源(在移植到 Django 之前,我曾经有一个搜索框,它可能每月搜索 4 次)。

我花时间在这里询问的原因(而不仅仅是写一个凌乱的小脚本)是这已经存在于管理员中。您可以设置要搜索的列,然后只搜索它“就可以工作”。

有没有办法处理管理员提供的搜索并将其拉入我的面向用户的应用程序?

【问题讨论】:

    标签: django search


    【解决方案1】:

    如果您想要一个非常简单的搜索,您可以使用icontains 查找和Q object

    from django.db.models import Q
    results = BlogPost.objects.filter(Q(title__icontains=your_search_query) | Q(intro__icontains=your_search_query) | Q(content__icontains=your_search_query))
    

    您还应该注意,Haystack 不必“非常复杂”。您可以在不到 15 分钟的时间内使用 Whoosh 后端设置 haystack。

    2016 年更新: 在 1.10 版 Django 中添加了 a full text search support(仅限 PostgreSQL)。使用新模块对原始问题的回答可能如下所示:

    from django.contrib.postgres.search import SearchVector
    
    results = BlogPost.objects.annotate(
        search=SearchVector('title', 'intro', 'content'),
    ).filter(search=your_search_query)
    

    新的全文搜索模块包含更多功能(例如按相关性排序),您可以read about them in the documentation

    【讨论】:

    • 我同意,Haystack+Whoosh 很容易上手。如果太费力,还不如使用谷歌网站搜索。
    • 我所说的复杂不仅仅是指设置。它比这个单行代码多英里。我知道它确实有很多更好的性能,但快速、肮脏的搜索是我目前所追求的。谢谢! @Stijn 引入另一个搜索引擎(我会选择 Bing,因为他们仍然有适当的服务器端 API)如果脏搜索不起作用,将是我的下一个调用端口。
    • 感谢您,非常有帮助。如果搜索没有结果怎么办?我们将如何生成和添加一个新的 BlogPost() 对象?
    【解决方案2】:

    来自 Django source:

    # Apply keyword searches.
    def construct_search(field_name):
        if field_name.startswith('^'):
            return "%s__istartswith" % field_name[1:]
        elif field_name.startswith('='):
            return "%s__iexact" % field_name[1:]
        elif field_name.startswith('@'):
            return "%s__search" % field_name[1:]
        else:
            return "%s__icontains" % field_name
    
    if self.search_fields and self.query:
        for bit in self.query.split():
            or_queries = [models.Q(**{construct_search(str(field_name)): bit}) for field_name in self.search_fields]
            qs = qs.filter(reduce(operator.or_, or_queries))
        for field_name in self.search_fields:
            if '__' in field_name:
                qs = qs.distinct()
                break
    

    显然,它使用数据库选项来执行搜索。如果不出意外,您应该能够重用其中的一些代码。

    文档也这么说:http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields

    然而,全文搜索使用 MySQL 索引(仅当您使用 MySQL 时)。

    【讨论】:

      【解决方案3】:

      您将使用 __search 运算符。它记录在Django QuerySet API Reference 中。还有istartswith,它执行不区分大小写的开头搜索。

      这是一个工作示例(改编自我自己的 Django 网站):

      def search(request):
          try:
              q = request.GET['q']
              posts = BlogPost.objects.filter(title__search=q) | \
                      BlogPost.objects.filter(intro__search=q) | \
                      BlogPost.objects.filter(content__search=q)
              return render_to_response('search/results.html', {'posts':posts, 'q':q})
          except KeyError:
              return render_to_response('search/results.html')
      

      请注意,__search 仅在 MySQL 中可用,并且需要直接操作数据库以添加全文索引。有关更多详细信息,请参阅MySQL documentation

      【讨论】:

      • “__search”运算符仅适用于支持全文索引的某些后端和表类型。
      • 谢谢,我已将其包含在我的回答中。
      【解决方案4】:

      如果你想让它像管理员一样工作,你可以试试我的 mini-lib Django simple search。它基本上是管理员搜索功能的一个端口。用 pip 安装:

      pip install django-simple-search
      

      并像这样使用它:

      from simple_search import search_filter
      from .models import BlogPost
      
      search_fields = ['^title', 'intro', 'content']
      query = 'search term here'
      posts = BlogPost.objects.filter(search_filter(search_fields, query))
      

      我还写了一篇关于它的博文:https://gregbrown.co/projects/django-simple-search

      【讨论】:

        最近更新 更多