南通公司网站建设,北京和隆优化科技,厦门网站搜索引擎优化,图库网站cmsDjango by Example第三章|Extending Your Blog Application笔记
之前已经写过两章内容了#xff0c;继续第三章。第三章继续对博客系统的功能进行拓展#xff0c;其中将会穿插一些重要的技术要点。 部分内容引用自原书#xff0c;如果大家对这本书感兴趣 请支持原版Django …Django by Example·第三章|Extending Your Blog Application笔记
之前已经写过两章内容了继续第三章。第三章继续对博客系统的功能进行拓展其中将会穿插一些重要的技术要点。 部分内容引用自原书如果大家对这本书感兴趣 请支持原版Django by Example·Antonio Melé 目录
第一章:建立一个博客系统 第二章:为博客系统添加高级功能 第三章 拓展博客系统功能
上一章介绍了Django表单的基础知识、学习了如何将第三方应用程序集成到项目中。本章将涵盖以下几点
创建自定义模板标签和过滤器为博客添加站点地图和RSS订阅功能用Solr和Haystack构建搜索引擎 1 创建自定义模板标签和过滤器
Django内置了各种模板标记例如% if %或% block %。您在模板中使用了几个。您可以在Django模板语言使用学习到更多关于Django模板语言的相关知识.
然而Django还允许您创建自己的模板标记来执行一些自定义操作。自定义模板标记在需要时可以非常方便的为您的模板添加Django模板未曾定义的功能。
1.1 创建自定义模板标签
Django提供了以下帮助函数允许您以简单的方式创建自己的模板标记
simple_tag处理数据并返回字符串inclusion_tag处理数据并返回渲染模板assignment_tag处理数据并在上下文中设置变量
模板标签必须存在于Django应用程序中。
1.1.1 使用simple_tag创建简单标签
在blog应用程序目录中创建一个新目录将其命名为templatetags并向其中添加一个空__init__.py文件。在同一文件夹中创建另一个文件将其名为blog_tags.py。此时blog应用程序的文件结构应如下所示 templatetags下创建的python文件的文件名很重要。您将使用此名称在模板中加载这个自定义的标签。
我们将首先创建一个简单的标签用来检索博客中发布的所有帖子。编辑刚刚创建的blog_tags.py文件并添加以下代码
from django import template
from ..models import Postregister template.Library()register.simple_tag
def total_posts():return Post.published.count()我们创建了一个简单的模板标记它返回到目前为止发布的帖子数量。每个模板标记模块都需要包含一个名为register的变量这样才能将自定义的标签添加到Django的模板库里。此变量是template.Library()一个实例用于注册您自己的模板标签和过滤器。然后我们用Python函数定义一个名为total_posts的标签并使用register.simple_tag将该函数定义为一个简单标签并注册。Django将使用该函数的名称作为标签名。如果您想用不同的名称注册它可以通过指定name属性的名称来实现它类似register.simple_tagnamemy_tag。 添加新模板标签模块后您需要重新启动Django开发服务器以便使用新模板标签和过滤器。 在使用自定义模板标签之前必须使用Django内置的% load %标签使其可用于模板。如前所述您需要使用包含模板标签和过滤器的Python模块(文件)的名称。打开blog/base.html模板并在其顶部添加%load blog_tags%以加载模板标签模。然后使用您创建的标签显示您的帖子总数。只需将%total_posts%添加到模板中。模板最终应如下所示
{% load blog_tags %}
{% load staticfiles %}
!DOCTYPE html
html
headtitle{% block title %}{% endblock %}/titlelink href{% static css/blog.css %} relstylesheet
/headbodydiv idcontent{% block content %}{% endblock %}/divdiv idsidebarh2My blog/h2pThis is my blog. Ive written {% total_posts %} posts so far./p/div
/body
/html我们需要重新启动服务器以跟踪添加到项目中的新文件。使用CtrlC停止开发服务器然后使用以下命令再次运行
python manage.py runserver打开http://127.0.0.1:8000/blog/在浏览器中。您应该在站点的侧边栏中看到帖子总数如下所示 自定义模板标签的强大之处在于您可以处理任何数据并将其添加到任何模板中而不考虑执行的视图。您可以执行QuerySet或处理任何数据以在模板中显示你想要的结果。 1.1.2 使用inclusion_tag创建一个包含标签
现在我们将创建另一个标签以在博客的侧边栏中显示最新的帖子。这次我们将使用包含标签。使用该标签可以让我们通过使用模板标签返回的上下文变量来呈现模板。编辑blog_tags.py文件并添加以下代码
register.inclusion_tag(blog/post/latest_posts.html)
def show_latest_posts(count5):latest_posts Post.published.order_by(-publish)[:count]return {latest_posts: latest_posts}在上述代码中我们使用register.inclusion_tag注册模板标签并指定必须使用blog/post/latest_posts.html模板呈现返回值。我们的模板标签将接受默认为5的可选参数并允许我们指定要显示的帖子数。我们使用此变量限制查询Post.published.order_by‘-publish’[count]的结果。注意函数返回字典而不是简单的值。包含标签必须返回一个字典该字典用作呈现指定模板的上下文。包含标记返回字典。我们刚刚创建的模板标记可以用于传递可选数量的注释以显示例如%show_latest_posts 3%。
现在在blog/post/下创建一个新的模板文件并将其命名为latest_posts.html。并向其添加以下代码
ul
{% for post in latest_posts %}lia href{{ post.get_absolute_url }}{{ post.title }}/a/li
{% endfor %}
/ul在这里我们用一个无序列表来展示latest_posts标签的返回值。现在编辑blog/base.html模板并添加新的模板标记以显示最后3条帖子。侧边栏块应如下所示
div idsidebarh2My blog/h2pThis is my blog. Ive written {% total_posts %} posts so far./ph3Latest posts/h3{% show_latest_posts 3 %}
/div
模板标记被调用传递要显示的帖子数并在给定上下文中就地呈现相应的模板。
现在返回浏览器并刷新页面。侧边栏现在应该如下所示 1.1.3 使用assignment_tag创建一个赋值标签
最后我们将创建一个赋值标签。赋值标签类似于简单标签但它们将结果存储在给定的变量中。我们将创建一个赋值标签来显示评论最多的帖子。编辑blog_tags.py文件并在其中添加以下代码
rom django.db.models import Countregister.assignment_tag
def get_most_commented_posts(count5):return Post.published.annotate(total_commentsCount(comments)).order_by(-total_comments)[:count]此QuerySet使用annotate函数进行查询聚合也使用了Count聚合函数。我们在total_comments字段中构建一个QuerySet聚合每个帖子的评论总数并根据该字段对QuerySet进行排序。我们还提供了一个可选的计数变量来限制返回到给定值的对象总数。
除了Count之外Django还提供了聚合函数Avg、Max、Min和Sum。有关聚合函数的详细信息请访问Django聚合函数。
编辑blog/base.html模板并将以下代码追加到侧边栏div元素中
h3Most commented posts/h3
{% get_most_commented_posts as most_commented_posts %} ul
{% for post in most_commented_posts %}lia href{{ post.get_absolute_url }}{{ post.title }}/a/li
{% endfor %}
/ul赋值模板标签的符号为% template_tag as variable %。对于模板标签我们使用% get_most_commented_posts as most_commented_posts%。这样我们将模板标签返回的结果存储在名为most_commented_posts的新变量中。然后我们就可以使用这个新变量然后用无序列表显示返回的帖子。
现在打开浏览器并刷新页面以查看最终结果。应该如下所示
有关自定义模板标签的详细信息请访问Django自定义模板标签。
1.2 自定义模板过滤器
Django有各种内置的模板过滤器允许您修改模板中的变量。模板过滤器事实上是Python函数它们接受一个或两个参数这两个变量一个是你要修改的模板变量另一个是可选参数。它们返回一个值这个值可以直接用于模板中或者继续被其他过滤器处理。一个过滤器看起来类似于variable| my_filter或者传递一个参数{variable| my_filter:“foo”。您可以对variable|filter1|filter2这样的变量应用任意数量的筛选器并且每个筛选器都将应用于上一个筛选器生成的输出。
我们将创建一个自定义过滤器它能够将我们的帖子内容转换为Markdown格式显示在页面中。Markdown是一种简单易用的纯文本格式语法它旨在转换为HTML。您可以学习更多有关Markdown基础知识在此处。
首先使用以下命令通过pip安装Python markdown模块
pip install Markdown2.6.2然后编辑blog_tags.py文件并包含以下代码
from django.utils.safestring import mark_safe import markdownregister.filter(namemarkdown)
def markdown_format(text):return mark_safe(markdown.markdown(text))自定义模板过滤器和自定义标签一样也是需要注册的。为了避免函数名和markdown模块之间的冲突我们为自定义过滤器函数名称加一个markdown前缀并将过滤器命名为markdown以便在模板中使用例如variable|markdown。Django对过滤器生成的HTML代码进行转义。我们使用Django提供的mark_safe函数将结果标记为要在模板中呈现的安全HTML。默认情况下Django不信任任何HTML代码并在将其放入输出之前对其进行转义。唯一的例外是标记为不可转义的变量。这种行为防止Django输出潜在危险的HTML并允许您在知道返回安全HTML时创建异常。
现在在文章列表和文章内容页模板中加载模板标签模块。在post/list.html和post/detail.html模板顶部的%extends%标记后面添加以下行
{% load blog_tags %}在post/detail.html模板中使用{{ post.body|markdown }}替换以下行
{{ post.body|linebreaks }}然后在post/list.html文件中使用{{ post.body|markdown|truncatewords_html:30 }}替换以下行
{{ post.body|truncatewords:30|linebreaks }} truncatewords_html过滤器在一定数量的字符之后截断字符串避免未闭合的html标记。
现在打开http://127.0.0.1:8000/admin/blog/post/add/在浏览器中并在正文处添加以下内容
This is a post formatted with markdown
--------------------------------------*This is emphasized* and **this is more emphasized**.Here is a list:
* One
* Two
* ThreeAnd a [link to the Django website](https://www.djangoproject.com/)打开浏览器查看帖子的呈现方式。您应该看到以下内容 如您所见自定义模板过滤器对于自定义格式非常有用。你可以在以下位置找到有关自定义过滤器的详细信息编写自定义模板过滤器。 2 为你的网站添加站点地图
sitemap又称“网站地图”是展示一个网站结构、栏目和内容说明等基本信息的文档就像人们对一个陌生城市的了解需要借助于城市地图一样对于一个网站信息的快速了解也可以借助于网站地图进行。
Django附带了一个站点地图框架它允许您动态生成站点地图。站点地图是一个XML文件它告诉搜索引擎网站的页面、它们的相关性以及更新的频率。通过使用站点地图您将帮助爬虫为您的网站内容编制索引。
Django站点地图框架依赖于Django.contrib.sites它允许您将对象关联到与项目一起运行的特定网站。当您想使用一个Django项目运行多个站点时这很方便。要安装站点地图框架我们需要激活项目中的站点和站点地图应用程序。编辑项目的settings.py文件并将django.contrib.sites和django.confrib.itemaps添加到INSTALLED_APPS设置中。还要为站点ID定义一个新设置如下所示
SITE_ID 1# Application definition
INSTALLED_APPS (# ...django.contrib.sites,django.contrib.sitemaps,
)现在运行以下命令在数据库中创建Django站点应用程序的表
python manage.py migrate站点应用程序现在已与数据库同步。现在在blog应用程序目录中创建一个新文件并将其命名为sitemaps.py。打开该文件并向其中添加以下代码
from django.contrib.sitemaps import Sitemap
from .models import Postclass PostSitemap(Sitemap):changefreq weeklypriority 0.9def items(self):return Post.published.all()def lastmod(self, obj):return obj.publish我们通过继承sitemaps模块的Sitemap类来创建自定义站点地图。changefreq和priority属性表示您的帖子展示页面的更改频率及其在网站中的相关性最大值为1。items方法返回要包含在此站点地图中的对象的QuerySet。默认情况下Django对每个对象调用get_absolute_url()方法来检索其url。请记住我们在第1章“构建博客应用程序”中创建了这个方法以检索帖子的规范URL。如果要为每个对象指定URL可以向sitemap类添加位置方法。lastmod方法接收items返回的每个对象并返回上次修改对象的时间。changefreq和priority方法也可以是方法或属性。您可以在Django官方文档中看到完整的站点地图参考该文档位于Django站点地图.
最后我们只需要添加站点地图URL。编辑项目的主urls.py文件并添加如下内容
from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.sitemaps.views import sitemap
from blog.sitemaps import PostSitemapsitemaps {posts: PostSitemap,
)urlpatterns [url(r^admin/, include(admin.site.urls)),url(r^blog/, include(blog.urlsnamespaceblog, app_nameblog)),url(r^sitemap\.xml$, sitemap, {sitemaps: sitemaps}, namedjango.contrib.sitemaps.views.sitemap),
]
在这里我们导入了所需的模块并定义了一个站点地图字典。我们定义了一个与sitemap.xml匹配并使用sitemap视图的URL模式。站点地图字典被传递到站点地图视图。现在打开http://127.0.0.1:8000/sitemap.xml在浏览器中。您应该看到如下XML代码
?xml version1.0 encodingUTF-8?
urlset xmlnshttp://www.sitemaps.org/schemas/sitemap/0.9urllochttp://example.com/blog/2015/09/20/another-post//loclastmod2015-09-29/lastmodchangefreqweekly/changefreqpriority0.9/priority/urlurllochttp://example.com/blog/2015/09/20/who-was-django-reinhardt//loclastmod2015-09-20/lastmodchangefreqweekly/changefreqpriority0.9/priority/url
/urlset每个帖子的URL都是通过调用其get_absolute_URL()方法构建的。lastmod属性对应于我们在sitemap中指定的发布后日期字段changefreq和priority属性也取自我们上面定义的PostSitemap类。您可以看到用于构建URL的域是example.com。该域来自数据库中存储的Site对象。这个默认对象是在我们将站点框架与数据库同步时创建的。打开http://127.0.0.1:8000/admin/sites/site/在浏览器中。您应该看到这样的内容
这是站点框架的列表显示管理视图。在这里您可以设置站点框架和依赖它的应用程序使用的域或主机。为了生成本地环境中存在的URL请将域名更改为127.0.0.1:8000如下图所示并保存它 在生产环境中您必须为站点框架使用自己的域名。 3 为博客添加RSS订阅功能
Django有一个内置的syndication feed(用于管理订阅功能)框架您可以使用它以类似于使用sitemaps框架创建站点地图的方式动态生成RSS订阅或Atom提要。 RSS是简易信息聚合“Really Simple Syndication”或“Richsite summary”(网站内容摘要)的缩写。是站点用来和其他站点之间共享内容的一种简易方式。 在blog应用程序目录中创建一个新文件并将其命名为feeds.py。向其中添加以下代码:
from django.contrib.syndication.views import Feed
from django.template.defaultfilters import truncatewords
from .models import Postclass LatestPostsFeed(Feed):title My bloglink /blog/description New posts of my blog.def items(self):return Post.published.all()[:5]def item_title(self, item):return item.titledef item_description(self, item):return truncatewords(item.body, 30)
首先我们创建一个继承syndication模块的Feed类的子类。title、link和description属性分别对应于title、link和descriptionRSS元素。
items方法检索要包含在订阅中的对象。我们仅检索此提要的最后五篇已发布文章。item_title和item_description方法接收items返回的每个对象并返回每个对象的标题和描述。我们使用truncatewords内置模板过滤器来构建包含前30个单词的博客文章描述。
现在编辑blog应用程序的urls.py文件导入刚刚创建的LatestPostsFeed并为它创建新的URL模式:
from .feeds import LatestPostsFeedurlpatterns [# ... url(r^feed/$, LatestPostsFeed(), namepost_feed),
]在浏览器中打开http://127.0.0.1:8000/blog/feed/。现在您应该可以看到RSS订阅的提要其中包括最后五篇博客文章
?xml version1.0 encodingutf-8?
rss xmlns:atomhttp://www.w3.org/2005/Atom version2.0channeltitleMy blog/titlelinkhttp://127.0.0.1:8000/blog//linkdescriptionNew posts of my blog./descriptionatom:link hrefhttp://127.0.0.1:8000/blog/feed/ relself/languageen-us/languagelastBuildDateSun, 20 Sep 2015 20:40:55 -0000/lastBuildDateitemtitleWho was Django Reinhardt?/titlelinkhttp://127.0.0.1:8000/blog/2015/09/20/who-was-django-reinhardt//linkdescriptionThe Django web framework was named after the amazing jazz guitarist Django Reinhardt./descriptionguidhttp://127.0.0.1:8000/blog/2015/09/20/who-was-django-reinhardt//guid/item.../channel
/rss如果您在RSS客户端中打开相同的URL您将能够看到您订阅的内容。
最后一步是将提要订阅功能链接添加到博客的侧边栏。打开blog/base.html模板在侧边栏div中的文章总数下添加以下行
pa href{% url blog:post_feed %}Subscribe to my RSS feed/a/p现在在浏览器中打开http://127.0.0.1:8000/blog/查看侧边栏。您将看到RSS订阅的功能链接 3 用Solr和Haystack构建搜索引擎
现在我们将在博客中添加搜索功能。Django ORM允许您使用icontains过滤器执行不区分大小写的查找。例如可以使用以下查询查找帖子正文中包含单词framework的帖子
Post.objects.filter(body__icontainsframework)但是如果您需要更强大的搜索功能则必须使用适当的搜索引擎。在这里我们将使用Solr为我们的博客构建一个搜索引擎。Solr是一个流行的开源搜索平台它提供全文搜索、术语提升、点击突出显示、多面搜索和动态聚类等高级搜索功能。
为了将Solr集成到我们的项目中我们将使用干Haystack。Haystack是一个Django应用程序可以作为多个搜索引擎的抽象层。它提供了一个简单的搜索API非常类似于Django查询集。让我们从安装和配置Solr和干堆开始。
3.1 安装Solr
您需要在您的机器上配置JAVA环境并且是1.7版或更高版本才能安装Solr。您可以使用shell提示符中的命令java-version检查java版本。输出可能有所不同但您需要确保安装的版本至少为1.7:
java version 1.7.0_25
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)如果您没有安装Java或您的版本低于所需版本则可以从http://www.oracle.com/technetwork/java/javase/downloads/index.html下载.
检查Java版本后从http://archive.apache.org/dist/lucene/solr/.解压缩下载的文件并转到Solr安装目录中的示例目录即cd Solr-4.10.4/example/。该目录包含一个可用的Solr配置。从该目录中使用以下命令使用内置Jetty web服务器运行Solr
java -jar start.jar打开浏览器并输入URLhttp://127.0.0.1:8983/solr/.您应该看到以下内容 这是Solr管理控制台。此控制台显示使用情况统计信息并允许您管理搜索后端、检查索引数据和执行查询。
3.2 创建一个Solr内核
Solr允许您隔离核心中的实例。每个Solr内核都是一个Lucene实例包含Solr配置、数据模式和使用它所需的其他配置。Solr允许您动态创建和管理内核。此示例配置一个名为collection1的Solr内核。如果你单击core Admin菜单选项卡您可以看到此core的信息如下图所示 我们将为我们的blog应用程序创建一个独立的Solr内核。首先我们需要创建此内核的文件结构。在solr-4.10.4/目录中的示例目录中创建一个新目录并将其命名为blog。然后在其中创建以下空文件和目录 添加以下代码到solrconfig.xml文件:
?xml version1.0 encodingutf-8 ?
configluceneMatchVersionLUCENE_36/luceneMatchVersion requestHandler name/select classsolr.StandardRequestHandler defaulttrue /requestHandler name/update classsolr.UpdateRequestHandler /requestHandler name/admin classsolr.admin.AdminHandlers /requestHandler name/admin/ping classsolr.PingRequestHandlerlst nameinvariantsstr nameqtsearch/strstr nameq*:*/str/st/requestHandler
/config您也可以从本章附带的代码中复制此文件。这是最小的Solr配置。编辑schema.xml文件并添加以下xml代码
?xml version1.0 ?
schema namedefault version1.5
/schema这是一个空的xml文件稍后我们将依据此文件使用Solr的自定义模式。 现在单击Core Admin菜单选项卡然后单击Add Core按钮。您将看到一个类似以下的表单允许您自定义此内核的信息 在上述页面对应位置填写以下内容
name: bloginstanceDir: blogdataDir: dataconfig: solrconfig.xmlschema: schema.xml
name字段是此Solr内核的名称。instanceDir字段是内核所在的的目录名称。dataDir是索引数据保存的目录它位于instanceDir目录下。config字段是Solr XML配置文件的名称schema字段是SolrXML数据模式文件的名称。
现在单击Add Core按钮。如果您看到以下内容则您的新内核已成功添加到Solr
3.3 安装Haystack模块
要在Django中使用Solr搭建搜索引擎我们还需要使用Haystack模块。使用以下命令通过pip安装Haystack
pip install django-haystack2.4.0
Haystack可以与几个搜索引擎后端交互。要使用Solr后端还需要安装pysolr模块。运行以下命令安装它
pip install pysolr3.3.2
安装django-haystack和pysolr两个模块后需要在项目中激活haystack。打开settings.py项目配置文件将haystack添加到INSTALLED_APPS设置中如下所示
INSTALLED_APPS (# ...haystack,
)您需要为haystack定义搜索引擎后端。可以通过在settings.py中添加HAYSTACK_CONNECTIONS配置项来完成此操作。将以下内容添加到settings.py文件中
HAYSTACK_CONNECTIONS {default: {ENGINE: haystack.backends.solr_backend.SolrEngine,URL: http://127.0.0.1:8983/solr/blog},
}注意URL指向我们的blog应用的Solr内核。Haystack现已安装完毕可与Solr一起使用。
3.4 为搜索引擎添加索引
现在我们必须在搜索引擎中注册要存储的模型。Haystack的惯例是在应用程序中创建一个search_indexs.py文件并在那里注册模型。在blog应用程序目录中创建一个新文件并将其命名为search_indexs.py。向其中添加以下代码
from haystack import indexes
from .models import Postclass PostIndex(indexes.SearchIndex, indexes.Indexable):text indexes.CharField(documentTrue, use_templateTrue) publish indexes.DateTimeField(model_attrpublish)def get_model(self):return Postdef index_queryset(self, usingNone):return self.get_model().published.all()这里我们需要为Post模型(博客帖子模型)对应的数据表建立索引。首先我们自定义一个索引类在这个类中需要告诉Haystack搜索的字段以及搜索这个操作对应的查询集。索引是通过将indexs.SearchIndex和indexs.Indexeble子类化而生成的。每个SearchIndex都要求其字段之一的documentTrue。惯例是将此字段命名为text 此字段是主搜索字段。当use_templateTrue时我们正在告诉Haystack该字段将被呈现在模板中用以构建搜索引擎将药索引的文档。publish字段是一个时间字段它也将被索引。我们使用model_attr参数表示该字段对应的是Post模型的publish 字段。该字段将使用索引的Post对象的publish字段的内容进行索引。
get_model()方法必须返回建立索引数据表对应的模型此处我们是需要搜索帖子的内容所以返回的就是Post模型。index_queryset()方法返回将被索引的对象的查询集queryset。请注意我们只搜索已发布的帖子。
现在在博客应用程序的templates目录中创建以下文件search/indexs/blog/post_text.txt并向其中添加以下代码
{{ object.title }}
{{ object.tags.all|join:, }}
{{ object.body }}这是我们的text字段的文档模板的默认路径Haystack使用应用程序名称和模型名称动态构建路径。每次我们要索引一个对象时Haystack都会基于该模板创建一个文档然后Solr搜索引擎中对文档进行索引。[这个地方的索引就是搜索的意思]
现在我们有了自定义搜索索引我们必须创建适当的Solr模式。Solr的配置是基于XML的因此我们必须将要索引的数据变成XML格式。幸运的是Haystack提供了一种基于搜索索引动态生成Solr模式的方法。打开终端并运行以下命令
python manage.py build_solr_schema执行上述代码您将看到一个XML输出。在生成的XML代码的底部您将看到Haystack自动为帖子(Post)的索引生成对应的字段
field nametext typetext_en indexedtrue storedtrue multiValuedfalse /
field namepublish typedate indexedtrue storedtrue multiValuedfalse /复制全部XML代码该XML是将数据索引到Solr中的模式。将新模式粘贴到Solr安装示例目录中的blog/conf/schema.xml文件中。schema.xml文件包含在本章附带的代码中因此您也可以直接从该文件复制它。
在浏览器中打开http://127.0.0.1:8983/solr/单击Core Admin菜单选项卡然后单击blog core然后单击Reload按钮 我们重新加载内核当核心完成重载时就可以用新模式索引新数据了。
3.5 索引数据
让我们把我们博客的帖子索引到Solr中。打开终端执行如下命令:
python manage.py rebuild_index你将看到以下警告:
WARNING: This will irreparably remove EVERYTHING from your search index in connection default.
Your choices after this are to restore from backups or rebuild via the rebuild_index command.
Are you sure you wish to continue? [y/N]输入y之后回车。Haystack将清除搜索索引并插入所有已发表的博客。你应该看到如下输出:
Removing all documents from your index because you said so. All documents removed.
Indexing 4 posts在浏览器中打开http://127.0.0.1:8983/solr/#/blog。您将看到索引文档的数量如下所示: 现在在浏览器中打开http://127.0.0.1:8983/solr/#/blog/query。这是Solr提供的查询接口。单击Execute查询按钮。默认查询请求在核心中索引的所有文档。您将看到带有查询结果的JSON输出。输出的文档如下所示:
{id: blog.post.1,text: Who was Django Reinhardt?\njazz, music\nThe Django web framework was named after the amazing jazz guitarist Django Reinhardt.,django_id: 1,publish: 2015-09-20T12:49:52Z, django_ct: blog.post
},这是为搜索索引中的每个帖子存储的数据。文本字段包含标题、用逗号分隔的标签和文章正文因为这个字段是用我们之前定义的模板构建的。
您已经使用python manage.py rebuild_index删除索引中的所有内容并重新索引文档。要在不删除所有对象的情况下更新索引可以使用python manage.py update_index。或者您可以使用参数–agenum_hours来更新更少的对象。您可以为此索引设置一个Cron作业以保持Solr索引的更新。
3.6 创建搜索视图
现在我们将创建一个视图允许用户搜索帖子。首先我们需要一个搜索表单。编辑blog应用程序下的forms.py文件并添加以下内容
class SearchForm(forms.Form):query forms.CharField()我们将使用查询字段让用户引入搜索词。编辑blog应用程序的views.py文件并添加以下代码:
from .forms import EmailPostForm, CommentForm, SearchForm
from haystack.query import SearchQuerySetdef post_search(request):form SearchForm()if query in request.GET:form SearchForm(request.GET)if form.is_valid():cd form.cleaned_dataresults SearchQuerySet().models(Post).filter(contentcd[query]).load_all() # count total resultstotal_results results.count()return render(request,blog/post/search.html,{form: form,cd: cd,results: results,total_results: total_results})在这个视图中首先实例化之前创建的搜索表单SearchForm。我们将使用GET方法提交表单以便生成的URL包含查询参数。我们将通过查询请求中的查询参数来确定表单是否已提交。当表单提交时我们用提交的GET数据实例化它并检查给定的数据是否有效。如果表单有效则使用SearchQuerySet对主要内容包含给定查询的索引Post对象执行搜索。load_all()方法一次从数据库加载所有相关的Post对象。使用这种方法我们用数据库对象填充搜索结果以避免在迭代结果以访问对象数据时对数据库的每个对象访问。最后我们将结果的总数存储在total_results变量中并将局部变量作为上下文传递给模板。
完成搜索视图的创建。我们需要创建一个模板以便在用户执行搜索时显示表单和结果。在templates/blog/post/目录中创建一个新文件命名为search.html并添加以下代码:
{% extends blog/base.html %}{% block title %}Search{% endblock %}{% block content %}{% if query in request.GET %}h1Posts containing {{ cd.query }}/h1h3Found {{ total_results }} result{{ total_results|pluralize }}/h3{% for result in results %}{% with postresult.object %}h4a href{{ post.get_absolute_url }}{{ post.title }}/a/h4{{ post.body|truncatewords:5 }}{% endwith %}{% empty %}pThere are no results for your query./p{% endfor %}pa href{% url blog:post_search %}Search again/a/p{% else %}h1Search for posts/h1form action. methodget{{ form.as_p }}input typesubmit valueSearch/form{% endif %}
{% endblock %}与在搜索视图中的逻辑一样我们根据查询参数的存在来区分表单是否已提交。在提交文章之前我们显示表单和提交按钮。提交帖子后我们显示执行的查询、结果总数和结果列表。每个结果都是由Solr返回并由Haystack封装的文档。我们需要使用结果。对象来访问与此结果相关的实际Post对象。
最后编辑你的博客应用程序的urls.py文件并添加以下URL模式:
url(r^search/$, views.post_search, namepost_search),现在在浏览器中打开http://127.0.0.1:8000/blog/search/。你会看到一个这样的搜索表单: 现在输入一个查询并单击Search按钮。你会看到搜索查询的结果就像这样: 现在您的项目中已经内置了一个强大的搜索引擎但是从这里开始您可以使用Solr和Haystack做很多事情。Haystack包括搜索视图、表单和搜索引擎的高级功能。您可以在http://django-haystack.readthedocs.org/en/latest/上阅读Haystack文档。
Solr搜索引擎可以通过自定义模式来适应任何需求。您可以组合执行的分析器、标记器和标记过滤器索引或搜索时间为您的网站内容提供更准确的搜索。你可以在https://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters上看到所有的使用方法。 4 总结
在本章中你学习了如何创建自定义的Django模板标签和过滤器为模板提供自定义功能。您还创建了一个站点地图供搜索引擎抓取您的站点并创建了一个RSS提要供用户订阅。您还通过将Solr与Haystack集成到项目中为您的博客构建了一个搜索引擎。
在下一章中你将学习如何通过使用Django认证框架、创建自定义用户配置文件和构建社交认证来构建一个社交网站。