• 更完善的博客系统
    • 静态页面
      • 安装 flatpages
      • 创建模板
    • 评论功能
    • Sitemap
      • 站点地图介绍
      • 创建首页的Sitemap
      • 创建静态页面的Sitemap
      • 创建博客的Sitemap
      • 提交到搜索引擎

    更完善的博客系统

    在Django框架中,内置了很多应用在它的”contrib”包中,这些包括:

    • 一个可扩展的认证系统
    • 动态站点管理页面
    • 一组产生RSS和Atom的工具
    • 一个灵活的评论系统
    • 产生Google站点地图(Google Sitemaps)的工具
    • 防止跨站请求伪造(cross-site request forgery)的工具
    • 一套支持轻量级标记语言(Textile和Markdown)的模板库
    • 一套协助创建地理信息系统(GIS)的基础框架

    这意味着,我们可以直接用Django一些内置的组件来完成很多功能,先让我们来看看怎么完成一个简单的评论功能。

    静态页面

    Django带有一个可选的“flatpages”应用,可以让我们存储简单的“扁平化(flat)”页面在数据库中,并且可以通过Django的管理界面以及一个Python API来处理要管理的内容。这样的一个静态页面,一般包含下面的几个属性:

    • 标题
    • URL
    • 内容(Content)
    • Sites
    • 自定义模板(可选)

    为了使用它来创建静态页面,我们需要在数据库中存储对应的映射关系,并创建对应的静态页面。

    安装 flatpages

    为此我们需要添加两个应用到settings.py文件的INSTALLED_APPS中:

    • django.contrib.sites——“sites”框架,它用于将对象和功能与特定的站点关联。同时,它还是域名和你的Django 站点名称之间的对应关系所保存的位置,即我们需要在这个地方设置我们的网站的域名。
    • django.contrib.flatpages,即上文说到的内容。

    在添加django.contrib.sites的时候,我们需要创建一个SITE_ID。通过这个值等于1,除非我们打算用这个框架去管理多个站点。代码如下所示:

    1. SITE_ID = 1
    2. INSTALLED_APPS = (
    3. 'django.contrib.admin',
    4. 'django.contrib.auth',
    5. 'django.contrib.contenttypes',
    6. 'django.contrib.sessions',
    7. 'django.contrib.messages',
    8. 'django.contrib.staticfiles',
    9. 'django.contrib.sites',
    10. 'django.contrib.flatpages',
    11. 'blogpost'
    12. )

    接着,还添加对应的中间件django.contrib.flatpages.middleware.FlatpageFallbackMiddlewaresettings.py文件的MIDDLEWARE_CLASSES中。

    然后,我们需要创建对应的URL来管理所有的静态页面。下面的代码是将静态页面都放在pages路径下,即如果我们有一个about的页面,那么对应的URL会变成 http://localhost/pages/about/。

    1. url(r'^pages/', include('django.contrib.flatpages.urls')),

    当然我们也可以将其配置为类似于 http://localhost/about/ 这样的URL:

    1. urlpatterns += [
    2. url(r'^(?P<url>.*/)$', views.flatpage),
    3. ]

    最后,我们还需要做一个数据库迁移:

    1. Operations to perform:
    2. Apply all migrations: contenttypes, auth, admin, sites, blogpost, sessions, flatpages, django_comments
    3. Running migrations:
    4. Rendering model states... DONE
    5. Applying flatpages.0001_initial... OK

    创建模板

    接着,我们可以在templates目录下创建flatpages文件,用于存放我们的模板文件,下面是一个简单的模板:

    1. {% extends 'base.html' %}
    2. {% block title %}关于我{% endblock %}
    3. {% block content %}
    4. <div>
    5. <h2>关于博客</h2>
    6. <p>一方面,找到更多志同道合的人;另一方面,扩大影响力。</p>
    7. <p>内容包括</p>
    8. <ul>
    9. <li>成长记录</li>
    10. <li>技术笔记</li>
    11. <li>生活思考</li>
    12. <li>个人试验</li>
    13. </ul>
    14. </div>
    15. {% endblock %}

    当我们完成模板后,我们就需要登录后台,并添加对应的静态页面的配置:

    管理员界面创建flatpage

    然后从高级选项中填写我们的静态页面的路径,我们就可以完成静态页面的创建。如下图所示:

    flatpage高级选项

    最后,还要有个链接加到首页的导航中:

    1. <li>
    2. <a href="/pages/about/">关于我</a>
    3. </li>

    下面让我们为我们的博客添加一个简单的评论功能吧!

    评论功能

    在早期的Django版本(1.6以前)中,Comments是自带的组件,但是后来它被从标准组件中移除了。因此,我们需要安装comments这个包:

    1. pip install django-contrib-comments

    再把它及它的版本添加到requirements.txt,如下所示:

    1. django==1.9.4
    2. selenium==2.53.1
    3. fabric==1.10.2
    4. djangorestframework==3.3.3
    5. djangorestframework-jwt==1.7.2
    6. django-cors-headers==1.1.0
    7. django-contrib-comments==1.7.1

    接着,将django.contrib.sitesdjango_comments添加到INSTALLED_APPS,如下:

    1. INSTALLED_APPS = (
    2. 'django.contrib.admin',
    3. 'django.contrib.auth',
    4. 'django.contrib.contenttypes',
    5. 'django.contrib.sessions',
    6. 'django.contrib.messages',
    7. 'django.contrib.staticfiles',
    8. 'django.contrib.sites',
    9. 'django_comments',
    10. 'rest_framework',
    11. 'blogpost'
    12. )

    然后做一下数据库迁移我们就可以完成对其的初始化:

    1. Operations to perform:
    2. Apply all migrations: contenttypes, admin, blogpost, auth, sites, sessions, django_comments
    3. Running migrations:
    4. Rendering model states... DONE
    5. Applying sites.0001_initial... OK
    6. Applying django_comments.0001_initial... OK
    7. Applying django_comments.0002_update_user_email_field_length... OK
    8. Applying django_comments.0003_add_submit_date_index... OK
    9. Applying sites.0002_alter_domain_unique... OK
    10. (growth-django)

    然后再添加URL到urls.py:

    1. url(r'^comments/', include('django_comments.urls')),

    现在,我们就可以登录后台,来创建对应的评论,但是这是时候评论是不会显示到页面上的。所以我们需要对我们的博客详情页的模板进行修改,在其中添加一句:

    1. {% render_comment_list for post %}

    用于显示对应博客的评论,最近我们的模板文件如下面的内容所示:

    1. {% extends 'base.html' %}
    2. {% load comments %}
    3. {% block head_title %}{{ post.title }}{% endblock %}
    4. {% block title %}{{ post.title }}{% endblock %}
    5. {% block content %}
    6. <div class="mdl-card mdl-shadow--2dp">
    7. <div class="mdl-card__title">
    8. <h2 class="mdl-card__title-text"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
    9. </div>
    10. <div class="mdl-card__supporting-text">
    11. {{post.body}}
    12. </div>
    13. <div class="mdl-card__actions">
    14. {{post.posted}} - By {{post.author}}
    15. </div>
    16. </div>
    17. {% render_comment_list for post %}
    18. {% endblock %}

    遗憾的是,当我们刷新页面的时候,页面报错了,原因如下所示:

    SITE_ID报错

    我们还需要定义一个SITE_ID,添加下面的代码到settings.py文件中即可:

    1. SITE_ID = 1

    然后,我们就可以从后台创建评论:

    后台创建评论

    Sitemap

    我们在之前的文章中提到过SEO的重要性,这里只是简单地对Sitemap的内容进行展开。

    站点地图介绍

    Sitemap译为站点地图,它用于告诉搜索引擎他们网站上有哪些可供抓取的网页。常见的Sitemap的形式是以xml出现了,如下是我博客的sitemap.xml的一部分内容:

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    3. <url>
    4. <loc>https://www.phodal.com/blog/mezzanine-add-new-page/</loc>
    5. <lastmod>2014-08-03</lastmod>
    6. <changefreq>Monthly</changefreq>
    7. <priority>0.2</priority>
    8. </url>
    9. </urlset>

    从上面的内容中,我们可以发现它包含了下面的一些XML标签:

    • urlset,封装该文件,并指明当前协议的标准。
    • url,每个URL实体的父标签。
    • loc,指明页面的URL
    • lastmod(可选),内容最后的修改时间
    • changefreq(可选),内容的修改频率,用于告知搜索引擎抓取频率。它包含的值有:alwayshourlydailyweeklymonthlyyearlynever
    • priority(可选),范围是从0.0~1.0,搜索引擎用于对你网站在搜索结果的排序,即内部的优先级排序。需要注意的是如果你把所有页面的优先级设置为1,那么它就和没有设置的效果是一样的。

    从上面的内容中,我们可以发现:

    站点地图能够提供与其中列出的网页相关的宝贵元数据:元数据是网页的相关信息,例如网页的最近更新时间、网页的更改频率以及网页相较于网站中其他网址的重要程度。 ——内容来自 Google Sitemap帮助文档。

    现在,我们一共有三种类型的页面:

    • 首页,通常来说首页的priority应该是最高的,而它的changefreq可以设置为dailyweekly,这取决于你的博客的更新频率。如果你是做一些UGC(用户生成内容)的网站,那么你应该设置为alwayshourly
    • 动态生成的博客详情页,这些内容一般很少进行改变,所以这的changefreq会比较低,如yearly或者monthly——并且没有高的必要性,它会导致搜索引擎一直抓取你的内容。这会对服务器造成一定的压力,并且无助于你网站的排名。
    • 静态页面,如About页面,它可以有一个高的priority,但是它的changefreq也不一定很高。

    下面就让我们从首页说起。

    创建首页的Sitemap

    与上面创建静态页面时一样,我们也需要添加django.contrib.sitemapsINSTALLED_APPS中。

    然后,我们需要指定一个URL规则。通常来说,这个URL是叫sitemap.xml——一个约定俗成的标准。我们需要创建一个sitemaps对象来存储所有的sitemaps:

    1. url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')

    由于,我们使用的视图处理方法是django.contrib.sitemaps.views.sitemap,代码如下所示:

    1. @x_robots_tag
    2. def sitemap(request, sitemaps, section=None,
    3. template_name='sitemap.xml', content_type='application/xml'):
    4. req_protocol = request.scheme
    5. req_site = get_current_site(request)

    在这个方法里,它指定了默认模板的位置,即在template目录中。

    现在,我们需要创建几种不同类型的sitemap,如下是首页的Sitemap,它继承自Django的Sitemap类:

    1. class PageSitemap(Sitemap):
    2. priority = 1.0
    3. changefreq = 'daily'
    4. def items(self):
    5. return ['main']
    6. def location(self, item):
    7. return reverse(item)

    它定义了自己的priority是最高的1.0,同时每新频率为daily。然后在items里面去取它所要获取的URL,即urls.py中对应的namemain的URL。在这里我们只返回了main一个值,依据于下面的location方法中的reverse,它找到了main对应的URL,即首页。

    最后结合首页sitemap.xml的urls.py代码如下所示:

    1. from sitemap.sitemaps import PageSitemap
    2. sitemaps = {
    3. "page": PageSitemap
    4. }
    5. urlpatterns = patterns('',
    6. url(r'^$', blogpostViews.index, name='main'),
    7. url(r'^blog/(?P<slug>[^\.]+).html', 'blogpost.views.view_post', name='view_blog_post'),
    8. url(r'^comments/', include('django_comments.urls')),
    9. url(r'^admin/', include(admin.site.urls)),
    10. url(r'^pages/', include('django.contrib.flatpages.urls')),
    11. url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
    12. ) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

    除此,我们还需要创建自己的sitemap.xml模板——自带的系统模板比较简单。

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    3. {% spaceless %}
    4. {% for url in urlset %}
    5. <url>
    6. <loc>{{ url.location }}</loc>
    7. {% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %}
    8. {% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
    9. {% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
    10. </url>
    11. {% endfor %}
    12. {% endspaceless %}
    13. </urlset>

    最后,我们访问http://localhost:8000/sitemap.xml,我们就可以获取到我们的sitemap.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    3. <url>
    4. <loc>http://www.phodal.com/</loc>
    5. <changefreq>daily</changefreq>
    6. <priority>1.0</priority>
    7. </url>
    8. </urlset>

    下一步,我们仍可以直接创建出对应的静态页面的Sitemap。

    创建静态页面的Sitemap

    相似的,我们也需要从items方法中,定义出我们所要创建页面的对象。

    1. from django.contrib.sitemaps import Sitemap
    2. from django.core.urlresolvers import reverse
    3. from django.apps import apps as django_apps
    4. class FlatPageSitemap(Sitemap):
    5. priority = 0.8
    6. def items(self):
    7. Site = django_apps.get_model('sites.Site')
    8. current_site = Site.objects.get_current()
    9. return current_site.flatpage_set.filter(registration_required=False)

    只不过这个方法可能会稍微麻烦一些,我们需要从数据库中取出当前的站点。再取出当前站点中的flatpage集合,对过滤那些不需要注册的页面,即代码中的registration_required=False

    最后再将这个对象放入sitemaps即可:

    1. from sitemap.sitemaps import PageSitemap, FlatPageSitemap
    2. sitemaps = {
    3. "page": PageSitemap,
    4. 'flatpages': FlatPageSitemap
    5. }

    现在,我们可以完成博客的Sitemap了。

    创建博客的Sitemap

    同上面一样的是,我们依然需要在items方法中返回所有的博客内容。并且在lastmod中,返回这篇博客的发表日期——以免他们返回的是同一个日期:

    1. class BlogSitemap(Sitemap):
    2. changefreq = "never"
    3. priority = 0.5
    4. def items(self):
    5. return Blogpost.objects.all()
    6. def lastmod(self, obj):
    7. return obj.posted

    最近我们的Sitemap.xml,如下所示:

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    3. <url>
    4. <loc>http://www.phodal.com/about/</loc>
    5. <priority>0.8</priority>
    6. </url>
    7. <url>
    8. <loc>http://www.phodal.com/</loc>
    9. <changefreq>daily</changefreq>
    10. <priority>1.0</priority>
    11. </url>
    12. <url>
    13. <loc>http://www.phodal.com/blog/hello.html</loc>
    14. <lastmod>2016-03-24</lastmod>
    15. <changefreq>never</changefreq>
    16. <priority>0.5</priority>
    17. </url>
    18. </urlset>

    提交到搜索引擎

    这里我们以Google Webmaster为例简单的介绍一下如何使用各种站长工具来提交sitemap.xml。

    我们可以登录Google的Webmaster:https://www.google.com/webmasters/tools/home?hl=zh-cn,然后点击添加属性来创建一个新的网站:

    添加网站

    这时候Google需要确认这个网站是你的,所以它提供几种方法来验证,除了下面的推荐方法:

    推荐的验证方式

    我们可以使用下面的这一些方法:

    备选的难方法

    我个人比较喜欢用HTML Tag的方式来实现

    HTML标签验证

    在我们完成验证之后,我们就可以在后台手动提交Sitemap.xml了。

    提交Sitemap.xml

    点击上方的添加/测试站点地图即可。