全棧一路坑之使用django建立博客

最近在看一篇全棧增加工程師實戰,而後學習裏面的項目,結果發現做者用的技術太過老舊,好多東西都已經被拋棄了,因此結合着官方文檔和本身的一些理解將錯誤的信息替換一下,邊寫邊學習php

準備工做和工具

做者說須要一些python基礎,可是中國程序員是最好的程序員,沒有基礎照樣看,大不了遇到不懂的現學就是嘍css

須要在計算機上安裝一些工具html

  • Python環境及包管理工具pip
  • 一款瀏覽器,推薦Chrome,固然,用本身喜歡的瀏覽器也能夠
  • 版本控制,推薦用Git,可是不少培訓機構出來的只會SVN,因此這個沒有什麼重要的
  • 一款IDE,我用的是pycharm,我的感受還挺好用的

 Django簡介

用來充字數的段落而已,估計讀技術書籍的沒人關心,值得一提的是Django是一個MTV架構,之前或許會有面試官問問MVC之類的表明什麼含義,但如今各類框架,各類標準,已經無法記了,但大致意思是將視圖層分爲兩層,一層Template模板,一層View視圖層,感受有點畫蛇添足python

Django應用架構

Django每個模塊在內部都稱之爲APP,每一個APP都有本身的三層架構jquery

安裝Django

這裏有一個新東西,是相似於php的XAMPP或者MAMP的一個集成環境,能夠避免機器被污染,仍是挺有用的,叫作virtualenv,安裝它的話須要使用python的包管理工具pip,若是沒有安裝pip的,按照下面的命令安裝linux

curl https://bootstrap.pypa.io/get-pip.py | python

 

做者在這裏使用的是pip3,也就是python3,可是據個人瞭解,如今市場,尤爲是中國,python3仍是沒有使用的,python2.7纔是王道,因此老老實實的用2.7安裝吧git

$ pip install virtualenv

 

而後就是要用這個工具建立一個工做區間了程序員

$ mkdir somewhere/virtualenvs
$ virtualenv somewhere/virtualenvs/<project-name> --no-site-packages

 

工做區間名隨便起,雖然寫着是項目名,但項目名是在後面指定的,而後到相應的目錄,啓動集成環境github

$ cd somewhere/virtualenvs/<project-name>/bin
$ source activate

 

要關閉環境須要使用web

$ deactivate

 

虛擬環境和工做區間安裝好以後,開始安裝Django

$ pip install django

 

下載完成以後,會本身安裝,而後Django給咱們提供了一個管理工具,能夠用它來控制一些東西,和Laravel中的Artisan是同樣的效果

建立項目

建立的項目名能夠隨便起,我這裏起名爲blog,執行下面代碼

$ django-admin startproject blog

 

執行完以後會建立一個blog的文件夾,進入文件夾以後就看到了生成的東西

blogpost,.gitignore,db.sqlite3都是後來生成的,至於裏邊每一個文件都是幹什麼不適合在一塊兒講述,後邊遇到哪一個再解釋是幹什麼的,都則字太多了誰都沒有興趣看。接下來咱們就能夠運行期一個服務器,來看看第一個成果,執行下面命令

python manage.py runserver

 

若是沒有報錯,打開瀏覽器,輸入網址http://127.0.0.1:8000,應該就能夠看到以下圖那樣的頁面了,一些簡單的英文閱讀問題應該不大

而後咱們須要建立一個管理員能夠登陸的後臺,Django已經本身提供了這個功能,咱們先須要運行數據遷移建立數據庫,數據遷移是比較新的技術都帶着的一項功能,爲了項目切換數據庫或者部署的時候方便一點,遷移的時候往哪兒遷移就看配置文件了,Django的配置文件是settings.py,在本項目由中應該是位於根目錄下的blog文件夾裏,打開能夠看到以下所示的默認配置

執行下面代碼,就會在根目錄看到新建立的數據庫db.sqlite3了

$ python manage.py migrate

 

而後建立一個超級管理員帳號,注意此處密碼最少要8位,不再是當年的一個1能夠解決的了

$ python manage.py createsuperuser

 

建立完成以後就能夠打開瀏覽器看一看了

 

寫到這兒差很少該出去遛個彎吃個飯,打個爐石啥的了,但就怕走開的這段時間你的電腦忽然起火什麼的,爲了防止代碼丟失,因此咱們還須要作相應的版本控制,就是咱們剛開始說的準備的工具git。做者用的是命令行的git,但我覺的不夠直觀,因此我直接用IDE裏的git,就是Pycharm。打開最下面的Terminal,會看到一個命令行之類的東西,在這裏執行命令更直觀一點。剛開始使用git的時候須要先初始化一個倉庫

git init

 

建立成功以後就能夠將全部的文件提交到版本控制裏了

git add .

 

.表明全部的文件,可是數據庫不能上傳到版本控制裏,一個是由於太大,另外一個是由於若是裏邊有重要數據,而且你將你的代碼在一些開源平臺上託管的話,別人就能垂手可得的得到你的數據了,因此使用reset命令來重置數據庫的狀態

git reset db.sqlite3

 

可是每次這樣操做的話會很麻煩,因此須要添加一個忽略文件.gitignore來忽略數據庫的修改,爲了方便起見直接用vim建立一個文件,並輸入相應的信息

vim .gitignore

 

而後將剛剛建立的忽略文件添加到版本控制中去

git add .gitignore

 

而後提交代碼到本地

git commit -m "init project"

 

引號中的內容就是提交信息,若是你想把代碼存儲到一些遠程倉庫裏去的話就須要將代碼push上去,但若是你沒有事先配置的話世界使用push會報錯,因此我直接使用IDE提供的引入版本控制功能

輸入你的用戶名和密碼就能夠鏈接到github而後將代碼push到github上從而讓更多的人看到了。

而後咱們須要建立一個博文模塊,名字是blogpost

django-admin startapp blogpost

 

而後建立博文的model,打開models.py,而後輸入下面代碼

from __future__ import unicode_literals

from django.db import models
from django.db.models import permalink


# Create your models here.
class Blogpost(models.Model):
    title = models.CharField(max_length=100, unique=True)
    author = models.CharField(max_length=100, unique=True)
    slug = models.CharField(max_length=100, unique=True)
    body = models.TextField()
    posted = models.DateField(db_index=True, auto_now_add=True)

    def __unicode__(self):
        return '%s' % self.title

    @permalink
    def get_absolute_url(self):
        return ('view_blog_post', None, {'slug': self.slug})

 

__unicode__函數是用來實現unicode功能的,當對Blogpost對象使用unicode的時候,就會返回它的title.db_index是講posted設置爲索引,auto_now_add是設置時間爲添加時的時間,修改後時間不會動。而後做者在這裏註冊出了問題,害的我辛苦了很久不見成功。註冊的時候是須要在blog/settings.py文件中註冊,而不是在做者所謂的admin中註冊。打開settings.py,將blogpost寫入INSTALLER_APPS中,以下所示

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blogpost'
]

 

而後須要在管理員管理界面能看到博文模塊,因此須要在admin.py中註冊blogpost模塊,打開blogpost/admin.py,把它編輯成這樣

from django.contrib import admin

# Register your models here.
from .models import Blogpost


class BlogpostAdmin(admin.ModelAdmin):
    exclude = ['posted']
    prepopulated_fields = {'slug': ('title',)}


admin.site.register(Blogpost, BlogpostAdmin)

 

 exclude用來排除掉posted字段,prepopulated_fields指定博文的slug和title是同樣的。接着咱們須要作數據庫遷移,好將生成的模型遷移到數據庫中

python manage.py migrate

 

打開瀏覽器就能看到以下結果

完成一部分,將代碼推送到Github上,提交信息寫了「建立博文模塊」

如今須要修改相應的路由來訪問博客,Django的路由在blog/urls.py中,可是一路過來感受做者在這兒的順序有點亂,官方文檔和序貫都是先寫出了view再建立路由,而做者直接建立了路由,讓我在閱讀的時候非常苦惱,做者這兒爲何要這麼寫。因此我決定先建立視圖,再去修改路由。

首先建立博客列表頁,打開blog/views.py,添加index視圖,顯示博客頁的列表

from django.shortcuts import render, render_to_response, get_object_or_404
from blogpost.models import Blogpost


# Create your views here.
def index(request):
    return render_to_response('index.html', {'posts': Blogpost.objects.all()[:5]})

 

然而這仍是不夠的,這頁是這個框架比較糟糕的地方,還須要再寫一個模板才能顯示出來,首先在blogpost文件夾下建立一個templates的文件夾,用來存放相應的模板文件,Django將會在這裏查找模板文件,Django不會本身建立也是醉了,官方的建議是在這個文件夾中再建立一個名字爲blogpost的文件夾,怕命名污染,感受這裏有點違背python的設計理念,多是我技術不夠,還沒法體會這個框架的優勢。因此按照官方的方法來,建立好對應的文件夾,而後在裏面建立一個index.html的文件,以下

{% extends 'base.html' %}
{% block title %}
    Welcome to my blog
{% endblock %}

{% block content %}
    <h1>Posts</h1>
    {% for post in posts %}
        <h2><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
        <p>{{ post.posted }} - By {{ post.author }}</p>
        <p>{{ post.body }}</p>
    {% endfor %}

{% endblock %}

 

在這段代碼裏顯然做者用到了一個叫base.html的頁面,而後做者很不負責的依然沒有給出來,我去他的源代碼中扒出了這個頁面,如今將它放在templates目錄下 ,代碼以下

{% load staticfiles %}
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>{% block head_title %}Welcome to my blog{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}">
</head>
<body data-twttr-rendered="true" class="bs-docs-home">
<header class="navbar navbar-static-top bs-docs-nav" id="top" role="banner">
    <div class="container">
        <div class="navbar-header">
            <button class="navbar-toggle collapsed" type="button" data-toggle="collapse"
                    data-target=".bs-navbar-collapse">
                <span class="sr-only">切換視圖</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a href="/" class="navbar-brand">Growth博客</a>
        </div>
        <nav class="collapse navbar-collapse bs-navbar-collapse" role="navigation">
            <ul class="nav navbar-nav">
                <li>
                    <a href="/pages/about/">關於我</a>
                </li>
                <li>
                    <a href="/pages/resume/">簡歷</a>
                </li>
            </ul>
            <ul class="nav navbar-nav navbar-right">
                <li><a href="/admin" id="loginLink">登入</a></li>
            </ul>
            <div class="col-sm-3 col-md-3 pull-right">
                <form class="navbar-form" role="search">
                    <div class="input-group">
                        <input type="text" id="typeahead-input" class="form-control" placeholder="Search" name="search" data-provide="typeahead">
                        <div class="input-group-btn">
                            <button class="btn btn-default search-button" type="submit"><i class="glyphicon glyphicon-search"></i></button>
                        </div>
                    </div>
                </form>
            </div>
        </nav>
    </div>
</header>
<main class="bs-docs-masthead" id="content" role="main">
    <div class="container">
        <div id="carbonads-container">
            THE ONLY FAIR IS NOT FAIR <br>
            ENJOY CREATE & SHARE
        </div>
    </div>
</main>
<div class="container" id="container">
    {% block content %}

    {% endblock %}
</div>
<footer class="footer">
    <div class="container">
        <p class="text-muted">@Copyright Phodal.com</p>
    </div>
</footer>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script src="{% static 'js/bootstrap3-typeahead.min.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>

 

而後,咱們還須要一個現實詳情的視圖,編輯views.py

from django.shortcuts import render, render_to_response, get_object_or_404
from blogpost.models import Blogpost


# Create your views here.
def index(request):
    return render_to_response('index.html', {'posts': Blogpost.objects.all()[:5]})


def view_post(request, slug):
    return render_to_response('blogpost_detail.html', {
        'post': get_object_or_404(Blogpost, slug=slug)
    })

 

而後就能夠編寫url使其能夠訪問了,訪問以後發現樣式全是錯的,去做者的Github上找到了樣式文件夾static,放到根目錄下,最後獲得的效果圖以下

提交代碼,準備編寫單元測試。

先來一個簡單的測試,測試首頁,在blogpost目錄下編輯tests.py文件

from django.core.urlresolvers import resolve
from django.test import TestCase
from blogpost.views import index


# Create your tests here.
class HomePageTest(TestCase):
    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/blog/')
        self.assertEqual(found.func, index)

 

運行測試

python manage.py test

 

結果顯示OK

進行下一個測試,測試頁面標題是否是咱們想要的結果

from django.core.urlresolvers import resolve
from django.http import HttpRequest
from django.test import TestCase
from blogpost.views import index, view_post


# Create your tests here.
class HomePageTest(TestCase):
    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/blog/')
        self.assertEqual(found.func, index)

    def test_home_page_returns_correct_html(self):
        request = HttpRequest
        response = index(request)
        self.assertIn(b'<title>Welcome to my blog</title>', response.content)

 

再添加一個測試測試詳情頁

from datetime import datetime

from django.core.urlresolvers import resolve
from django.http import HttpRequest
from django.test import TestCase

from blogpost.models import Blogpost
from blogpost.views import index, view_post


# Create your tests here.
class HomePageTest(TestCase):
    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/blog/')
        self.assertEqual(found.func, index)

    def test_home_page_returns_correct_html(self):
        request = HttpRequest
        response = index(request)
        self.assertIn(b'<title>Welcome to my blog</title>', response.content)


class BlogpostTest(TestCase):
    def test_blogpost_url_resolves_to_blog_post_view(self):
        found = resolve('/blog/this_is_a_test.html')
        self.assertEqual(found.func, view_post)

    def test_blogpost_create_with_view(self):
        Blogpost.objects.create(title='hello', author='admin', slug='this_is_a_test', body='This is a blog',
                                posted=datetime.now())
        response = self.client.get('/blog/this_is_a_test.html')
        self.assertIn(b'This is a blog', response.content)

 

運行測試,得

寫完了單元測試,還須要寫一些集成測試,這裏使用的是一款叫作Selenium的軟件,本來就想用這款軟件作一些測試,可是不怎麼會用,如今正好學習一下。使用以前要先安裝Selenium,直接使用pip安裝便可

而後編寫測試,自動化測試首頁是否包含」Welcome to my blog「

from datetime import datetime

from django.core.urlresolvers import resolve
from django.http import HttpRequest
from django.test import TestCase

from blogpost.models import Blogpost
from blogpost.views import index, view_post
from django.test import LiveServerTestCase
from selenium import webdriver


# Create your tests here.
class HomePageTest(TestCase):
    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/blog/')
        self.assertEqual(found.func, index)

    def test_home_page_returns_correct_html(self):
        request = HttpRequest
        response = index(request)
        self.assertIn(b'<title>Welcome to my blog</title>', response.content)


class BlogpostTest(TestCase):
    def test_blogpost_url_resolves_to_blog_post_view(self):
        found = resolve('/blog/this_is_a_test.html')
        self.assertEqual(found.func, view_post)

    def test_blogpost_create_with_view(self):
        Blogpost.objects.create(title='hello', author='admin', slug='this_is_a_test', body='This is a blog',
                                posted=datetime.now())
        response = self.client.get('/blog/this_is_a_test.html')
        self.assertIn(b'This is a blog', response.content)


class HomepageTestCase(LiveServerTestCase):
    def setUp(self):
        self.selenium = webdriver.Firefox()
        self.selenium.maximize_window()
        super(HomepageTestCase, self).setUp()

    def tearDown(self):
        self.selenium.quit()
        super(HomepageTestCase, self).tearDown()

    def test_visit_homepage(self):
        self.selenium.get('%s%s' % (self.live_server_url, "/blog"))
        self.assertIn("Welcome to my blog", self.selenium.title)

 

運行測試,ffirefox快速的一閃而過,程序正確運行,出現OK,而後繼續測試博客詳情頁

class BlogpostDetailCase(LiveServerTestCase):
    def setUp(self):
        Blogpost.objects.create(
            title='hello',
            author='admin',
            slug='this_is_a_test',
            body='This is a blog',
            posted=datetime.now
        )
        self.selenium = webdriver.Firefox()
        self.selenium.maximize_window()
        super(BlogpostDetailCase, self).setUp()

    def tearDown(self):
        self.selenium.quit()
        super(BlogpostDetailCase, self).tearDown()

    def test_vist_blog_post(self):
        self.selenium.get('%s%s' % (self.live_server_url, "/blog/this_is_a_test.html"))
        self.assertIn("hello", self.selenium.title)

 

而後測試用戶首頁點擊博客標題是否能調到對應的博客

class BlogpostFromHomepageCase(LiveServerTestCase):
    def setUp(self):
        Blogpost.objects.create(
            title='hello',
            author='admin',
            slug='this_is_a_test',
            body='This is a blog',
            posted=datetime.now
        )
        self.selenium = webdriver.Firefox()
        self.selenium.maximize_window()
        super(BlogpostDetailCase, self).setUp()

    def tearDown(self):
        self.selenium.quit()
        super(BlogpostDetailCase, self).tearDown()

    def test_visit_blog_post(self):
        self.selenium.get('%s%s' % (self.live_server_url, "/blog"))
        self.selenium.find_element_by_link_text("hello").click()
        self.assertIn("hello", self.selenium.title)

 

測試完沒有問題以後,就可使用上面寫的測試搭建集成測試了,做者在這裏犯了一個想固然的錯誤,須要github的推送,就須要將代碼部署到服務器上去,在本地的話github的post是收不到的,我在本身的服務器上搭建了jenkins服務器,具體安裝沒遇到問題,因此就不在這裏說了,百度上能找到不少的教程。安裝好以後訪問服務器的網址加8080端口,就能看到安裝頁面了,安裝的時候會提示一串字符串密碼,須要記錄下來輸入剛開始的頁面裏。我下載的是2,千萬不要下載1的穩定版。

我選擇安裝全部建議的插件,安裝過程確實至關緩慢,能夠站起來活動一下去接個水之類的,反正我是這麼幹的

安裝好以後,就是要建立用戶名和密碼了,而後到了主界面,建立一個任務

源碼管理選擇git,而後輸入git的倉庫地址,構建觸發器選擇Github的那個,而後點擊增長構建步驟,選擇execute shell,這裏又卡了我兩天,剛開始是各類命令找不到,若是是按照我說的在linux下的話就不用擔憂了,下面是個人shell腳本

virtualenv  python
source python/bin/activate
pip install -r requirements.txt
python manage.py test

 

而後想要提交後就出發構建的話,還須要去github裏配置鉤子

而後當代碼提交到github上的時候就能夠自動構建了,而後,事情的進展每每會往你最不想看到的結果發展的,結果可視化測試果真出錯了,報的錯說瀏覽器沒有打開,不過想一想linux連桌面系統都沒裝,天然無法打開。而後安裝了一款虛擬桌面軟件xfvb,而後再安裝python的pyvirtualdisplay的模塊,將測試代碼修改成以下這樣,就能夠正常測試了

from datetime import datetime

from django.core.urlresolvers import resolve
from django.http import HttpRequest
from django.test import TestCase

from blogpost.models import Blogpost
from blogpost.views import index, view_post
from django.test import LiveServerTestCase
from selenium import webdriver
from pyvirtualdisplay import Display

#test
class HomePageTest(TestCase):
    def test_root_url_resolves_to_home_page_view(self):
        found = resolve('/blog/')
        self.assertEqual(found.func, index)

    def test_home_page_returns_correct_html(self):
        request = HttpRequest
        response = index(request)
        self.assertIn(b'<title>Welcome to my blog</title>', response.content)


class BlogpostTest(TestCase):
    def test_blogpost_url_resolves_to_blog_post_view(self):
        found = resolve('/blog/this_is_a_test.html')
        self.assertEqual(found.func, view_post)

    def test_blogpost_create_with_view(self):
        Blogpost.objects.create(title='hello', author='admin', slug='this_is_a_test', body='This is a blog',
                                posted=datetime.now())
        response = self.client.get('/blog/this_is_a_test.html')
        self.assertIn(b'This is a blog', response.content)


class HomepageTestCase(LiveServerTestCase):
    def setUp(self):
        self.display = Display(visible=0, size=(1024, 768))
        self.display.start()
        self.selenium = webdriver.Firefox()
        self.selenium.maximize_window()
        super(HomepageTestCase, self).setUp()

    def tearDown(self):
        self.selenium.quit()
        self.display.stop()
        super(HomepageTestCase, self).tearDown()

    def test_visit_homepage(self):
        self.selenium.get('%s%s' % (self.live_server_url, "/blog"))
        self.assertIn("Welcome to my blog", self.selenium.title)


class BlogpostDetailCase(LiveServerTestCase):
    def setUp(self):
        Blogpost.objects.create(
            title='hello',
            author='admin',
            slug='this_is_a_test',
            body='This is a blog',
            posted=datetime.now
        )
        self.display = Display(visible=0, size=(1024, 768))
        self.display.start()
        self.selenium = webdriver.Firefox()
        self.selenium.maximize_window()
        super(BlogpostDetailCase, self).setUp()

    def tearDown(self):
        self.selenium.quit()
        self.display.stop()
        super(BlogpostDetailCase, self).tearDown()

    def test_vist_blog_post(self):
        self.selenium.get('%s%s' % (self.live_server_url, "/blog/this_is_a_test.html"))
        self.assertIn("hello", self.selenium.title)


class BlogpostFromHomepageCase(LiveServerTestCase):
    def setUp(self):
        Blogpost.objects.create(
            title='hello',
            author='admin',
            slug='this_is_a_test',
            body='This is a blog',
            posted=datetime.now
        )
        self.display = Display(visible=0, size=(1024, 768))
        self.display.start()
        self.selenium = webdriver.Firefox()
        self.selenium.maximize_window()
        super(BlogpostFromHomepageCase, self).setUp()

    def tearDown(self):
        self.selenium.quit()
        self.display.stop()
        super(BlogpostFromHomepageCase, self).tearDown()

    def test_visit_blog_post(self):
        self.selenium.get('%s%s' % (self.live_server_url, "/blog"))
        self.selenium.find_element_by_link_text("hello").click()
        self.assertIn("hello", self.selenium.title)

 

最後測試一次,完美

django有不少自帶的功能,而後使用自帶的功能來作一個簡單的評論功能,先安裝flatpages,首先添加兩個應用到settings.py文件的INSTALLED_APPS中

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blogpost',
    'django.contrib.sites',
    'django.contrib.flatpages'
]

 

而後添加中間件

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
]

 而後修改url

而後這兒實際上是一個重點,可是做者卻一筆帶過,致使我看的沒頭沒尾的,Django有一個可選的簡單頁面的應用,它可讓你存儲簡單的扁平化結構的HTML內容在數據庫中,你能夠經過Django的管理界面和一個Python API處理要管理的內容。

一個浮動頁面是一個簡單的包含有URL,標題和內容的對象。使用它做爲一次性,特殊用途的頁面,好比關於咱們或者隱私政策的頁面,那些你想要保存在數據庫,可是又不想開發一個自定義的Django應用。

一個簡單的頁面應用能夠是用自定義的模板或者系統默認的模板,系統的單頁面模板,他能夠和一個或者多個站點相關聯

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^blog/$', 'blogpost.views.index'),
    url(r'^blog/(?P<slug>[^\.]+).html', 'blogpost.views.view_post', name='view_blog_post'),
    url(r'^admin/', admin.site.urls),
    url(r'^pages/', include('django.contrib.flatpages.urls')),
]

最後,再作一個數據遷移

python manage.py migrate

 

而後在根目錄下面建立一個templates的文件夾,在templates中建立flatpages文件夾用來存放模板,而後建立about.html

{% 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 %}

 

而後登錄後臺,添加對應的靜態頁面

而後訪問127.0.0.1:8000/pages/about就會發現,模板不存在,這裏又是做者挖的一個坑,Django的默認模板文件夾是在每一個APP下面,然而做者是直接在最外邊建了一個模板文件夾,而後修改了settings.py卻沒有告訴讀者。因此我這裏仍是按照django的規矩,將模板文件夾建在blogpost內,以下圖所示

而後再次訪問上述網址,一切正常,天下大吉

接下來纔要正式進入正題,爲咱們的博客添加評論功能了

安裝comments包

pip install django-contrib-comments

 

而後從新生成依賴文件

pip freeze > requirements.txt

 

而後將comments包添加到INSTALLED_APPS中

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blogpost',
    'django.contrib.sites',
    'django.contrib.flatpages',
    'django_comments'
]

 

進行數據庫遷移

python manage.py migrate

 

修改url

urlpatterns = [
    url(r'^$', 'blogpost.views.index'),
    url(r'^blog/(?P<slug>[^\.]+).html', 'blogpost.views.view_post', name='view_blog_post'),
    url(r'^admin/', admin.site.urls),
    url(r'^pages/', include('django.contrib.flatpages.urls')),
    url(r'^comments/', include('django_comments.urls')),
]

 

而後登錄後臺添加一些評論

添加完評論報了以下的錯誤

是由於沒有安裝pytz這個包致使的,安裝pytz並重啓runserver

pip install pytz

 

而後要在首頁上顯示,修改博客詳情頁

{% extends 'base.html' %}

{% block head_title %}{{ post.title }}{% endblock %}
{% block title %}{{ post.title }}{% endblock %}

{% block content %}
    <div>
        <div>
            <h2><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
        </div>
        {{ post.body }}
        <p>
            {{ post.posted }} - By {{ post.author }}
        </p>
    </div>
    {% render_comment_list for post %}
{% endblock %}

 

而後,我依然沒有找到評論在哪兒顯示,坑實在是太多了,等之後整明白了再來這兒補充吧。

接着再來玩玩SEO

安裝sitemaps,網站地圖是用來告訴搜索引擎你的頁面更新頻率和頁面之間關係的的一個XML文件

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blogpost',
    'django.contrib.sites',
    'django.contrib.flatpages',
    'django_comments',
    'django.contrib.sitemaps',
]

在根目錄下建立一個sitemap的目錄用來保存站點地圖,建立sitemaps.py,priority是搜索引擎的優先級,changefreq是更新頻率,items方法用來返回對象的列表,在這裏只返回含有一個元素的列表,就是main,而後後面的location方法是根據items()返回的對象列表返回絕對路徑,就是返回main的絕對路徑。

from django.contrib.sitemaps import Sitemap
from django.core.urlresolvers import reverse


class PageSitemap(Sitemap):
    priority = 1.0
    changefreq = 'daily'

    def items(self):
        return ['main']

    def location(self, obj):
        return reverse(obj) 

而後修改urls.py

from django.conf.urls import url, include
from django.contrib import admin
from django.contrib.sitemaps.views import sitemap
from sitemap.sitemaps import PageSitemap

sitemaps = {
    "page": PageSitemap
}

urlpatterns = [
    url(r'^$', 'blogpost.views.index', name='main'),
    url(r'^blog/(?P<slug>[^\.]+).html', 'blogpost.views.view_post', name='view_blog_post'),
    url(r'^admin/', admin.site.urls),
    url(r'^pages/', include('django.contrib.flatpages.urls')),
    url(r'^comments/', include('django_comments.urls')),
    url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
]

 

而後訪問http://127.0.0.1:8000/sitemap.xml

而後建立靜態頁面的sitemap,先從數據庫中取出當前的站點,在取出當前站點中的flatpage集合,使用registration_required=False過濾那些不須要註冊的頁面

class FlatPageSitemap(Sitemap):
    priority = 0.8

    def items(self):
        Site = apps.get_model('sites.Site')
        current_site = Site.objects.get_current()
        return current_site.flatpage_set.filter(registration_required=False)

 

而後修改urls.py

from sitemap.sitemaps import PageSitemap, FlatPageSitemap

sitemaps = {
    "page": PageSitemap,
    'flatpages': FlatPageSitemap
}

 

而後建立博客的sitemap,在lastmod中,返回這篇博客的發表日期,一面他們返回的是同一個日期

class BlogSitemap(Sitemap):
    changefreq = 'never'
    priority = 0.5

    def items(self):
        return BlogSitemap.objects.all()

    def lastmod(self, obj):
        return obj.posted

 

from sitemap.sitemaps import PageSitemap, FlatPageSitemap, BlogSitemap

sitemaps = {
    "page": PageSitemap,
    'flatpages': FlatPageSitemap,
    'blog': BlogSitemap
}

 

最後結果以下圖

至於最後做者所說的使用站長工具的,這裏就再也不多嘗試了,本篇文章到此結束,下一篇文章中開始嘗試製做一些API

相關文章
相關標籤/搜索