在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,除非我們打算用這個框架去管理多個站點。代碼如下所示:
~~~
SITE_ID = 1
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'django.contrib.flatpages',
'blogpost'
)
~~~
接著,還添加對應的中間件`django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`到`settings.py`文件的`MIDDLEWARE_CLASSES`中。
然后,我們需要創建對應的URL來管理所有的靜態頁面。下面的代碼是將靜態頁面都放在pages路徑下,即如果我們有一個about的頁面,那么的URL會變成 http://localhost/pages/about/。
~~~
url(r'^pages/', include('django.contrib.flatpages.urls')),
~~~
當然我們也可以將其配置為類似于 http://localhost/about/ 這樣的URL:
~~~
urlpatterns += [
url(r'^(?P<url>.*/)$', views.flatpage),
]
~~~
最后,我們還需要做一個數據庫遷移:
~~~
Operations to perform:
Apply all migrations: contenttypes, auth, admin, sites, blogpost, sessions, flatpages, django_comments
Running migrations:
Rendering model states... DONE
Applying flatpages.0001_initial... OK
~~~
### 創建模板
接著,我們可以在`templates`目錄下創建`flatpages`文件,用于存放我們的模板文件,下面是一個簡單的模板:
~~~
{% extends 'base.html' %}
{% block title %}關于我{% endblock %}
{% block content %}
<div>
<h2>關于博客</h2>
<p>一方面,找到更多志同道合的人;另一方面,擴大影響力。</p>
<p>內容包括</p>
<ul>
<li>成長記錄</li>
<li>技術筆記</li>
<li>生活思考</li>
<li>個人試驗</li>
</ul>
</div>
{% endblock %}
~~~
當我們完成模板后,我們就需要登錄后臺,并添加對應的靜態頁面的配置:

管理員界面創建flatpage
然后從高級選項中填寫我們的靜態頁面的路徑,我們就可以完成靜態頁面的創建。如下圖所示:

flatpage高級選項
最后,還要所個鏈接加到首頁的導航中:
~~~
<li>
<a href="/pages/resume/">簡歷</a>
</li>
~~~
下面讓我們為我們的博客添加一個簡單的評論功能吧!
## 評論功能
在早期的Django版本(1.6以前)中,Comments是自帶的組件,但是后來它被從標準組件中移除了。因此,我們需要安裝comments這個包:
~~~
pip install django-contrib-comments
~~~
再把它及它的版本添加到`requirements.txt`,如下所示:
~~~
django==1.9.4
selenium==2.53.1
fabric==1.10.2
djangorestframework==3.3.3
djangorestframework-jwt==1.7.2
django-cors-headers==1.1.0
django-contrib-comments==1.7.1
~~~
接著,將`django.contrib.sites`和`django_comments`添加到`INSTALLED_APPS`,如下:
~~~
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'django_comments',
'rest_framework',
'blogpost'
)
~~~
然后做一下數據庫遷移我們就可以完成對其的初始化:
~~~
Operations to perform:
Apply all migrations: contenttypes, admin, blogpost, auth, sites, sessions, django_comments
Running migrations:
Rendering model states... DONE
Applying sites.0001_initial... OK
Applying django_comments.0001_initial... OK
Applying django_comments.0002_update_user_email_field_length... OK
Applying django_comments.0003_add_submit_date_index... OK
Applying sites.0002_alter_domain_unique... OK
(growth-django)
~~~
然后再添加URL到urls.py:
~~~
url(r'^comments/', include('django_comments.urls')),
~~~
現在,我們就可以登錄后臺,來創建對應的評論,但是這是時候評論是不會顯示到頁面上的。所以我們需要對我們的博客詳情頁的模板進行修改,在其中添加一句:
~~~
{% render_comment_list for post %}
~~~
用于顯示對應博客的評論,最近我們的模板文件如下面的內容所示:
~~~
{% extends 'base.html' %}
{% load comments %}
{% block head_title %}{{ post.title }}{% endblock %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<div class="mdl-card mdl-shadow--2dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text"><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
</div>
<div class="mdl-card__supporting-text">
{{post.body}}
</div>
<div class="mdl-card__actions">
{{post.posted}} - By {{post.author}}
</div>
</div>
{% render_comment_list for post %}
{% endblock %}
~~~
遺憾的是,當我們刷新頁面的時候,頁面報錯了,原因如下所示:

SITE_ID報錯
我們還需要定義一個`SITE_ID`,添加下面的代碼到`settings.py`文件中即可:
~~~
SITE_ID = 1
~~~
然后,我們就可以從后臺創建評論:

后臺創建評論
## Sitemap
我們在之前的文章中提到過SEO的重要性,這里只是簡單地對Sitemap的內容進行展開。
### 站點地圖介紹
Sitemap譯為站點地圖,它用于告訴搜索引擎他們網站上有哪些可供抓取的網頁。常見的Sitemap的形式是以xml出現了,如下是我博客的sitemap.xml的一部分內容:
~~~
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.phodal.com/blog/mezzanine-add-new-page/</loc>
<lastmod>2014-08-03</lastmod>
<changefreq>Monthly</changefreq>
<priority>0.2</priority>
</url>
</urlset>
~~~
從上面的內容中,我們可以發現它包含了下面的一些XML標簽:
* urlset,封裝該文件,并指明當前協議的標準。
* url,每個URL實體的父標簽。
* loc,指明頁面的URL
* lastmod(可選),內容最后的修改時間
* changefreq(可選),內容的修改頻率,用于告知搜索引擎抓取頻率。它包含的值有:`always`、`hourly`、`daily`、`weekly`、`monthly`、`yearly`、`never`
* priority(可選),范圍是從0.0~1.0,搜索引擎用于對你網站在搜索結果的排序,即內部的優先級排序。需要注意的是如果你把所有頁面的優先級設置為1,那么它就和沒有設置的效果是一樣的。
從上面的內容中,我們可以發現:
> 站點地圖能夠提供與其中列出的網頁相關的寶貴元數據:元數據是網頁的相關信息,例如網頁的最近更新時間、網頁的更改頻率以及網頁相較于網站中其他網址的重要程度。 ——內容來自 Google Sitemap幫助文檔。
現在,我們一共有三種類型的頁面:
* 首頁,通常來說首頁的priority應該是最高的,而它的`changefreq`可以設置為`daily`、`weekly`,這取決于你的博客的更新頻率。如果你是做一些UGC(用戶生成內容)的網站,那么你應該設置為`always`、`hourly`。
* 動態生成的博客詳情頁,這些內容一般很少進行改變,所以這的changefreq會比較低,如`yearly`或者`monthly`——并且沒有高的必要性,它會導致搜索引擎一直抓取你的內容。這會對服務器造成一定的壓力,并且無助于你網站的排名。
* 靜態頁面,如About頁面,它可以有一個高的`priority`,但是它的`changefreq`也不一定很高。
下面就讓我們從首頁說起。
### 創建首頁的Sitemap
與上面創建靜態頁面時一樣,我們也需要添加`django.contrib.sitemaps`到`INSTALLED_APPS`中。
然后,我們需要指定一個URL規則。通常來說,這個URL是叫sitemap.xml——一個約定俗成的標準。我們需要創建一個sitemaps對象來存儲所有的sitemaps:
~~~
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
~~~
因此,我們需要創建幾種不同類型的sitemap,如下是首頁的Sitemap,它繼承自Django的Sitemap類:
~~~
class PageSitemap(Sitemap):
priority = 1.0
changefreq = 'daily'
def items(self):
return ['main']
def location(self, item):
return reverse(item)
~~~
它定義了自己的priority是最高的1.0,同時每新頻率為`daily`。然后在items里面去取它所要獲取的URL,即`urls.py`中對應的`name`的`main`的URL。在這里我們只返回了`main`一個值,依據于下面的location方法中的`reverse`,它找到了main對應的URL,即首頁。
最后結合首頁sitemap.xml的`urls.py`代碼如下所示:
~~~
from sitemap.sitemaps import PageSitemap
sitemaps = {
"page": PageSitemap
}
urlpatterns = patterns('',
url(r'^$', blogpostViews.index, name='main'),
url(r'^blog/(?P<slug>[^\.]+).html', 'blogpost.views.view_post', name='view_blog_post'),
url(r'^comments/', include('django_comments.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^pages/', include('django.contrib.flatpages.urls')),
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
~~~
除此,我們還需要創建自己的`sitemap.xml`模板——自帶的系統模板比較簡單。
~~~
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{% spaceless %}
{% for url in urlset %}
<url>
<loc>{{ url.location }}</loc>
{% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %}
{% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
{% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
</url>
{% endfor %}
{% endspaceless %}
</urlset>
~~~
最后,我們訪問[http://localhost:8000/sitemap.xml](http://localhost:8000/sitemap.xml),我們就可以獲取到我們的`sitemap.xml`:
~~~
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.phodal.com/</loc>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
</urlset>
~~~
下一步,我們仍可以直接創建出對應的靜態頁面的Sitemap。
### 創建靜態頁面的Sitemap
相似的,我們也需要從items訪法中,定義出我們所要創建頁面的對象。
~~~
from django.contrib.sitemaps import Sitemap
from django.core.urlresolvers import reverse
from django.apps import apps as django_apps
class FlatPageSitemap(Sitemap):
priority = 0.8
def items(self):
Site = django_apps.get_model('sites.Site')
current_site = Site.objects.get_current()
return current_site.flatpage_set.filter(registration_required=False)
~~~
只不過這個方法可能會稍微麻煩一些,我們需要從數據庫中取中當前的站點。再取出當前站點中的flatpage集合,對過濾出那些不需要注冊的頁面,即代碼中的`registration_required=False`。
最近再將這個對象放入sitemaps即可:
~~~
from sitemap.sitemaps import PageSitemap, FlatPageSitemap
sitemaps = {
"page": PageSitemap,
'flatpages': FlatPageSitemap
}
~~~
現在,我們可以完成博客的Sitemap了。
### 創建博客的Sitemap
同上面一樣的是,我們依然需要在items方法中返回所有的博客內容。并且在lastmod中,返回這篇博客的發表日期——以免他們返回的是同一個日期:
~~~
class BlogSitemap(Sitemap):
changefreq = "never"
priority = 0.5
def items(self):
return Blogpost.objects.all()
def lastmod(self, obj):
return obj.posted
~~~
最近我們的Sitemap.xml,如下所示:
~~~
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.phodal.com/about/</loc>
<priority>0.8</priority>
</url>
<url>
<loc>http://www.phodal.com/</loc>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>http://www.phodal.com/blog/hello.html</loc>
<lastmod>2016-03-24</lastmod>
<changefreq>never</changefreq>
<priority>0.5</priority>
</url>
</urlset>
~~~
### 提交到搜索引擎
這里我們以Google Webmaster為例簡單的介紹一下如何使用各種站長工具來提交sitemap.xml。
我們可以登錄Google的Webmaster:[https://www.google.com/webmasters/tools/home?hl=zh-cn](https://www.google.com/webmasters/tools/home?hl=zh-cn),然后點擊添加屬性來創建一個新的網站:

添加網站
這時候Google需要確認這個網站是你的,所以它提供幾點方法來驗證,除了下面的推薦方法:

推薦的驗證方式
我們可以使用下面的這一些方法:

備選的難方法
我個人比較喜歡用HTML Tag的方式來實現

HTML標簽驗證
在我們完成驗證之后,我們就可以在后臺手動提交Sitemap.xml了。

提交Sitemap.xml
點擊上方的**添加/測試站點地圖**即可。