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


最近在看一篇全棧增長工程師實戰,然后學習里面的項目,結果發現作者用的技術太過老舊,好多東西都已經被拋棄了,所以結合着官方文檔和自己的一些理解將錯誤的信息替換一下,邊寫邊學習

准備工作和工具

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

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

  • Python環境及包管理工具pip
  • 一款瀏覽器,推薦Chrome,當然,用自己喜歡的瀏覽器也可以
  • 版本控制,推薦用Git,但是很多培訓機構出來的只會SVN,所以這個沒有什么重要的
  • 一款IDE,我用的是pycharm,個人感覺還挺好用的

 Django簡介

用來充字數的段落而已,估計讀技術書籍的沒人關心,值得一提的是Django是一個MTV架構,以前或許會有面試官問問MVC之類的代表什么含義,但現在各種框架,各種標准,已經沒法記了,但大體意思是將視圖層分為兩層,一層Template模板,一層View視圖層,感覺有點多此一舉

Django應用架構

Django每一個模塊在內部都稱之為APP,每個APP都有自己的三層架構

安裝Django

這里有一個新東西,是類似於php的XAMPP或者MAMP的一個集成環境,可以避免機器被污染,還是挺有用的,叫做virtualenv,安裝它的話需要使用python的包管理工具pip,如果沒有安裝pip的,按照下面的命令安裝

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

 

作者在這里使用的是pip3,也就是python3,但是據我的了解,現在市場,尤其是中國,python3還是沒有使用的,python2.7才是王道,所以老老實實的用2.7安裝吧

$ pip install virtualenv

 

然后就是要用這個工具創建一個工作區間了

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

 

工作區間名隨便起,雖然寫着是項目名,但項目名是在后面指定的,然后到相應的目錄,啟動集成環境

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

 

要關閉環境需要使用

$ 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM