本文的内容来自《python web开发从入门到实战》这本书,本人进行了实际操作了解整个pyton web开发的过程。
前端采用bootstrap进行制作,提供输入框和按钮让用户进行信息输入,然后将计算式通过Ajax方式传输给后台进行计算。后台采用Django进行开发,获取到前端发送的数据后利用python的子进程模块subprocess来计算式子,并将计算结果返回给前段进行显示。
使用django-admin startproject compute
创建项目后,项目工作目录下有一个manage.py文件以及一个与项目名字形同的compute子文件夹。manage.py文件作为项目的主文件,用来执行与项目相关的一些重要命令,例如,项目的启动、数据库的同步、后台管理员的创建、静态文件的迁移等。在compute子文件夹下有几个python文件,下面对这些文件做基本介绍:
目录: D:\python web学习\compute\compute\compute
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/2/20 10:57 __pycache__
-a---- 2021/2/20 10:48 407 asgi.py
-a---- 2021/2/20 10:48 3185 settings.py
-a---- 2021/2/20 10:48 770 urls.py
-a---- 2021/2/20 10:48 407 wsgi.py
-a---- 2021/2/20 10:48 0 __init__.py
init.py:表示文件,可以是一个空文件。主要用来表明当前文件所在的文件夹是一个python包,在这里的作用是声明compute子文件夹为一个独立的模块。
setting.py:整个项目的全局配置文件。各种应用、资源路径、模板等配置均在此文件中设置。
urls.py:网络访问的页面映射文件。创建的web项目下所有的页面路由都需要在该文件中配置,否则在访问的时候会找不到对应的页面。
wsgi.py:全称是web server gateway interface,即网络服务器的网管接口。在这里是指python应用与web服务器交互的接口,一般不需要做任何修改。
上面四个文件中需要重点股占虎setting.py和urls.py文件,这两个文件是项目中经常需要修改和编辑的文件。
0.1所创建的项目仅仅是一个web项目的外壳,为了能够满足特定的功能需求需要创建特定的功能对应的应用。
# 在项目中创建应用
python manage.py startapp app
# 可以看到项目中多出来一个app的文件夹
目录: D:\python web学习\compute\compute
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/2/20 10:56 app
d----- 2021/2/20 10:56 compute
-a---- 2021/2/20 10:57 0 db.sqlite3
-a---- 2021/2/20 10:48 685 manage.py
# 展开文件夹
PS D:\python web学习\compute\compute> cd app
PS D:\python web学习\compute\compute\app> dir
目录: D:\python web学习\compute\compute\app
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/2/20 10:56 migrations
-a---- 2021/2/20 10:56 66 admin.py
-a---- 2021/2/20 10:56 86 apps.py
-a---- 2021/2/20 10:56 60 models.py
-a---- 2021/2/20 10:56 63 tests.py
-a---- 2021/2/20 10:56 66 views.py
-a---- 2021/2/20 10:56 0 __init__.py
migrations:数据库迁移文件夹,在执行数据库迁移的时候会产生一些中间结果,这些结果就存放在该文件夹中。
init.py:表示文件,可以是个空文件,用来表明当前创建的app文件夹是一个python模块。
admin.py:管理员配置文件,主要是用来注册一些数据库中的模型到后台管理。django给每个项目提供了一个强大的后台管理系统,为了能够在后台管理系统中管理数据库中的数据,需要通过配置admin.py文件来确认那些数据信息可以被后台管理系统管理。
apps.py:应用的配置文件,一般情况下不需要修改。
models.py:数据库文件,用来管理数据库中的模型数据。
tests.py:测试文件,在这里可以对应用做一些测试。
.view.py:视图文件,对于每个访问的实际处理操作都在这个文件中编写,在这个文件中定义每个访问/路由的处理函数,每个访问与那个函数绑定则由urls.py文件配置。
上述几个文件需要关注的是:views.py、models.py、admin.py。另外还有几个重要文件需要手动进行创建。其实这些文件的内容结构本身并没有严格的限定,可以吧所有的内容都合并到一个文件中,之所以定义这几个文件是为了方便区分功能。
前提准备工作:已经安装了pyghon、vscode、django
# 在cmd或者vscode的终端中创建项目
django-admin startproject compute
# 切换到项目工作目录,manage.py文件目录下,创建一个名为app的应用
PS D:\python web学习\compute> cd .\compute\
PS D:\python web学习\compute\compute> dir
目录: D:\python web学习\compute\compute
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/2/20 10:48 compute
-a---- 2021/2/20 10:48 685 manage.py
PS D:\python web学习\compute\compute> python manage.py startapp app
PS D:\python web学习\compute\compute> dir
目录: D:\python web学习\compute\compute
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/2/20 10:56 app
d----- 2021/2/20 10:56 compute
-a---- 2021/2/20 10:48 685 manage.py
System check identified no issues (0 silenced).
# 启动项目
PS D:\python web学习\compute\compute> python .\manage.py runserver
# ctrl+c退出项目
项目启动后,通过浏览器访问http://127.0.0.1:8000,查看是否正常
首先梳理一下页面访问的基本流程,具体包括下面几个步骤:
在app文件夹下创建一个templates子文件夹,注意该文件夹的名字必须为templates,因为django框架会自动搜索每个应用下的templates文件夹,如果命名拼写错误,后面运行项目时会出现找不到模板文件的错误提示。在templates文件夹下创建一个index.html文件编辑html文件。
PS D:\python web学习\compute\compute> cd .\app\
PS D:\python web学习\compute\compute\app> md templates
PS D:\python web学习\compute\compute\app> cd .\templates\
# 创建index.html文件,并写入html代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>在线计算器</title>>
</head>>
<body>
<h1>一款在线计算器</h1>
</body>
</html>
打开项目配置文件compute下的setting.py文件,知道到INSTALLED_APPS字段,将创建的app应用添加进来。
为了后期项目部署和访问方便,需要开放访问权限,找到ALLOWED_HOSTS字段。进行下面编辑
配置视图处理函数,编辑app文件夹下的view.py文件
从django包中的shortcuts模块中引入render()函数,用于页面的渲染,然后添加了访问首页对应的home()处理函数,在该函数中并没有执行其他的操作,仅仅是通过render()函数返回index.html页面。
编辑配置文件夹compute中的urls.py文件
首先导入app应用下的views模块,然后通过配置urlpatterns字段将根访问路径(默认http://127.0.0.1:8000)和home()函数进行绑定。
在cmd中启动项目
PS D:\python_web_study\compute\compute> python manage.py runserver
下载bootstrap
链接: https://github.com/twbs/bootstrap/archive/v3.3.7.zip
将下载好的bootstrap源代码解压,找到其中的dist文件夹,该文件夹下有三个文件件:css、fonts和js。这三个子文件夹为需要导入的前段配置文件。
接下来,在compute项目的app文件夹下面创建一个名为static的子文件夹,然后将bootstrap中的css、fonts、js三个文件夹复制到static文件夹下面。并且在static文件夹下新建一个名为img的子文件夹用于存放静态图片。
下载bootstrap3.3.7对应的jquery
链接: http://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
按ctrl+s组合键进行保存,保存为jquery.min.js文件。将文件保存到app/static/js中。
{% load staticfiles %}
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scal=1">
<title>在线计算器title>>
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" />
<link rel="stylesheet" href="{% static 'css/style.css' %}" />
<script src="{% static 'js/jquery.min.js' %}">script>
<script src="{% static 'js/bootstrap.min.js' %}">script>
head>>
<body>
<button type="button" class="btn btn-success btn-lg btn_clear" id="lgbut_clear" onclick="fun_clear()">
清空
button>
<button type="button" class="btn btn-primary btn-lg" id="lgbut_compute">
计算
button>
body>
html>
目标设计页面:
页面设计分解:
两个文本框组件–一个用于显示计算器公式、一个用于显示计算结果
16个公式编辑按钮,包含数字、小数点和加减乘除等
两个逻辑按钮,一个用于清空文本框内容、一个用于执行公式计算
编辑index.html的body部分
{% load staticfiles %}
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scal=1">
<title>在线计算器title>
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" />
<link rel="stylesheet" href="{% static 'css/style.css' %}" />
<script src="{% static 'js/jquery.min.js' %}">script>
<script src="{% static 'js/bootstrap.min.js' %}">script>
head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-xs-1 col-sm-4">div>
<div id="computer" class="col-xs-10 c0l-sm-6">
<input type="text" id="txt_code" name="txt_code" value="" class="form-control input_show" placeholder="公式计算" disabled>
<input type="text" id="txt_result" name="txt_result" value="" class="form-control input_show" placeholder="结果" disabled>
<br/>
<div>
<button type="button" class="btn btn-default btn_num" onclick="fun_7()">7button>
<button type="button" class="btn btn-default btn_num" onclick="fun_8()">8button>
<button type="button" class="btn btn-default btn_num" onclick="fun_9()">9button>
<button type="button" class="btn btn-default btn_num" onclick="fun_div()">÷button>
<br/>
<button type="button" class="btn btn-default btn_num" onclick="fun_4()">4button>
<button type="button" class="btn btn-default btn_num" onclick="fun_5()">5button>
<button type="button" class="btn btn-default btn_num" onclick="fun_6()">6button>
<button type="button" class="btn btn-default btn_num" onclick="fun_mul()">×button>
<br/>
<button type="button" class="btn btn-default btn_num" onclick="fun_1()">1button>
<button type="button" class="btn btn-default btn_num" onclick="fun_2()">2button>
<button type="button" class="btn btn-default btn_num" onclick="fun_3()">3button>
<button type="button" class="btn btn-default btn_num" onclick="fun_sub()">-button>
<br/>
<button type="button" class="btn btn-default btn_num" onclick="fun_0()">0button>
<button type="button" class="btn btn-default btn_num" onclick="fun_00()">00button>
<button type="button" class="btn btn-default btn_num" onclick="fun_dot()">.button>
<button type="button" class="btn btn-default btn_num" onclick="fun_add()">+button>
div>
<div>
<br/>
<button type="button" class="btn btn-success btn-lg btn_clear" id="lgbut_clear" onclick="fun_clear()">
清空
button>
<button type="button" class="btn btn-primary btn-lg" id="lgbut_compute">
计算
button>
div>
div>
<div class="col-xs-1 col-sm-2">div>
div>
div>
<div class="extendContent">div>
body>
html>
name设置属性分组
value是按钮的名字
编辑css文件夹中的style.css文件
/* 设置整体的背景样式 */
body {
background-image: url("../img/ka.jpg");
background-position: center 0;
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
-webkit-background-size: cover;
-o-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
}
/* 显示文本框样式进行设置 */
.input_show {
margin-top: 35px;
max-width: 280px;
height: 35px;
}
/* 数字按钮样式进行设置 */
.btn_num {
margin: 1px 1px 1px 1px;
width: 60px;
}
/* 清空按钮样式进行设置 */
.btn_clear {
margin-left: 40px;
margin-right: 20px;
}
/* 用于将背景拉伸,否则在手机上浏览时背景会显示不全 */
.extendContent {
height: 300px;
}
单机数字按钮在“公式计算”文本框中显示添加的数字或者运算符号;单机“清空”按钮,可以对两个文本框中的数据进行清楚。该部分功能主要通过javascript代码实现。
添加到body末尾
<script>
var x = document.getElementById("txt_code");
var y = document.getElementById("txt_result");
function fun_7() {
x.value += '7';
}
function fun_8() {
x.value += '8';
}
function fun_9() {
x.value += '9';
}
function fun_div() {
x.value += '/';
}
function fun_4() {
x.value += '4';
}
function fun_5() {
x.value += '5';
}
function fun_6() {
x.value += '6';
}
function fun_mul() {
x.value += '*';
}
function fun_1() {
x.value += '1';
}
function fun_2() {
x.value += '2';
}
function fun_3() {
x.value += '3';
}
function fun_sub() {
x.value += '-';
}
function fun_0() {
x.value += '0';
}
function fun_00() {
x.value += '00';
}
function fun_dot() {
x.value += '.';
}
function fun_add() {
x.value += '+';
}
function fun_clear() {
x.value = '';
y.value = '';
}
</script>
document.getElementById(“txt_code”) 获取id为txt_code中的内容
单机“计算”按钮,将“公式计算”文本框中的数据通过Ajax发送给后端服务器,同时能够接受后端服务器发回来的执行结果并且显示在“结果”文本框中。之所以采用Ajax,是因为该项目适宜采用局部刷新的方式提交数据并更新结果,这样可以有较好的用户体验。
<script>
function ShowResult(data) {
var y = document.getElementById('txt_result');
y.value = data['result'];
}
</script>
<script>
$('#lgbut_compute').click(function () {
$.ajax({
url: '/compute/', // 调用django服务器计算公式
type: 'POST', // 请求类型
data: {
'code': $('#txt_code').val() // 获取文本框中的公式
},
dataType: 'json', // 期望获得的响应类型为json
success: ShowResult // 在请求成功之后调用该回调函数输出结果
})
})
</script>
其中url用来设置请求路径,即将请求提交到“当前根网址/compute/”进行计算
在app文件夹中的view.py文件中,添加下列代码
from django.shortcuts import render
import subprocess
from django.views.decorators.http import require_POST
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
# Create your views here.
def home(request):
return render(request, 'index.html')
def run_code(code):
try:
code = 'print(' + code + ')'
output = subprocess.check_output(['python', '-c', code],
universal_newlines=True,
stderr=subprocess.STDOUT,
timeout=30)
except subprocess.CalledProcessError as e:
output = '公式输入有误'
return output
@csrf_exempt
@require_POST
def compute(request):
code = request.POST.get('code')
result = run_code(code)
return JsonResponse(data={'result': result})
头部首先通过import subprocess引入子进程模块用于执行发送过来的计算公式;然后引入require_POST装饰器来获得后台服务器的post请求权限(否则发过来的请求会被后台服务器阻止);接下来引入JsonResponse模块用于将计算得到的结果封装成JSON字符串;最后引入csrf_exempt装饰器用于规避csrf校验(防止网站被跨站攻击)。
在公式计算run_code函数中,主要通过调用子进程模块subprocess的check_output函数进行公式计算。
最后,需要对访问路由urls进行配置,变价compute中的urls.py文件,在urlpatterns字段中添加代码,
from django.contrib import admin
from django.urls import path
from app.views import home, compute # 导入首页对应的处理函数
urlpatterns = [
path('admin/', admin.site.urls),
path('', home, name='home'), # 首頁路由
path('compute/', compute, name='compute'), # 添加針對公式計算compute的路由
]