ITPub博客

首页 > IT基础架构 > > 卧槽,简单的Django ElasticSearch Haystack我竟然调了那么久。。。

卧槽,简单的Django ElasticSearch Haystack我竟然调了那么久。。。

作者:格伯纳 时间:2020-05-29 11:46:27 0 删除 编辑

最近一直在看django by example, 但由于这个教程是很久之前的了,而且搜索功能也是用solr去做的,然后去网上找代码也基本上没有,想了想,算了,干脆自己写了,应该也不难,但没想到搞了这么久,不过最终还是写出来了。。。

首先这个haystack只支持1.x和2.x版本的els, 所以不要装错了,我装了2.x的els, 当然els安装之前肯定要装java的,首先settings.py设置如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'haystack',
    'blog',
    'taggit',
    'django.contrib.sites',
    'django.contrib.sitemaps',
]


HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch2_backend.Elasticsearch2SearchEngine',
        'URL': 'http://127.0.0.1:9200/',
        'INDEX_NAME': 'blog_search',
    },
}

HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

由于我是想搜索博客的内容,models.py中的Post数据库字段如下:

class Post(models.Model):
    STATUS_CHOICES = (
        ('draft', 'Draft'),
        ('published', 'Published'),
    )
    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=250,
                            unique_for_date='publish')
    author = models.ForeignKey(User, related_name='blog_posts', on_delete=models.CASCADE)
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=10,
                              choices=STATUS_CHOICES,
                              default='draft')
    objects = models.Manager()
    published_objects = PublishedManager()
    tags = TaggableManager()

    class Meta:
        ordering = ('-publish',)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('blog:post_detail', args=[self.publish.year,
                                                 self.publish.strftime('%m'),
                                                 self.publish.strftime('%d'),
                                                 self.slug])

然后forms.py我继承了haystack.forms的SearchForm

class BlogSearchForm(SearchForm):
    def no_query_found(self):
        return self.searchqueryset.all()

接下来是search_indexes.py, 这个是必须要写的

from haystack import indexes
from .models import Post


class PostIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    title = indexes.CharField(model_attr='title')
    slug = indexes.CharField(model_attr='slug')
    body = indexes.CharField(model_attr='body')

    def get_model(self):
        return Post

这里的text字段基本上规范都是这样,然后有use_template=True, 这样就允许用数据模板去建立搜索引擎去索引文件。

然后要去建立模板文件,路径为templates/search/indexes/blog/post_text.txt,这样搜索引擎才知道根据什么字段去建立索引,

{{object.title}}
{{object.slug}}
{{object.body}}

然后可以敲命令来建立索引了,python manage.py rebuild_index, 成功以后开始写views.py

def post_search(request):
    form = BlogSearchForm()
    cd = None
    results = None
    total_results = None
    if 'q' in request.GET:
        form = BlogSearchForm(request.GET)
        if form.is_valid():
            cd = form.cleaned_data
            results = SearchQuerySet().models(Post).filter(content=cd['q']).load_all()
            total_results = results.count()
    return render(request, 'search/search.html', {'form': form,
                                                  'cd': cd,
                                                  'results': results,
                                                  'total_results': total_results})

这里有一些调试小技巧:有时当你并知道搜索出来的东西有什么属性的时候,可以用print(dir())的方法去调试,不然在框架里实际上很难去调整。

我一开始views.py的代码实际上是这样写的:

def post_search(request):
     form = BlogSearchForm(request.GET)  # 一定要将form传到html中,否则并不会将表单显示出来
     blogs = form.search()
     print(dir(blogs[0]))
     return render(request, 'search/search.html', {'blogs': blogs, 'form': form})

然后els的普通查询是q=query这种形式的,与原教程solr的query有点区别。

最后把views.py里面变量传到html就可以啦,所以search.html是这样的:

{% extends "blog/base.html" %}

{% block title %}Search{% endblock %}

{% block content %}
    {% if "q" in request.GET %}
        <h1>Posts containing "{{ cd.q }}"</h1>
        <h3>Found {{ total_results }} result{{ total_results|pluralize }}</h3>
        {% for result in results %}
            {% with post=result.object %}
                <h4><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h4>
                {{ post.body|truncatewords:5 }}
            {% endwith %}
        {% empty %}
        <p>There are no results for your query.</p>
        {% endfor %}
        <p><a href="{% url "blog:post_search" %}">Search again</a></p>
    {% else %}
        <h1>Search for posts</h1>
        <form action="" method="get">
            {{ form.as_p }}
            <input type="submit" value="Search">
        </form>
    {% endif %}
{% endblock %}

最后代码已经放到我的github上面了

willwinworld/web-related​github.com图标

至此,django by example的前3章就完美搞定了,其实还是要弄清楚数据是怎么流动的,api摸摸肯定会越来越熟练。还要补充一点的是,每次新建索引的时候,可能需要重复的删除els里面的内容,所以在git客户端里可以一次性将所有的doc删除完,命令是curl -X DELETE 'localhost:9200/_all'

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31509949/viewspace-3146252/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: PostgreSQL 别名
请登录后发表评论 登录
全部评论
管理员

注册时间:2018-03-30

  • 博文量
    2383
  • 访问量
    984257