美文网首页Python我爱编程
简明Python开发教程(6):用Django搭建网站

简明Python开发教程(6):用Django搭建网站

作者: 问道轩 | 来源:发表于2018-04-11 00:42 被阅读285次

前面已经分享了Python的基础知识和典型应用,那么如何可视化呈现结果并进行交互?
一般用网页形式进行展示,网页展示结果、交互,服务器后台提供数据支持。开发网站又是一个复杂的工作。
幸好Python的Django框架可以让我们非常容易的搭建网站系统,只需要我们学习一点点HTML、CSS、JavaScript等前端知识,了解一下Django的工作原理就可以工作了。
前期我们梳理了工作岗位需要掌握的11大类、327小类技能点,并对27位同事的技能掌握进行摸底调查,分为:没听过、初级、中级、高级四部分;
同时统计近5年的外出培训记录。
目前需要开发一个网站,提供查询功能:
1)按人员查:对比显示该同事的技能掌握情况和培训记录;
2)按技能查询:显示不同基本人员分布情况

1 Django介绍

Django是用Python开发的免费开源web框架。
当初我使用自强学堂完成学习入门,推荐。
首先需要安装相应版本的Django,如1.11。
如果已经安装Anaconda,那么使用conda intsall django。即可完成安装。
一般情况,开发Django应用有以下几步:

1.1 创建一个工程

使用django-admin.py startproject project_name创建一个新工程,然后发现会自动新建一个文件夹,有着一定的模板。

image.png

可以看到目录结构基本如下:

hrinfo/
    manage.py
    hrifno/
        __init__.py
        settings.py
        urls.py
        wsgi.py

urls.py写一些url解析规则,setting.py包含一些全局配置信息,manage.py提供一些管理功能。
如进入工程目录,运行开发环境,测试Django是否工作正常。

image.png

一切正常,打开浏览器,输入127.0.0.1:8000,结果如下,说明Django工作正常。

image.png

1.2 新建一个应用App

进入工程目录后,输入python manage.py startapp hrskill,可以发现新建一个hrskill文件夹,包含若干文件:

image.png

这里最重要的是views.py文件,写网站后台处理逻辑。

1.3 修改配置setting.py文件

打开setting.py文件,增加App名称,如果希望关联数据库,如修改为Mysql
数据库,也可以配置,这里简化处理,这里不配数据库。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hrskill',  #新增配置
]

1.4 测试应用功能

通过修改urls.py 和 views.py来测试应用是否正常工作。比如我们想访问127.0.0.1:8000时,能够显示欢迎语句。
在views.py新增index函数:

from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
def index(request):
    return HttpResponse(u"欢迎光临!")

index()返回 HttpResponse 对象,可以显示在网页上,现在需要规定那个网址能使用这个函数,也就是需要在urls.py进行修改:

from django.conf.urls import url
from django.contrib import admin

from hrskill import views as hrskill_views #新增

urlpatterns = [
    url(r'^$', hrskill_views.index),  #新增url解析规则,什么网址对应什么函数
    url(r'^admin/', admin.site.urls),
]

其中网址写法符合正则表达式规则。
然后运行开发服务器 python manage.py runserver,打开浏览器,输入127.0.0.1:8000,结果如下:

image.png

1.5 使用模板(templates)进行交互

前面通过HttpResponse 来把内容显示到网页上,非常简单,能做的事也很少。
更多的我们是用模板templates的方法,就是事先写好html文件,然后直接返回这个html文件,这样就可以美化页面。
在hrskill文件夹下新建templates文件夹,然后新建一个index.html文件。
/templates/index.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
    </head>
    <body>
        欢迎跟着朱老师学Django.
    </body>
</html>

然后修改/hrskill/views.py如下:

from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse  #可以注释掉
def index(request):
    return render(request, 'index.html')  #修改为这样即可
    #return HttpResponse(u"欢迎光临!")

然后可以刷新下网页(由于之前开发服务器一直运行,修改views.py会自动生效,无需重启,非常方便开发调式),结果已经更新。完美。


image.png

1.6 对模板进行渲染

上面功能还是很单一,只能返回写好的html文件。服务器更强大的应该是动态更新html文件,可以交互,比如不同用户访问,通过后台查询账号对应用户姓名,显示个性化欢迎语。
修改/templates/index.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
    </head>
    <body>
        {{name}},欢迎跟着朱老师学Django.
    </body>
</html>

修改/hrskill/views.py如下:

from django.shortcuts import render
def index(request):
    name = '朱锋'  #模拟获取后台获取用户姓名,这里省略
    return render(request, 'index.html',{'name':name})  #注意传name参数给前端

刷新网页,效果如下:

image.png

1.7 前端传参数给后台

很多时候,用户需要在前端网页输入某些关键字,然后传递给后台,后台根据这些参数进行处理,并返回结果。
这里简单模拟下用户在前端网页输入数字后,后台获取数字后加10返回,显示。
首先修改/templates/index.html内容如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
        <script src="../static/js/jquery-3.2.0.min.js"></script>
    </head>
    <body>
        <p id="p1">欢迎跟着朱老师学Django.</p>
        <form action="/search/" method="get">
            <input id="name" type="text" >
            <button id='sum' type="button">Go!</button>
        </form>
        <script>
            $(document).ready(function() {
                $("#sum").click(function() {
                    var ne_str = $("#name").val();
                    $.ajaxSettings.async = false;
                    $.getJSON("/search/",{"name":ne_str}, function(ret) {
                        document.getElementById("p1").innerHTML = ret['data']
                    });
                });
            });
            </script>
    </body>
</html>

由于使用Jquery,需要导入,将相应js文件放入/hrskill/static/js目录下(自己新建)。
同时上面html文件中增加了一个表单form及对应的动作,包括一个输入框input,一个提交按钮,通过JavaScript的Ajax技术获取后台数据,获取数据后修改p1内容。
此时刷新网页,效果如下:

image.png

此时点击Go应该没有任何反应,因为后台没进行后台修改。
接下来我们要修改后台处理逻辑。
首先增加一个url网址对应的views函数。
修改/hringo/urls.py如下:

from django.conf.urls import url
from django.contrib import admin
from hrskill import views as hrskill_views #新增
urlpatterns = [
    url(r'^$', hrskill_views.index),  #新增url解析规则,什么网址对应什么函数
    url(r'^search/$', hrskill_views.search),  #新增search Url对应view中函数
    url(r'^admin/', admin.site.urls),
]

此时点击Go,Django后台会报错,因为没有修改views.py。
修改/hrskill/views.py如下:

from django.shortcuts import render
# Create your views here.
from django.http import HttpResponse
import json  #新增json处理  
def index(request):
    name = '朱锋'  #模拟获取后台获取用户姓名,这里省略
    return render(request, 'index.html',{'name':name})  #修改为这样即可
def search(request): #新增search函数
    name = request.GET['name']
    ret = {}
    ret['data'] = '你输入的字符串是——{}'.format(name)
    return HttpResponse(json.dumps(ret),content_type='application/json')

现在我们在输入框输入任何字符串,点击“Go”,提交后看看效果。(如果没响应,建议重启开发服务器再试试)。
输入“今天天气真好”,然后点击Go,效果如下:

点击前.png
点击后.png
偶尔可能犯迷糊,参数传递有问题,重新加载正常,需要前端大牛帮忙解决

以上,我们已经简单介绍了Django,包括网页的基本交互,接下来就是丰富处理逻辑,美化前端页面,都在上面的框架内完成。

2 前端优化——AdminLTE、Bootstrap、Echarts

为了使前端页面更美观,也使得交互更近优化,我们可以学习一些基本的前端技术的使用,如:
Bootstrap简洁、直观、强悍的前端开发框架,让web开发更迅速、简单。
AdminLTE,是基于Bootstrap3高度可定制的响应式管理模板,是网页更简单。
Echarts开源免费的可视化图表。
上述工具,自己查看教程学习,下载相应的js文件,放置合适路径。因为我也只是会用

3 最终实现

回到一开始的项目需求,按人员或技能查询并用合适图表对比显示分析。
首先看看后台Mysql两个数据库结构:
staff_skill表格式,提供人员技能掌握情况。

image.png

training_record表样例,提供人员培训记录。

image.png

3.1 HTML文件设计

总共设计3个html页面,分别是首页index.html、人员查询页面searchstaff.html和技能查询页面searchskill.html。
下载相应的js、css文件,放到/hrskill/static/下合适路径。
index.html如下(说实话,可能有些css、js文件是不必要,但是我不知道):

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>欢迎使用</title>
        <link rel="stylesheet" href="../static/css/bootstrap.min.css">
        <link rel="stylesheet" href="../static/css/bootstrap-table.min.css">
        <link rel="stylesheet" href="../static/css/AdminLTE.min.css">
        <link rel="stylesheet" href="../static/css/_all-skins.min.css">
        <link rel="stylesheet" href="../static/css/blue.css">
        <link rel="stylesheet" href="../static/css/morris.css">
        <link rel="stylesheet" href="../static/css/jquery-jvectormap-1.2.2.css">
        <link rel="stylesheet" href="../static/css/datepicker3.css">
        <link rel="stylesheet" href="../static/css/daterangepicker.css">
        <link rel="stylesheet" href="../static/css/bootstrap3-wysihtml5.min.css">
        <link rel="stylesheet" href="../static/css/dataTables.bootstrap.css">
        <script src="../static/js/jquery-3.2.0.min.js"></script>
        <script src="../static/js/bootstrap.min.js"></script>
        <script src="../static/js/bootstrap-table.min.js"></script>
        <script src="../static/js/bootstrap-table-zh-CN.min.js"></script>
        <script src="../static/js/jquery.dataTables.min.js"></script>
        <script src="../static/js/dataTables.bootstrap.min.js"></script>
        <script src="../static/js/jquery.slimscroll.min.js"></script>
        <script src="../static/js/fastclick.min.js"></script>
        <script src="../static/js/app.min.js"></script>
        <script src="../static/js/demo.js"></script>
    </head>
    <body class="hold-transition skin-blue sidebar-mini">
        <div class="wrapper">
            <header class="main-header">
                <a href="/" class="logo">
                    <span class="logo-lg">人员技能管理系统</span>
                </a>
                <nav class="navbar navbar-static-top"></nav>
            </header>
            <aside class="main-sidebar">
                <section class="sidebar">
                    <ul class="sidebar-menu">
                        <li class="active treeview">
                            <a href="#">
                                <i class="fa fa-th"></i> <span>快速查询</span>
                                <span class="pull-right-container">
                                    <i class="fa fa-angle-left pull-right"></i>
                                </span>
                            </a>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchstaff"><i class="fa fa-circle-o"></i>人员查询</a>
                                </li>
                            </ul>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchskill"><i class="fa fa-circle-o"></i>技能查询</a>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </section>
            </aside>
            <div class="content-wrapper"></div>
        </div>
    </body>
</html>

人员查询searchstaff.html文件如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>人员查询</title>
        <link rel="stylesheet" href="../static/css/bootstrap.min.css">
        <link rel="stylesheet" href="../static/css/bootstrap-table.min.css">
        <link rel="stylesheet" href="../static/css/AdminLTE.min.css">
        <link rel="stylesheet" href="../static/css/_all-skins.min.css">
        <link rel="stylesheet" href="../static/css/blue.css">
        <link rel="stylesheet" href="../static/css/morris.css">
        <link rel="stylesheet" href="../static/css/jquery-jvectormap-1.2.2.css">
        <link rel="stylesheet" href="../static/css/datepicker3.css">
        <link rel="stylesheet" href="../static/css/daterangepicker.css">
        <link rel="stylesheet" href="../static/css/bootstrap3-wysihtml5.min.css">
        <link rel="stylesheet" href="../static/css/dataTables.bootstrap.css">
        <script src="../static/js/jquery-3.2.0.min.js"></script>
        <script src="../static/js/bootstrap.min.js"></script>
        <script src="../static/js/bootstrap-table.min.js"></script>
        <script src="../static/js/bootstrap-table-zh-CN.min.js"></script>
        <script src="../static/js/jquery.dataTables.min.js"></script>
        <script src="../static/js/dataTables.bootstrap.min.js"></script>
        <script src="../static/js/jquery.slimscroll.min.js"></script>
        <script src="../static/js/fastclick.min.js"></script>
        <script src="../static/js/app.min.js"></script>
        <script src="../static/js/demo.js"></script>
    </head>
    <body class="hold-transition skin-blue sidebar-mini">
        <div class="wrapper">
            <header class="main-header">
                <a href="/" class="logo">
                    <span class="logo-lg">人员技能管理系统</span>
                </a>
                <nav class="navbar navbar-static-top"></nav>
            </header>
            <aside class="main-sidebar">
                <section class="sidebar">
                    <ul class="sidebar-menu">
                        <li class="active treeview">
                            <a href="#">
                                <i class="fa fa-th"></i> <span>快速查询</span>
                                <span class="pull-right-container">
                                    <i class="fa fa-angle-left pull-right"></i>
                                </span>
                            </a>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchstaff"><i class="fa fa-circle-o"></i>人员查询</a>
                                </li>
                            </ul>
                            <ul class="treeview-menu">
                                <li class="active">
                                    <a href="/searchskill"><i class="fa fa-circle-o"></i>技能查询</a>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </section>
            </aside>
            <div class="content-wrapper">
                <section class="content" >
                    <form action="/getstaff/" method="get">
                        <label>姓名:</label>
                        <input id="name" type="text" >
                        <button id='sum' class="btn btn-default" type="button">查询</button>
                    </form>
                    <p class="tab-p" id = "remark"></p>
                    <table id="table" data-checkbox-header="true" data-search="true"></table>
                    <table id="table_train" data-checkbox-header="true" data-search="true"></table>
                </section>
            </div>
        </div>

        <script>
        $(document).ready(function() {
            $("#sum").click(function() {
                var name_str = $("#name").val();
                //alert(name_str)
                $.ajaxSettings.async = false;
                $.getJSON("/getstaff/",{"username":name_str}, function(ret) {
                    document.getElementById("remark").innerHTML = ret['remark']
                    var cols = ret['cols']
                    var a_skills = ret['a_skills']
                    var cols_train = ret['cols_train']
                    var train_record = ret['train_record']
                    var $table = $('#table');
                    var $table_train = $('#table_train');
                    $table.bootstrapTable('destroy');
                    $table_train.bootstrapTable('destroy');
                    $(function() {
                        $table.bootstrapTable({
                            detailView: true,
                            data: a_skills,
                            dataType: "json",
                            search: true, //显示搜索框
                            columns: cols,
                            onExpandRow: function(index, row, $detail) {
                                InitSubTable(index, row, $detail);
                            }
                            });
                        InitSubTable = function(index, row, $detail) {
                            var b_skills = row.b_skills;
                            var cur_table = $detail.html('<table></table>').find('table');
                            $(cur_table).bootstrapTable({
                                data: b_skills,
                                columns: cols,
                            });
                        };
                    });
                    $(function(){
                            $table_train.bootstrapTable({
                            data: train_record,
                            dataType: "json",
                            search: true, //显示搜索框
                            columns: cols_train,
                        });
                    });
                });
            });
        });
        </script>
    </body>
</html>

通过输入被查询人员姓名,查询显示其技能和培训情况。
技能查询searchsskill.html文件如下:

未完待续,大家可以完成

通过输入被查询技能名称,查询显示人员掌握情况。

3.2 后台处理逻辑设置

修改urls.py如下:

from django.conf.urls import url
from django.contrib import admin
from hrskill import views as hrskill_views #新增
urlpatterns = [
    url(r'^$', hrskill_views.index),  #新增url解析规则,什么网址对应什么函数
    url(r'^searchstaff/$', hrskill_views.searchstaff),  #新增searchstaff函数
    url(r'^searchskill/$', hrskill_views.searchskill),  #新增searchskill函数
    url(r'^admin/', admin.site.urls),
]

修改views.py如下:

from django.shortcuts import render
from django.http import HttpResponse
import pandas as pd
import json  #新增json处理  
import pymysql #操作数据库
ip = '127.0.0.1'
user = 'root'
password = 'root'
db = 'hrinfo'
def index(request):
    name = '朱锋'  #模拟获取后台获取用户姓名,这里省略
    return render(request, 'index.html',{'name':name})  #修改为这样即可
def staffinfo(request):    
    return render(request, 'searchstaff.html')  
def skillinfo(request):
    return render(request, 'searchskill.html')  
#查询人员信息
def getstaff(request): 
    name = request.GET["username"]
    conn = pymysql.connect(host=ip, port=3306, user=user, passwd=password, db=db,charset='utf8')
    sql_skill = "SELECT * FROM staff_skill"
    skills = pd.read_sql(sql_skill,conn)
    skills = skills[skills['name']==name]
    ret = {}
    cols = []
    col = ['name','skill_name','date','no','primary','middle','senior']
    col_title = ['姓名','技能名称','认证日期','没听过','初级','中级','高级']
    for i in range(len(col)):
        col_f = {}       
        col_f['field'] = col[i]
        col_f['title'] = col_title[i]
        cols.append(col_f)
    ret['cols'] = cols
    a_skills = []
    for a_skill,group in skills.groupby(['a_skill']):
        row = {}
        date = max(group['skill_date'])
        num = len(group)
        no = len(group[group['skill_level']=='没听过'])
        primary = len(group[group['skill_level']=='初级'])
        middle = len(group[group['skill_level']=='中级'])
        senior = len(group[group['skill_level']=='高级'])
        row['name'] = name
        row['skill_name'] = a_skill
        row['date'] = date
        row['no'] = '{}/{}'.format(no,num)
        row['primary'] = '{}/{}'.format(primary,num)
        row['middle'] = '{}/{}'.format(middle,num)
        row['senior'] = '{}/{}'.format(senior,num)
        b_skills = []
        for b_skill ,b_group in group.groupby(['b_skill']):
            b_row = {}
            b_row['name'] = name
            b_row['skill_name'] = b_skill
            b_row['date'] = date
            num = len(b_group)
            no = len(b_group[b_group['skill_level']=='没听过'])
            primary = len(b_group[b_group['skill_level']=='初级'])
            middle = len(b_group[b_group['skill_level']=='中级'])
            senior = len(b_group[b_group['skill_level']=='高级'])
            b_row['no'] = '{}/{}'.format(no,num)
            b_row['primary'] = '{}/{}'.format(primary,num)
            b_row['middle'] = '{}/{}'.format(middle,num)
            b_row['senior'] = '{}/{}'.format(senior,num)
            b_skills.append(b_row)
        row['b_skills'] = b_skills
        a_skills.append(row)    
    ret['a_skills'] = a_skills
    
    sql_train = "SELECT * FROM training_record"
    trains = pd.read_sql(sql_train,conn)
    cj_trains = trains[trains['name']==name]
    zj_trains = pd.DataFrame()
    for i in trains.index:
        speaker = trains.loc[i]['speaker']
        if name in speaker:
            zj_trains = zj_trains.append(trains.loc[i],ignore_index=True)
    re_train = []
    if not zj_trains.empty:
        for topic in set(zj_trains['train_topic']):    
            topic_train = zj_trains[zj_trains['train_topic'] == topic][['train_date','days','train_class','train_loc']]
            topic_train = topic_train.drop_duplicates()
            row = dict(topic_train.iloc[0])
            row['name'] = name
            row['topic'] = topic
            row['isspeaker'] = '是'
            re_train.append(row)
    if not cj_trains.empty:
        for i in cj_trains.index:
            topic = cj_trains.loc[i]['train_topic']
            if zj_trains.empty or (topic not in set(zj_trains['train_topic'])):
                row = dict(cj_trains.loc[i][['train_date','days','train_class','train_loc']])
                row['name'] = name
                row['topic'] = topic
                row['isspeaker'] = '否'
                re_train.append(row)
    ret['train_record'] = re_train
    cols_train = []
    col_train = ['name','topic','train_date','days','train_class','train_loc','isspeaker']
    col_title_train = ['姓名','培训名称','培训日期','培训天数','培训类型','培训地点','是否为讲师']
    for i in range(len(col_train)):
        col_f = {}       
        col_f['field'] = col_train[i]
        col_f['title'] = col_title_train[i]
        cols_train.append(col_f)
    ret['cols_train'] = cols_train
    
    #写评语
    num = len(skills)
    senior = len(skills[skills['skill_level']=='高级'])
    middle = len((skills[skills['skill_level']=='中级']))
    primary = len((skills[skills['skill_level']=='初级']))
    no = len((skills[skills['skill_level']=='没听过']))
    num_zj = len(zj_trains)
    num_cj = len(zj_trains) + len(cj_trains)
    remark = "<br>{}同学,在全部的{}个知识点中,掌握情况大概如下:高级{}/{},中级{}/{},初级{}/{},没听过{}/{}。\
    近期主讲{}次培训,参加{}次培训。<br>".format(name,num,senior,num,middle,num,primary,num,no,num,num_zj,num_cj)
    ret['remark'] = remark
    return HttpResponse(json.dumps(ret),content_type='application/json')
 

由于时间关系,后台处理逻辑实现比较乱,建议单独一个模块,写各种函数,实现数据处理功能。
现在我们可以看看网页的效果
点击左侧“人员查询”:

image.png

输入姓名“XX”,点击查询:

image.png
由于时间关系,技能查询功能未实现,同时显示方式、评价都有很多优化的地方,使得交互更加友好。
期待你们的完善。
全部教程到此结束,砖已抛出,期待你们的玉。
Python真是零基础编程的神器!

相关文章

  • 简明Python开发教程(6):用Django搭建网站

    前面已经分享了Python的基础知识和典型应用,那么如何可视化呈现结果并进行交互?一般用网页形式进行展示,网页展示...

  • django基础

    django介绍 Django 是用python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站...

  • Django-01-helloworld

    1.简介 web框架,快速开发网站,提供内置服务器 2.环境搭建 本教程系列基于python 2.7和django...

  • python开发-Django框架使用

    Django框架简介 Django框架是由Python开发的免费的开源网站框架,可用于快速搭建高性能,优雅的网站。...

  • Python学习笔记-第十八天

    Django官方学习笔记Django快速搭建blogrunoob Django教程vim python搭建1vim...

  • Python构建网站

    Python Django框架网站搭建入门 Django 中文文档 The Django Book

  • 第三节、Django基础

    基础知识 Django是用Python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站!Web应...

  • 很详细的Django入门详解

    Django 是用Python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站!采用了MVC的框...

  • 《简明Python教程》

    下载地址:下载地址 官方网站: http://python.swaroopch.com/ 简明 Python 教程...

  • 个人博客搭建完成

    花了一个周末,用Django搭建了个人博客。其中参照了Django 博客开发教程。 个人博客只是初步完成,需要修改...

网友评论

    本文标题:简明Python开发教程(6):用Django搭建网站

    本文链接:https://www.haomeiwen.com/subject/yphwhftx.html