Django搭建博客(五):为博客添加后台管理功能

上一篇我们还留了一个小问题没有解决,其实这个问题我是特意留到这一篇来讲的,请往下看 ⇩

现在我们的博客已经具备了基本的页面,但是如果我想发表一篇新的文章的话,还得到数据库里手动添加。

而且如果我们想修改一篇文章的话也很麻烦,这时候一个后台管理界面就很有用了。

一、需求分析

在添加后台管理界面之前,让我们想一想需要一些什么功能:

  • 能够添加文章
  • 能够修改文章
  • 能够删除文章

还有一些功能,比如在线编辑、实时预览、markdown支持我们以后再添加。

现在我们已经把功能列出来了,接下来就是分析一下需要什么页面:

  • 查看所有文章的页面,在这个页面里应该有修改和删除文章的选项,还要有添加新文章的选项
  • 点击修改文章应该出现编辑页面
  • 点击删除文章应该出现确认页面
  • 点击添加文章应该出现文章编辑页面,这个和修改文章的页面应该是相同的

然后在修改、添加、删除文章后应该返回文章列表。

二、显示文章页面

确定下来页面我们就可以开始敲代码了,按照页面之间的逻辑关系,我们先完成显示文章列表的页面。

这个页面和我们的首页很相似,我们只需要添加几个按钮即可:

{% extends 'myblog/base.html' %}

{% block title %}Post List{% endblock %}

{% block main %}

<ul class="list-unstyled">
{% for post in pagedata.post_list %}
<li>
    <div class="row">
        <div class="col-lg-10">
            <h1><a href="{{post.get_absolute_url}}">{{post.title}}</a></h1>
            <span class="d-block">{{post.tags}}</span>
            <span class="d-block">{{post.get_format_date}}</span>
            <p>{{post.get_brief_content}}</p>
        </div>
        <div class="col-lg-2">
            <div class="row">
                <div class="col"><a href="#">修改</a></div>
            </div>
            <div class="row">
                <div class="col"><a href="#">删除</a></div>
            </div>
        </div>
    </div>
</li>
{% endfor %}
 </ul>

{% endblock %}

再把链接和视图添加上去,运行一下看看效果:

三、添加文章功能

添加一个新建文章的按钮:

现在按钮的位置都添加好了,我们分别为每个按钮添加链接,首先是添加文章的按钮,这个链接是一个固定的值,我们可以直接写到页面中去(当然,等以后页面多了肯定不能这么写,不过现在只有几个页面,所以问题不大)。

<div class="add-article">
    <a class="text-success" href="/myblog/addArticle">添加文章</a>
</div>

然后再创建一个视图和模板,再添加链接:

修改 urls.py文件:

# myblog/urls.py
from django.urls import re_path
from . import views


urlpatterns = [
    re_path(r'^index/{0,1}$', views.index),
    re_path(r'^article/\d{4,4}/\d{1,2}/(?P<title>.+)/{0,1}$', views.article),
    re_path(r'^articles/list/{0,1}$', views.article_list),
    
    re_path(r'^addArticle/{0,1}$', views.addArticle),
]

创建一个模板文件 add_article.html:

{% extends 'myblog/base.html' %}

{% block title %}Add Article{% endblock %}

{% block main %}

<div class="row">
    <div class="col">
        <form action="/myblog/addArticle" method="post">
            {% csrf_token %}
            <div class="row my-3">
                <div class="col">
                    <label for="title">标题</label>
                    <input type="text" name="title" id="title">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="tags">标签</label>
                    <input type="text" name="tags" id="tags">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="content">正文</label>
                    <textarea class="d-block" type="text" name="content" id="content"></textarea>
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <button type="submit">提交</button>
                </div>
            </div>
        </form>
    </div>
</div>

{% endblock %}

再添加一个视图函数 addArticle:

def addArticle(request):
    if request.method == 'GET':
        return render(request, 'myblog/add_article.html')
    elif request.method == 'POST':
        title = request.POST['title']
        key = abs(hash(title))
        tags = request.POST['tags']
        content = request.POST['content']
        date = datetime.datetime.now().strftime('%Y-%m-%d')

        Post(key=key, title=title, tags=tags, content=content, date=date).save()

        return HttpResponseRedirect('/myblog/articles/list/')

当请求方式为 get请求时,addArticle函数会返回 add_article页面:

当请求方式为 post时,也就是点击提交后,addArticle函数会接收页面提交的数据,并将其保存到数据库中,然后重定向到 article_list页面查看添加结果。

注意到在保存到数据库时多了一个 key参数。

这就是我们用来替换 title用来查找文章的值,key是由 title经过哈希运算得到的值,我们可以认为 key和 title是一一对应的。

这样文章链接就可以根据 key来生成。

要应用这个变化,我们还需要修改一些文件:

首先修改文章的链接:

re_path(r'^article/\d{4,4}/\d{1,2}/(?P<key>\d+)/{0,1}$', views.article),

然后修改 Post类的 get_absolute_url方法:

def get_absolute_url(self):
    return f'/myblog/article/{self.date.year}/{self.date.month}/{self.key}'

注意:

这里链接以 ” / “开头说明该链接是相对于网站根目录的链接,即最终的链接是:

http://127.0.0.1:8000/myblog/article/2018/8/1/45555555544

如果不以 ” /“开头则说明该链接是相对于当前页面的链接,假设当前页面是

http://127.0.0.1:8000/myblog/index

那么最终的链接是: http://127.0.0.1:8000/myblog/myblog/article/2018/8/1/45555555544

可以看到,myblog重复了两次,由于当前页面的不确定性,所以我们在所有的页面里都使用带反斜杠的链接。

改了上面两处还不够,我们还需要改一下 article视图函数,其实就是将 title改为了 key:

def article(request, key):
    post = Post.objects.filter(key=key).get()
    return render(
        request,
        'myblog/article.html',
        {'pagedata':
             {'post': post}
        }
    )

接下来访问一下文章详情页面 :

这样我们就把添加文章的功能给做好了,接下来我们再来完成修改文章的功能。

四、修改文章功能

首先我们先添加一个链接:

re_path(r'^modifyArticle/{0,1}$', views.modifyArticle)

再修改 articles_list.html模板文件,为每篇文章添加对应的修改链接:

<div class="row">
    <div class="col text-info">
        <a href="{{post.get_modify_url}}">修改</a>
    </div>
</div>

再给 Post类添加 get_modify_url方法:

    def get_modify_url(self):
        return f'/modifyArticle/{self.key}'

做完这些我们还需要添加一个 modify_article模板:

{% extends 'myblog/base.html' %}

{% block title %}Modify Article{% endblock %}

{% block main %}

<div class="row">
    <div class="col">
        <form action="{{pagedata.post.get_modify_url}}" method="post">
            {% csrf_token %}
            <div class="row my-3">
                <div class="col">
                    <label for="title">标题</label>
                    <input type="text" name="title" id="title" value="{{pagedata.post.title}}">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="tags">标签</label>
                    <input type="text" name="tags" id="tags" value="{{pagedata.post.tags}}">
                </div>
            </div>
            <div class="row my-3">
                <div class="col">
                    <label for="content">正文</label>
                    <textarea class="d-block" type="text" name="content" id="content">{{pagedata.post.content}}</textarea>
                </div>
            </div>
            <input type="hidden" name="key" value="{{pagedata.post.key}}">
            <div class="row my-3">
                <div class="col">
                    <button type="submit">提交</button>
                </div>
            </div>
        </form>
    </div>
</div>

{% endblock %}

这个模板和 add_article模板基本一致,我们只做了一些小的改动。

我们为每个 input标签添加了一个 value,value的值就是文章对应属性的值。

最后我们还需要添加一个视图函数 modifyArticle来处理请求:

def modifyArticle(request, key):
    if request.method == 'GET':
        post_list = Post.objects.filter(key=key)
        if len(post_list) == 0:
            return HttpResponse('文章不存在')
        else:
            return render(
                request,
                'myblog/modify_article.html',
                {'pagedata':
                     {'post':post_list[0]}
                }
            )
    elif request.method == 'POST':
        title = request.POST['title']
        key = request.POST['key']
        tags = request.POST['tags']
        content = request.POST['content']
        date = datetime.datetime.now().strftime('%Y-%m-%d')

        post = Post.objects.filter(key=key)[0]
        post.title = title
        post.tags = tags
        post.content = content
        post.date = date

        post.save()

        return HttpResponseRedirect('/myblog/articles/list/')

我们来测试一下:

现在只剩下删除功能没有做了,删除功能其实很简单,只需要添加一个确认页面,然后在数据库里执行删除操作即可,这些我就不再多写了。

最后看看整体效果:

不过我们得后台管理还有很多问题,比如:没有进行身份验证。 在下一篇我们会为博客添加身份认证机制

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏云计算教程系列

CentOS 7如何设置uWSGI和Nginx提供Python应用服务

在本指南中,我们将设置一个由uWSGI提供服务的简单WSGI应用程序。我们将使用Nginx Web服务器作为应用程序服务器的反向代理,以提供强大的连接处理。我们...

2164
来自专栏云计算教程系列

如何在Ubuntu 14.04上设置uWSGI和Nginx以服务Python应用程序

在本教程中,我们将设置一个由uWSGI提供服务的简单WSGI应用程序。我们将使用Nginx Web服务器作为应用程序服务器的反向代理,以提供更强大的连接处理。我...

2190
来自专栏HTML5学堂

wamp的使用与安装

HTML5学堂:突然发现官网里没有写关于wamp的文章,竟然没有wamp的安装,竟然真的没有wamp(利利碎碎念中),于是乎,来普及一下吧,看看wamp是什么,...

6444
来自专栏吴柯的运维笔记

如何用Rysnc实现数据同步?

Rsync(remote sync) 是UNIX及类UNIX平台一款数据镜像备份软件,它不像FTP等其他文件传输服务那样需要进行全备份,Rsync可以根据数据...

41113
来自专栏ml

JavaScript基础知识(1)

表单的确认 :       客户端确认         --减少服务器负载         --缩短用户等待时间         --兼容性难       服务...

2853
来自专栏你不就像风一样

[原创]颠覆传统网站开发模式的web服务器

以Java web举例,现在的网站系统开发模式,对于web端和服务端的数据交互以及页面渲染,无外乎两种:

1402
来自专栏云计算教程系列

如何使用Prometheus监控CentOS 7服务器

Prometheus是由SoundCloud开发的开源监控系统。与其他监控系统(如InfluxDB和Graphite)一样,Prometheus将其所有数据存储...

8980
来自专栏IMWeb前端团队

让chrome插件在手机上跑起来

本文作者:IMWeb moonye 原文出处:IMWeb社区 未经同意,禁止转载 创建一个chrome的插件,并让这个插件能够作为一个app,运行在终...

2175
来自专栏BestSDK

37个TOP实例命令,超过一半你肯定都没见过

1. Top 命令输出 首先,让我们了解一下输出。top命令会显示系统的很多信息。我们需要理解不同部分输出的意义:默认运行时,top命令会显示如下输出: ? 前...

3276
来自专栏北京马哥教育

用 30 个实例完全解读 TOP 命令

1785

扫码关注云+社区

领取腾讯云代金券