默认搜索功能
默认情况下,文章搜索插件支持搜索文章的标题和摘要部分。如果要搜索文章内容部分,需要额外的配置。
添加配置
ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE = True
当该变量激活之后,在文章插件保存时,它会将它的内容渲染并保存到数据库,然后我们在搜索时就能够搜到该部分内容。
但是仅仅设置ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE并不能自动地将前面保存的内容添加到对应数据库,我们需要执行下面的命令rebuild_article_search_data
python manage.py rebuild_article_search_data
该命令里的--language
是可选的,简写-l
,它用于指定翻译的内容,例如
python manage.py rebuild_article_search_data -l en de
如果不指定语言,那么它会处理所有的语言
Aldryn Search and Haystack
Aldryn News & Blog supports Aldryn Search and Django Haystack.
If you have Aldryn Search and Haystack installed and configured in your project, News & Blog’s content can also be rendered searchable. To enable this, add:
ALDRYN_NEWSBLOG_SEARCH = True
in your settings. Note that if your search infrastructure is not configured, this setting will have no effect.
代码适配
实际上仅仅做上面的修改并不能成功工作, 会提示markdown
对象没有render_plugin
函数,问题出在下面的函数
aldryn_newsblog/utils/aldryn_newsblog.py
def get_plugin_index_data(base_plugin, request):
text_bits = []
instance, plugin_type = base_plugin.get_plugin_instance()
if instance is None:
# this is an empty plugin
return text_bits
search_fields = getattr(instance, 'search_fields', [])
if hasattr(instance, 'search_fulltext'):
# check if the plugin instance has search enabled
search_contents = instance.search_fulltext
elif hasattr(base_plugin, 'search_fulltext'):
# now check in the base plugin instance (CMSPlugin)
search_contents = base_plugin.search_fulltext
elif hasattr(plugin_type, 'search_fulltext'):
# last check in the plugin class (CMSPluginBase)
search_contents = plugin_type.search_fulltext
else:
# disabled if there's search fields defined,
# otherwise it's enabled.
search_contents = not bool(search_fields)
if search_contents:
from djangocms_markdown.models import Markdown
# if not type(instance) in [Markdown, Comments, Picture, Style, Bootstrap3CodePlugin, Boostrap3ImagePlugin]:
if instance and hasattr(instance, 'render_plugin'):
plugin_contents = instance.render_plugin(
context=RequestContext(request))
elif type(instance) in [Markdown]:
plugin_contents = instance.body
else:
plugin_contents = None
if plugin_contents:
text_bits = get_cleaned_bits(plugin_contents)
else:
values = (get_field_value(instance, field) for field in search_fields)
for value in values:
cleaned_bits = get_cleaned_bits(value or '')
text_bits.extend(cleaned_bits)
return text_bits
修改上面的代码,如果对象没有render_plugin
函数,则忽略
至少有下面函数是没有的
from djangocms_comments.models import Comments
from djangocms_picture.models import Picture
from djangocms_style.models import Style
from aldryn_bootstrap3.models import Bootstrap3CodePlugin
from aldryn_bootstrap3.models import Boostrap3ImagePlugin
但是我们希望还是要搜索markdown的内容,检查markdown对象的定义
class Markdown(CMSPlugin):
body = models.TextField()
def __str__(self):
return self.body[:64]
针对Markdown可以做特别处理。当然其实更好的是搜索处理过之后的内容,但本质上通过上面方法可以搜索了。
上面的针对Markdown部分的代码如下
elif type(instance) in [Markdown]:
plugin_contents = instance.body
代码走读
看一下代码的实现
,下面这段代码是搜索结果的处理,可以看到有一个字段是search_data
class ArticleSearchResultsList(ArticleListBase):
model = Article
def get_queryset(self):
qs = super(ArticleSearchResultsList, self).get_queryset()
if not self.edit_mode:
qs = qs.published()
if self.query:
return qs.filter(
Q(translations__title__icontains=self.query) |
Q(translations__lead_in__icontains=self.query) |
Q(translations__search_data__icontains=self.query)
).distinct()
else:
return qs.none()
它在model里的定义如下,真正的内容content是一个placeholder
class Article(TranslatedAutoSlugifyMixin,
TranslationHelperMixin,
TranslatableModel):
# TranslatedAutoSlugifyMixin options
slug_source_field_name = 'title'
slug_default = _('untitled-article')
# when True, updates the article's search_data field
# whenever the article is saved or a plugin is saved
# on the article's content placeholder.
update_search_on_save = getattr(
settings,
'ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE',
False
)
translations = TranslatedFields(
title=models.CharField(_('title'), max_length=234),
slug=models.SlugField(
verbose_name=_('slug'),
max_length=255,
db_index=True,
blank=True,
help_text=_(
'Used in the URL. If changed, the URL will change. '
'Clear it to have it re-created automatically.'),
),
lead_in=HTMLField(
verbose_name=_('lead'), default='',
help_text=_(
'The lead gives the reader the main idea of the story, this '
'is useful in overviews, lists or as an introduction to your '
'article.'
),
blank=True,
),
meta_title=models.CharField(
max_length=255, verbose_name=_('meta title'),
blank=True, default=''),
meta_description=models.TextField(
verbose_name=_('meta description'), blank=True, default=''),
meta_keywords=models.TextField(
verbose_name=_('meta keywords'), blank=True, default=''),
meta={'unique_together': (('language_code', 'slug', ), )},
search_data=models.TextField(blank=True, editable=False)
)
content = PlaceholderField('newsblog_article_content',
related_name='newsblog_article_content')
从下面这个代码片段中可以看到它会根据设置ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE
来觉得是否更新搜索结果
update_search_on_save = getattr(
settings,
'ALDRYN_NEWSBLOG_UPDATE_SEARCH_DATA_ON_SAVE',
False
)
search_data
在get_search_data
获取,通过遍历plugin内容加到结果里
def get_search_data(self, language=None, request=None):
"""
Provides an index for use with Haystack, or, for populating
Article.translations.search_data.
"""
if not self.pk:
return ''
if language is None:
language = get_current_language()
if request is None:
request = get_request(language=language)
description = self.safe_translation_getter('lead_in', '')
text_bits = [strip_tags(description)]
for category in self.categories.all():
text_bits.append(
force_unicode(category.safe_translation_getter('name')))
for tag in self.tags.all():
text_bits.append(force_unicode(tag.name))
if self.content:
plugins = self.content.cmsplugin_set.filter(language=language)
for base_plugin in plugins:
plugin_text_content = ' '.join(
get_plugin_index_data(base_plugin, request))
text_bits.append(plugin_text_content)
return ' '.join(text_bits)
在更新文章时,这个search_data也会更新,保存时会将内容存到数据库,具体参考下面函数
def update_search_data(sender, instance, **kwargs):
class Article(TranslatedAutoSlugifyMixin,
TranslationHelperMixin,
TranslatableModel):
def save(self, *args, **kwargs):
搜索列表控制
当显示的条目多时,会发现只能显示5行了,查了一下代码
aldryn_newsblog\views.py
class ArticleSearchResultsList(ArticleListBase):
...
def get(self, request, *args, **kwargs):
self.query = request.GET.get('q')
self.max_articles = request.GET.get('max_articles', 0)
self.edit_mode = (request.toolbar and request.toolbar.edit_mode)
return super(ArticleSearchResultsList, self).get(request)
def get_paginate_by(self, queryset):
"""
If a max_articles was set (by a plugin), use that figure, else,
paginate by the app_config's settings.
"""
return self.max_articles or super(
ArticleSearchResultsList, self).get_paginate_by(self.get_queryset())
class ArticleListBase(AppConfigMixin, AppHookCheckMixin, TemplatePrefixMixin,
PreviewModeMixin, ViewUrlMixin, ListView):
def get_paginate_by(self, queryset):
if self.paginate_by is not None:
return self.paginate_by
else:
try:
return self.config.paginate_by
except AttributeError:
return 10 # sensible failsafe
aldryn_common\paginator.py
def paginate_by(fallback=15):
return getattr(settings, 'ALDRYN_COMMON_PAGINATOR_PAGINATE_BY', fallback)
要解决显示的问题,有两个方法
1.修改配置使得paginate_by
值改变
它对应的数据库配置是
class NewsBlogConfig(TranslatableModel, AppHookConfig):
paginate_by = models.PositiveIntegerField(
_('Paginate size'),
blank=False,
default=5,
help_text=_('When paginating list views, how many articles per page?'),
)
可以通过下面配置界面修改
这个改法有个问题,这个配置是app级别的,它同时会修改正常的blog列表的结果。
2.传递max_articles
参数
我们需要在模板文件里添加该变量
article_search.html
<form action="{{ query_url }}" method="get">
<div class="row">
<div class="col-sm-12">
<div class="input-group">
<input type="text" name="q" id="search-plugin-{{ instance.pk }}" class="form-control" placeholder="{% trans "Search for article ..." %}" required>
<span class="input-group-btn">
<input type="hidden" name="max_articles" value="{{ instance.max_articles }}">
<button class="btn btn-default" type="submit">Go!</button>
</span>
</div><!-- /input-group -->
</div><!-- /.col-sm-12 -->
</div><!-- /.row -->
</form>
添加一个hidden的input: max_articles
同时,可以看到它的数据库对应的字段
class NewsBlogArticleSearchPlugin(NewsBlogCMSPlugin):
max_articles = models.PositiveIntegerField(
_('max articles'), default=10,
validators=[django.core.validators.MinValueValidator(1)],
help_text=_('The maximum number of found articles display.')
)
在下面plugin插件可修改
这样,就可以最大显示100多条搜索记录啦
其实,还有个方法就是跟blog显示一样将结果分页。比如: http://www.codingsoho.com/zh/blog/search/?q=deployment&max_articles=100 这个结果,如果返回结果是多于5条记录的,我们也可以用http://www.codingsoho.com/zh/blog/search/?q=deployment&max_articles=5&page=2遍历它的结果,这个就不在本文详述了。
评论
留言请先登录或注册! 并在激活账号后留言!