用Django2.0搭建一个博客

2018-03-13 | Tags: 博客搭建

缘起

近来觉得想记录一下平时学习的东西,又苦于写了笔记自己常常不会去看,时间久了又都淡忘了,正好手上有一台服务器,干脆自己搭个博客,有空的时候记录一下,也方便常常浏览。

工具选择

一般最常见的选择是WordPress,提供了前后台一站式博客搭建功能,还有大量的模版和插件可以用,不过WordPress的后台基于PHP,没有什么开发经验,而且WordPress相对有些臃肿,修改不方便,这次就不选择了。

还有一些基于Github生成静态站点的工具,如hexo, Jekyll等,这些工具的特点是非常轻量级,不需要后台服务器,可以托管在Github上,免去了搭建和配置服务器的麻烦。但是静态站点因为没有后台服务支持,有些动态功能比如搜索、评论等比较难以实现。

基于简单易开发和高扩展的考虑,这里选择了使用Django开发了几个简单的页面,完全满足当前的需求,并且有足够的自由度进行各种功能的开发。

环境配置

搭建python环境一般使用virtualenv,可以创建一个独立的Python运行环境,和其他环境隔离开,保证独立配置不会被干扰。

首先安装virtualenv:

[sudo] pip install virtualenv

然后选择安装 virtualenvwrapper ,它提供了一系列命令,帮助便捷的管理虚拟环境。

安装virtualenvwrapper:

[sudo] pip install virtualenvwrapper

在当前shell窗口启用virtualenvwrapper:

export WORKON_HOME=~/Envs
source /usr/local/bin/virtualenvwrapper.sh

这里的WORKON_HOME表示统一存放虚拟环境的位置在~/Envs,这里可以自己定义。 如果virtualenvwrapper.sh脚本不在/usr/local/bin下的话,可以到/usr/bin下寻找或使用which virtualenvwrapper.sh查看具体位置。

如果要使virtualenvwrapper一直有效的话,把上面两行启用命令写入shell启动脚本中(一般是~/.bashrc,或~/.profile)

配置好virtualenvwrapper之后就可以建一个新的虚拟环境作为之后的开发环境,这边使用python3作为基础python版本,并安装最新的Django2.0。

mkvirtualenv --python=python3 blogenv

mkvirtualenv之后会自动进入到blogenv环境中,之后可以通过deactivateworkon blogenv退出和进入blogenv环境。

进入python验证一下当前环境的python版本:

(blogenv)  ~  python
Python 3.6.3 (default, Oct  9 2017, 12:11:29) 
[GCC 7.2.1 20170915 (Red Hat 7.2.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information

安装最新版本的Django

pip install django

Django2.0和1.x相比,增加了一些特性方便进行网站的开发,What’s new in Django2.0 文档中一共列出了三个新的特性:

  1. 更简单的URL路由语法 (Simplified URL routing syntax)
  2. admin应用的针对移动设备的优化改进(Mobile-friendly contrib.admin)
  3. 支持SQL开窗表达式(Window expressions)

到这里Django的基本环境就配置好了

博客搭建

Django的运行简介

简单来说,Django运行主要主要基于mvt模型,分别是model layer,view layer, template layer。

  1. model layer主要是抽象了一个通用方法层用于组织和操作网站中用到的数据。
  2. view layer主要用于响应用户的访问请求并返回结果。
  3. template layer主要用于渲染展示给用户的页面,可以方便的插入python传递过来的数据。

建立Django项目

进入blogenv环境,之后默认操作都在blogenv环境下。

workon blogenv

通过django-admin新建一个名为blog的目录,并在blog目录建立一个为main的app目录

django-admin startproject blog
cd blog
python manage.py startapp main

此时的目录结构是这样的

.
├── blog
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   └── settings.cpython-36.pyc
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── main
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── manage.py

这里需要在blog/settings.py的INSTALLED_APPS 列表中加入对main的支持

INSTALLED_APPS = [
    # [...]
    'main',
]

接下来就可以开始在main目录下开发博客相关的功能了。

编辑model layer

model layer主要用于处理网站中用到的数据,并抽象和统一化对数据库对操作,在博客中自然主要就是文章的数据了。首先确认在blog/settings.py中对数据库后台的设定,这边方便起见使用python自带的sqlite,如果要使用其他的数据库修改为相应的配置即可。

DATABASES = {
     'default': {
    ¦   'ENGINE': 'django.db.backends.sqlite3', 
    ¦   'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

然后打开main/models.py,添加如下代码

class Article(models.Model):
¦   title = models.CharField(max_length=30)
¦   content = models.TextField()
¦   date = models.DateTimeField()

这里表示会在数据库中建立一个名为Atricle的model,一共有title,content,date三个字段,即文章的标题,内容和日期这三项最基本的内容。一个model是一个对网站数据的定义,包括了各项基本字段和数据的各种行为。每个model都会最终操作数据库中的所相对应的数据表。

然后我们可以利用强大的Django Admin后台,作为我们博客的后台编辑页面。打开main/admin.py,添加如下代码:

from main.models import Article
admin.site.register(Article)

这里将之前定义的Article注册到Admin后台中。

然后需要建立Article和Admin所需要的数据表,并建立一个在项目的根目录shell中执行:

(blogenv)  python manage.py makemigrations
(blogenv)  python manage.py migrate
(blogenv)  python manage.py createsuperuser

然后将网站服务运行起来,就可以访问Admin后台了:

(blogenv) python manage.py runserver

这里默认将服务起到本机的8000端口,如果被占用了可以在命令最后添加其他端口号,如果成功启动就可以访问http://127.0.0.1:8008/admin/进入Admin后台界面了。

登入之后的界面如下: Admin后台

点击Article之后的Add就可以添加新的博客文章了: Admin文章

点击Article可以进入文章列表,添加或者修改文章: Admin文章

这里的Article Object是我们之前在main/models.py中定义的Article类的默认名称,为了可以在Article类中添加__str__方法定义显示的名称,修改后的代码如下:

class Article(models.Model):
    title = models.CharField(max_length=30)
    content = models.TextField()
    date = models.DateTimeField()

    def __str__(self):
        return self.title

Admin文章

使用使用view layer建立url映射

后台现在已经有了文章之后我们怎么把它显示出来呢?

我们要有不同的url路径来对不同页面进行访问,我们首先建立一个index页面显示所有文章的列表,然后用article+文章编号的页面来访问不同的文章,这边我们可以编辑blog/urls.py加入这两个页面的URL访问规则:

from main import views as main_views

urlpatterns = [
    path('admin/', admin.site.urls),

    path('', main_views.index),
    path('article/<int:article_id>', main_views.article_id),
]

在Django2中,这里path的第一个参数表示url的路由规则, 第二个参数表示需要调用对应的函数,这里添加的两个规则分别表示将对/的url路径访问调用main_views.index()函数和对/article/id的url路径访问调用main_views.article_id(id)函数,其中id是一个可以被捕获的int值,这样就起到了访问不同id的文章的功能。

其中main_views.index()和main_views.article_id(id)的实现如下

def index(request):
    articles = Article.objects.filter(is_show=True).order_by('-date')
    context = {
        'articles': articles,
    }
    return render(request, 'main/index.html', context)


def article_id(request, article_id):
    try:
        article = Article.objects.get(id=article_id)
    except Exception as e:
        print(e.with_traceback, e)

    if article is not None:
        return render(request, 'main/article.html', {
            'article':article,
            'date': article.date.strftime("%Y-%m-%d"),
            'content': markdown.markdown(article.content),
            })

根据请求在model Article中查找对应的文摘,并传到对应的template中进行渲染,就可以生成最后返回给用户的网页了。

建立template layer

django template是一个类似于html语法的文件,但是其中可以额外插入django传入的实时数据,达成动态生成页面的能力。

template 文件通常放在当前django app的template·目录下,如上文中return render(request, 'main/index.html', context)main/index.html,django会自动查找main/template/main/index.html,其实现如下

{% extends "main/base.html" %}
{% load staticfiles %}
{% load i18n %}

{% block content %}
<div class='mtb-15'>
    <div class='container'>
        <div class='row main-title' >
            <p><b>文章</b></p>
            <hr>
        </div>
        <div class='row'>
            {% for article in articles %}
            <div class='article-title'>
                <p><span>{{ article.date|date:"Y-m-d" }} <span>
                        <a href="blog/{{ article.id }}">{{ article.title }}</a></p>
            </div>
            {% endfor %}
        </div>
    </div>
</div>
{% endblock %}

其中extends "main/base.html"表示本文件继承了main/base.html,是base.html的扩展。在base.html`中可以实现一些页面的公共部分,比如<head>,<footer>,网页标头等等。

load staticfilesload i18n 表示加载了静态文件和多语言的功能模块

block content 表示将里面的内容填充到base.html对应标示block content的部分,其中block是关键字,content是要填充内容的标识,可以自己定义多种标识来进行对应的填充。

block content 内部, {% for article in articles %}中的articles对应了main_views.index()传入的字典中的articles字段,这里可以我们将articles进行遍历,并将内部所有的article的data,id和title渲染到页面中,形成了整个主页的内容。

结束

到这里,我们的blog基本成型了,可以通过127.0.0.1:8000/访问主页,通过127.0.0.1:8000/blog/<id>访问对应的文章。然后就可以发挥我们的聪明才智,在这个基础上不断添加新的有趣的功能,搭建我们自己心中完美的blog了。

本站整体代码可以访问我的github,供参考。