• 欢迎访问金笔头博客,这是一个菜鸟(伪)程序员的自留地,欢迎访问我的github:点击进入

Django2.0笔记(3)-开发个人博客系统(一)

python eason 1570次浏览 5个评论 扫描二维码

开发环境

  • PyCharm 2017.3.2 (Professional Edition)
  • Python 3.6.3
  • windows 10
  • Sqlite3

本节目标

开发一个包含如下功能的博客系统:

  • 后台文章管理,包括新增、删除和编辑
  • 后台分类管理,包括新增、删除和编辑
  • 后台标签管理,包括新增、删除和编辑
  • 前台列表页展示文章概要信息、发布时间、文章分类、标签、浏览次数
  • 前台文章列表页分页展示
  • 前台文章列表页点击”阅读全文”显示文章详细内容
  • 前台文章详情页每刷新一次浏览次数+1

先放效果图吧

Django2.0笔记(3)-开发个人博客系统(一)

开发过程

1.新建项目

使用pycharm创建Django项目jbt_blog Django2.0笔记(3)-开发个人博客系统(一)

2.创建目录

创建项目所需目录,目录结构如下: Django2.0笔记(3)-开发个人博客系统(一)

3.创建app

使用startapp命令创建app,名字为blog Django2.0笔记(3)-开发个人博客系统(一) 将生成的blog文件夹拖入apps文件夹下,此时目录结构如下 Django2.0笔记(3)-开发个人博客系统(一)

4.注册app并配置静态文件目录

修改settings.py文件,注册新建的appblog,并配置静态文件目录,改动部分如下:

INSTALLED_APPS = [
    ......
    'apps.blog',  # 注册app
]
# 配置静态文件目录
STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static'),
    ]

5.创建模型

关于模型

  • 每一个Django 模型都继承自django.db.models.Model
  • 在模型当中每一个属性都对应一个数据库表的字段

关于数据库 本项目创建之后,默认使用的是sqlite数据库,可以通过修改settings.py来修改后端数据库设置

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

还可以设置其他数据库, 如MySQL, PostgreSQL, 为了方便, 本文使用默认数据库设置。 修改blog目录下的models.py文件,分别创建文章模型Article,类别模型Category和标签模型Tag

from django.db import models
from django.utils.timezone import now


class Tag(models.Model):
    name = models.CharField(verbose_name='标签名', max_length=64)
    created_time = models.DateTimeField(verbose_name='创建时间', default=now)
    last_mod_time = models.DateTimeField(verbose_name='修改时间', default=now)

    # 使对象在后台显示更友好
    def __str__(self):
        return self.name

    class Meta:
        ordering = ['name']
        verbose_name = '标签名称'  # 指定后台显示模型名称
        verbose_name_plural = '标签列表'  # 指定后台显示模型复数名称
        db_table = "tag"  # 数据库表名


class Category(models.Model):
    name = models.CharField(verbose_name='类别名称', max_length=64)
    created_time = models.DateTimeField(verbose_name='创建时间', default=now)
    last_mod_time = models.DateTimeField(verbose_name='修改时间', default=now)

    class Meta:
        ordering = ['name']
        verbose_name = "类别名称"
        verbose_name_plural = '分类列表'
        db_table = "category"  # 数据库表名

    # 使对象在后台显示更友好
    def __str__(self):
        return self.name


class Article(models.Model):
    STATUS_CHOICES = (
        ('d', '草稿'),
        ('p', '发表'),
    )
    title = models.CharField(verbose_name='标题', max_length=100)
    content = models.TextField(verbose_name='正文', blank=True, null=True)
    status = models.CharField(verbose_name='状态', max_length=1, choices=STATUS_CHOICES, default='p')
    views = models.PositiveIntegerField(verbose_name='浏览量', default=0)
    created_time = models.DateTimeField(verbose_name='创建时间', default=now)
    pub_time = models.DateTimeField(verbose_name='发布时间', blank=True, null=True)
    last_mod_time = models.DateTimeField(verbose_name='修改时间', default=now)
    category = models.ForeignKey(Category, verbose_name='分类', on_delete=models.CASCADE, blank=False, null=False)
    tags = models.ManyToManyField(Tag, verbose_name='标签集合', blank=True)

    # 使对象在后台显示更友好
    def __str__(self):
        return self.title

    # 更新浏览量
    def viewed(self):
        self.views += 1
        self.save(update_fields=['views'])

    # 下一篇
    def next_article(self):  # id比当前id大,状态为已发布,发布时间不为空
        return Article.objects.filter(id__gt=self.id, status='p', pub_time__isnull=False).first()

    # 前一篇
    def prev_article(self):  # id比当前id小,状态为已发布,发布时间不为空
        return Article.objects.filter(id__lt=self.id, status='p', pub_time__isnull=False).first()

    class Meta:
        ordering = ['-pub_time']  # 按文章创建日期降序
        verbose_name = '文章'  # 指定后台显示模型名称
        verbose_name_plural = '文章列表'  # 指定后台显示模型复数名称
        db_table = 'article'  # 数据库表名
        get_latest_by = 'created_time'

6.注册模型并同步数据库

修改blog目录下的admin.py注册模型

from django.contrib import admin
from .models import Article, Category, Tag

admin.site.register(Article)
admin.site.register(Category)
admin.site.register(Tag)

通过Pycharm的Tools-->Run manage.py Task依次执行makemigrationsmigrate命令同步数据库

7.显示语言、时区和分页设置

为保证登录后台时页面显示语言为中文,并且发表文章时显示时间的准确性,我们需要修改settings.py文件,改动部分如下:

LANGUAGE_CODE = 'zh-hans'  # 简体中文
TIME_ZONE = 'Asia/Shanghai'  # 上海
PAGE_NUM = 3  # 每页显示3篇文章

8.创建超级用户并登录后台发表文章

执行createsuperuser命令创建超级用户 Django2.0笔记(3)-开发个人博客系统(一) 启动开发服务器,使用刚刚创建的用户登录后台并测试发表文章 Django2.0笔记(3)-开发个人博客系统(一)

9.编写视图函数

Django中,网页和其他内容是通过视图传递的,每个视图由一个简单的Python函数表示,Django将通过检查请求的URL(准确地说,是域名后面的部分URL)来选择一个视图。本文中仅包含homedetail两个视图函数,编辑apps/blog/views.py

from django.shortcuts import render
from apps.blog.models import Article
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.http import Http404
from django.conf import settings


def home(request):  # 主页
    posts = Article.objects.all()  # 获取全部的Article对象
    paginator = Paginator(posts, settings.PAGE_NUM)  # 每页显示数量,对应settings.py中的PAGE_NUM
    page = request.GET.get('page')  # 获取URL中page参数的值
    try:
        post_list = paginator.page(page)
    except PageNotAnInteger:
        post_list = paginator.page(1)
    except EmptyPage:
        post_list = paginator.page(paginator.num_pages)
    return render(request, 'home.html', {'post_list': post_list})


def detail(request, id):  # 查看文章详情
    try:

        post = Article.objects.get(id=str(id))
        post.viewed()   # 更新浏览次数
        tags = post.tags.all()  # 获取文章对应所有标签
    except Article.DoesNotExist:
        raise Http404
    return render(request, 'post.html', {'post': post, 'tags': tags})

10.配置路由

编辑jbt_blog下的urls.py,为不同的URL配置相应的视图函数

from django.contrib import admin
from django.urls import path
from apps.blog import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home, name='home'),
    path('home/', views.home, name='home'),
    path('articles/<int:id>/', views.detail, name='detail'),
]

11.静态文件准备

本文用到的静态文件为样式文件和字体文件 Django2.0笔记(3)-开发个人博客系统(一) 下载地址:https://github.com/leeyis/jbt_blog

12.创建HTML模板文件

基础模板base.html内容如下:

<!DOCTYPE html>
{% load static %}
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %} jbt Blog {% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/pure-min.css' %}"/>
    <link rel="stylesheet" type="text/css" href="{% static 'css/grids-responsive-min.css' %}"/>
    <link rel="stylesheet" type="text/css" href="{% static 'css/blog.css' %}"/>
    <link rel="stylesheet" type="text/css" href="{% static 'css/font-awesome.min.css' %}"/>
</head>
<body>
<div id="layout" class="pure-g">
    <div class="sidebar pure-u-1 pure-u-md-1-4">
        <div class="header">
            <h1 class="brand-title"><a href="{% url 'home' %}">金笔头博客</a></h1>
            <h2 class="brand-tagline">Love Learning, Love Sharing</h2>
            <nav class="nav">
                <ul class="nav-list">
                    <li class="nav-item">
                        <a class="pure-button" href="https://github.com/leeyis/">Github</a>
                    </li>
                </ul>
            </nav>
        </div>
    </div>
    <div class="content pure-u-1 pure-u-md-3-4">
        <div>
            {% block content %}
            {% endblock %}
        </div>
    </div>
</div>
</body>
</html>

主页模板home.html继承自基础模板,页面代码如下:

{% extends "base.html" %}
{% block content %}
    <div class="posts">
        {% for post in post_list %}
            <section class="post">
                <header class="post-header">
                    <h2 class="post-title"><a href="{% url 'detail' id=post.id %}">{{ post.title }}</a></h2>
                    <p class="post-meta">
                        发布时间: <a class="post-author" href="#">{{ post.pub_time |date:'Y/m/d'}}</a>&nbsp;&nbsp;
                        分类: <a class="post-category post-category-pure" href="#">{{ post.category }}</a>&nbsp;&nbsp;
                        标签:
                        {% for tag in post.tags.all %}
                            <a class="post-category post-category-pure" href="#">{{ tag }}</a>
                        {% endfor %}&nbsp;&nbsp;
                        浏览次数:{{ post.views }}
                    </p>
                </header>

                <div class="post-description">
                    <p>
                        {{ post.content|truncatewords_html:100 }}
                    </p>
                </div>
                <div><a class="post-category post-category-design" href="{% url 'detail' id=post.id %}">阅读全文</a></div>

            </section>
        {% endfor %}
    </div><!-- /.blog-post -->
    {% if post_list.object_list and post_list.paginator.num_pages > 1 %}
        <div>
            {% if post_list.has_previous %}
                <a class="footer" href="?page={{ post_list.previous_page_number }}">
                    <i class="fa fa-angle-left"></i>&nbsp;&nbsp;上一页
                </a>
            {% endif %}
            {% if post_list.has_next %}
                <a class="footer" href="?page={{ post_list.next_page_number }}">
                    下一页&nbsp;&nbsp;<i class="fa fa-angle-right"></i>
                </a>
            {% endif %}
            </div>
    {% endif %}
{% endblock %}

文章详情页post.html也继承自基础模板,页面代码如下:

{% extends "base.html" %}
{% block content %}
<div class="posts">
        <section class="post">
            <header class="post-header">
                <h2 class="post-title">{{ post.title }}</h2>

                    <p class="post-meta">
                        发布时间: {{ post.pub_time|date:'Y/m/d H:m:s'}}&nbsp&nbsp
                        分类: <a class="post-category post-category-pure" href="#">{{ post.category }}</a>&nbsp&nbsp
                        标签:
                          {% for tag in tags %}
                            <a class="post-category post-category-pure" href="#">{{ tag }}</a>
                          {% endfor %}&nbsp;&nbsp;
                        浏览次数:{{ post.views }}
                    </p>
            </header>

                <div class="post-description">
                    <p>
                        {{ post.content }}
                    </p>
                </div>
        </section>
</div><!-- /.blog-post -->
{% endblock %}

13.测试

以上过程全部做完后,启动开发服务器,登录后台发表文章,在前台应该就可以看到效果了 Django2.0笔记(3)-开发个人博客系统(一)

代码

全部代码已分享至Github:https://github.com/leeyis/jbt_blog

有账户的不妨star一下啦~


金笔头博客, 版权所有丨如未注明 , 均为原创, 转载请注明Django2.0笔记(3)-开发个人博客系统(一)
喜欢 (4)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(5)个小伙伴在吐槽
  1. 你好博主,这一篇也有一个小问题,就是点开阅读全文,会报500的错误我是按着步骤一步一步来的,但我发现不到哪里有错,求指正一下
    sing2018-04-14 21:53 Reply 未知操作系统 | Firefox 59.0
    • 你下载github上的代码,本地run起来看看和你自己的代码哪里有差别,我看不到你的代码没办法帮你哦
      eason2018-04-16 09:21 Reply Windows 10 | Chrome 65.0.3325.181
  2. order_by('id') ?查找前一篇和查找后不同,不是已经按meta:created time??
    GNQ2018-03-12 23:14 Reply Windows 8.1 | Chrome 64.0.3282.186
    • 感谢提醒,代码已更新
      eason2018-03-13 16:52 Reply Windows 10 | Chrome 64.0.3282.186
  3. def next_article(self): return Article.objects.filter(id__gt=self.id, status='p').order_by('id').first()meta 已经是按created_time 了,为什么还要按order_by('id') def prev_article(self): return Article.objects.filter(id__lt=self.id, status='p').first()这个为什么没有 order_by('id')
    GNQ2018-03-12 23:12 Reply Windows 8.1 | Chrome 64.0.3282.186