全栈一路坑之使用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

相关文章
相关标签/搜索