文章来源:Python Django+SQL+Pandas+Pyecharts自建在线数据分析平台(一)
作者:ccpic
感谢:感谢作者 ccpic 分享的优质内容,本网页主要用于学习知识的存档备份,欢迎点击原网页支持作者。
(一)需求分析&技术实现
(二)初步搭建Django环境
(三)页面布局&Django模板
(四)SQL+Pandas初步处理数据
(五)前端表单交互
(六)Ajax异步传参与加载
(七)前端数据格式的处理
(八)DataTables接管前端表格
(九)Pyecharts实现交互图表
(十)静态图表的展示
(十一)“导出数据至Excel”功能
(十二)添加和配置缓存
(十三)用户登录系统
(十四)部署Django至生产环境
本章我们的目标是完成一个用户登录系统,使数据不至于裸奔。我们的需求是比较简单的,因为是自建自用的数据平台,用户权限可以在后台分配,也不涉及注册模块和密码找回等功能,就是简单的登录和登出。
Django有比较完善的原生用户和授权系统,包括内置的User和Group模型。一般情况下,我们不需要重写和扩展这些模型,直接应用即可。
首先,确保在工程的settings.py文件中有下方与用户权限相关的installed app和中间件:
INSTALLED_APPS = [ ...  'django.contrib.auth', 'django.contrib.contenttypes',
MIDDLEWARE = [ ... 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ]
|
Django原生系统的用户数据和sesssion数据都需要数据库存储,我们之前一直没有使用Django的数据库接口,这次要用了。我们可以使用django默认的sqlite3数据库,它是个单文件轻型数据库,与业务数据分离。settings.py里设置如下:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
|
因为是第一次使用Django数据库接口,我们需要执行migrate命令一次。如果在一般的Django项目中,migrate命令大概我们很早就很熟识了:
再顺便把超级管理员账号创建了
python manage.py createsuperuser
|
其实我们进行到这个步骤时会有一种强烈感觉,我们依然在以Django MTV的的框架思路在搭建这个用户系统。上面完成的工作是M的部分,并且我们已经有了一条符合内置User model的超级管理员用户信息的数据。下面我们需要继续完成T和V的部分。
在template下新建registration文件夹,里面再新建login.html模板。

login模板还是继承自base.html,并且内容部分以**{% block body %}{% endblock %}**开头结尾。在第三章我们解释过这种模板继承的机制,并且这个login页面就和我们在第三章举的index页面的例子一模一样。
而login.html内容为:
{% extends "chpa_data/base.html" %}
{% block body %} <div id="pusher" class="pusher" style="padding-top:100px"> <div class="ui middle aligned center aligned grid"> <div class="column"> <h2 class="ui image header"> <div class="content"> 用户登录 </div> </h2>
<form method="post" action="{% url 'login' %}" class="ui large form"> {% csrf_token %} {% if next %} {% if user.is_authenticated %} <div class="ui info message">您的账户没有权限浏览当前页面。 请尝试登录有权限的账号</div> {% else %} <div class="ui info message">未登录用户没有权限浏览当前页面,请登录</div> {% endif %} {% endif %} <div class="ui stacked secondary segment"> <div class="field"> <div class="ui left icon input"> <i class="user icon"></i> {{ form.username }} </div> </div> <div class="field"> <div class="ui left icon input"> <i class="lock icon"></i> {{ form.password }} </div> </div> <input class="ui fluid large blue submit button" type="submit" value="登录"> <input type="hidden" name="next" value="{{ next }}"> </div> {% if form.errors %} <div class="ui info message">用户名或密码错误,请再次尝试。</div> {% endif %}
</form>
<div class="ui message"> 如登录困难,请联系管理员 </div> </div> </div> </div> ... {% endblock body %}
|
此时登录界面已经有了,但是布局有点诡异。

我们需要写一些css调整下:
{% block body %} ... <style> body { background-color: #DADADA; }
body > .grid { height: 100%; }
.column { max-width: 450px; }
.ui.footer.segment { margin: 5em 0em 0em; }
</style> {% endblock body %}
|
Login.html的代码很好读懂,只有一个{{ next }}有些奇怪,但我们放一放,到后面相关部分再做解释。
下面配置URL,我们需要更改的是工程的urls.py,而不是chpa app的urls.py。添加登录权限相关url后它应该长这样:
urlpatterns = [
path('chpa/', include('chpa_data.urls')), path('admin/', admin.site.urls), path('accounts/', include('django.contrib.auth.urls')), ]
|
同时我们要在工程的settings.py里设置2个参数,明确登入和登出成功后分别的默认landing page:
LOGIN_REDIRECT_URL = '/chpa/index' LOGOUT_REDIRECT_URL = '/accounts/login'
|
此时我们如果访问http://127.0.0.1:8088/accounts/login/,已经能使用这个登录界面了,我们甚至可以输入之前设置的超级管理员账户,登录成功后重定向到上方的/chpa/index页面。
但是,现在直接输入其他url能绕过此登录验证,我们还需要给所有与URL绑定的视图方法(本例中也就是views.py里的index, query, search, export4个)都加上@login_required装饰器, 如果涉及到多个装饰器的场合,@login_required装饰器放在最上面第一个加载:
from django.contrib.auth.decorators import login_required
@login_required def index(request): ...
@login_required @cache_page(60 * 60 * 24 * 30) def query(request): ...
@login_required @cache_page(60 * 60 * 24 * 30) def search(request, column, kw): ...
@login_required @cache_page(60 * 60 * 24 * 30) def export(request, type): ...
|
此时可以回过头来解释login.html里{{ next }}的问题。
以query方法为例,@login_required装饰器会在query方法之前运行,即当任何URL成功定向到query方法后,@login_required将首先检查该用户是否已登录。如果他们已登录,则query将运行并返回结果。
而如果未登录,它将阻止query方法运行,而重定向至/login?next=%2Fquery。加载页面后此时的next后的参数为一个GET请求的参数被捕捉。所以这时login.html可以用django tag语法调用{{ next }}
login.html再使用语句,把next作为一个隐藏元素在登录时发送,用户登录成功后此next相当于覆盖了默认的LOGIN_REDIRECT_URL ,把页面重定向回query方法。
简单地说,这个{{ next }}可以帮助我们在登录后重定向至登录前访问的网页。
最后,我们做一些收尾工作。因为我们需要Django自带的admin界面至少完成用户管理的工作,我们在header做一些admin的超链接以及登出的按钮等工作。此时的header.html为:
<div class="ui large top fixed inverted menu"> <div class="ui container"> <a href="{% url 'chpa:index' %}" class="item">首页</a> {% if request.user.is_staff %} <a href="{% url 'admin:index' %}" class="item">后台管理</a> {% endif %} </div> <div class="right menu"> {% if not request.user.username %} <div class="ui item"> 未登录 </div> {% else %} <div class="ui item"> 您好,{{ request.user.username }} </div> <a class="ui item" href="{% url 'logout' %}"> 切换用户 </a> {% endif %} </div> </div>
|
完成~

增加了后台管理链接和右上角(显示当前用户名和登出按钮)