[toc]
Django实验
1 实验类型
验证型,2学时,必选实验
2 实验目的
掌握Flask不同类型请求参数的实现方法;熟悉Flask文件上传方法;熟悉ORM框架SQLAlchemy实现表CRUD操作方法。
3 实验内容与要求
使用不同的路由参数方法实现若干不同Web Api;实现文件上传功能;实现表的增删改查。
4 实验环境
Microsoft Edge/Chrome/Firefox
等浏览器,Visual Studio Code
,REST Client
,Python 3.4+
,Django 4.0+
5 步骤
安装依赖
- 创建工作目录(
学号
),最终目录结构如下(包含创建的各类文件):
学号:.
│ dao.py
│ database.py
│ requirements.txt
│ route.py
│ student.db
│ student.py
│ template.py
│ upload.py
├─static
│ │ hello.js
│ └─upload
└─templates
│ index.html
│ login.html
│ upload.html
│ uploaded.html
└─student
create.html
retrieve.html
update.html
注:后续代码均在工作目录创建
- 创建虚拟环境
.venv
- 激活虚拟环境:
- 安装依赖包:
路由
编写基于Flask的应用程序实现不同的参数传递方式,Web Api定义如下:
URL | 功能 | 输入 | 输出 |
---|---|---|---|
/ |
返回login.html 登录界面,其中有表单包含参数:username |
login.html |
|
/hello/<name> |
接收参数name,返回收到的参数 | name参数 | 回收到的参数 |
/login |
以GET和POST方式接收表单参数username,返回收到的参数 | username | 收到的参数 |
- 在工作目录创建
templates/login.html
,参数代码如下:
<html>
<body>
<form action="/login" method="POST">
<p>Enter Name:</p>
<p><input type="text" name="username" /></p>
<p><input type="submit" value="submit" /></p>
</form>
</body>
</html>
- 在工作目录新建
route.py
实现表中的Web Api,参数代码如下:
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route("/")
def hello_world():
'''登录页面'''
return render_template("login.html")
@app.route("/hello/<name>")
def hello_name(name):
'''接收变量name'''
return f"Hello {name}"
@app.route("/login", methods = ["POST", "GET"])
def login():
'''接收表单参数'''
if request.method == "POST":
username = request.form["username"] #提取参数
return f"Hello {username} by POST"
else:
username = request.args.get["username"] #提取参数
return f"Hello {username} by GET"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
- 启动服务器
注:后续实验启动方式类似不再赘述
- 在浏览器中访问
http://127.0.0.1:5000
,在表单中输入参数,提交后观察返回结果是否正确
模板与静态文件
使用视图函数(render_template
)向Jinja2模板(index.html
)传递参数(name),使用静态文件(hello.js
)显示接收到的参数,Web Api如下:
URL | 功能 | 输入 | 输出 |
---|---|---|---|
/ |
返回index.html ,按需求处理参数 |
index.html |
- 创建
templates/index.html
,接收Flask传递过来的参数,参考代码如下:
<html>
<head>
<script type="text/javascript" src="{{ url_for('static', filename = 'hello.js') }}"></script>
</head>
<body>
<p>接收到的name:</p>
<p>{{name}}</p>
<input type="button" onclick="sayHello('{{name}}')" value="Say Hello" />
</body>
</html>
- 创建
static/hello.js
,使用静态文件处理参数,参考代码如下:
- 创建
template.py
实现路由表中各URL功能,参考代码如下:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
name = "Jack Ma"
# render_template方法:渲染模板
# 参数1: 模板名称 参数n: 传到模板里的数据
return render_template('index.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
- 在浏览器中访问
http://127.0.0.1:5000
,观察参数是否接收到并点击按钮检查静态文件是否正确工作
文件上传
通过表单向Flask上传文件(以图片为例),Web Api如下:
URL | 功能 | 输入 | 输出 |
---|---|---|---|
/ |
返回upload.html ,提供文件上传界面 |
upload.html |
|
/upload |
接收上传文件并保存至static/upload 目录 |
文件 | 结果页面:uploaded.html |
- 创建
template/upload.html
,实现文件上传界面,参考代码如下:
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form action="http://127.0.0.1:5000/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="提交" />
</form>
</body>
</html>
- 创建
tempalte/uploaded.html
,显示上传的图片,参考代码如下:
<html>
<head>
<title>File Upload</title>
</head>
<body>
<p>已上传的图片:</p>
<img src="static/upload/{{file_name}}">
</body>
</html>
- 创建
upload.py
,实现各Web Api,参考代码如下:
from flask import Flask, render_template, request
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'static/upload/' # 设定上传目录
@app.route('/')
def index():
'''上传界面'''
return render_template('upload.html')
@app.route('/upload',methods=['GET','POST'])
def upload():
'''上传'''
if request.method == 'POST':
f = request.files['file'] # 提取文件
file_name = f.filename
f.save(os.path.join(app.config['UPLOAD_FOLDER'], file_name))
return render_template('uploaded.html', file_name = file_name) # 显示上传图片
else:
return render_template('upload.html')
if __name__ == '__main__':
app.run(debug=True)
- 访问
http://127.0.0.1:5000/
,上传图片并观察是否成功
SQLAlchemy框架
使用ORM框架Sqlalchemy实现学生表(学号,姓名,性别,年龄)
的增删改查,Web Api如下:
URL | 功能 | 输入 | 输出 |
---|---|---|---|
/create |
创建新记录 | 学生信息 | retrieve.html 页面(包含操作结果) |
/delete |
删除记录 | 学号 | retrieve.html 页面(包含操作结 |
/update_index |
显示修改页面 | 学号 | update.html 页面(包含操作结果) |
/update |
修改记录 | 选定学生信息 | retrieve.html 页面(包含操作结果) |
/retrieve |
显示所有数据 | retrieve.html 页面(包含操作结果) |
- 创建数据库实用函数文件(
database.py
)用于实现Sqlalchemy操作基础功能,参考代码如下:
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///student.db')
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def init_db():
'''
初始化数据库
'''
import student
Base.metadata.create_all(bind=engine)
- 创建Student实体类(
student.py
),参考代码如下:
from sqlalchemy import Column, Integer, String
from database import Base
class Student(Base):
'''学生实体类'''
__tablename__ = "Student" #表名
no = Column(String(50), primary_key = True) #学号
name = Column(String(50)) #姓名
gender = Column(String(2)) #性别
age = Column(Integer) #年龄
def __init__(self, obj):
self.no = obj["no"]
self.name = obj["name"]
self.gender = obj["gender"]
self.age = obj["age"]
def __repr__(self):
return f'<Student {self.name!r}>'
- 基于Flask实现各Web Api(
dao.py
),参考代码如下:
from flask import Flask, request, render_template
from student import Student
from database import init_db, db_session
import logging
logger = logging.getLogger(__name__)
app = Flask(__name__)
app.secret_key = "random string"
@app.route("/create", methods = ["GET", "POST"])
def create():
"""增"""
message = ""
if request.method == "POST":
obj = get_student(request.form)
if not obj["no"]:
message = "信息不完整!"
else:
#创建新记录
try:
db_session.add(Student(obj))
db_session.commit()
message = "增加成功!"
except Exception as e:
message = e
logger.debug(message)
return render_template("student/create.html", message = message)
def get_student(form):
"""
从表单提取学生信息
@form: 学生信息表单
"""
res = {
"no": form["no"],
"name": form["name"],
"gender": form["gender"],
"age": form["age"]
}
return res
@app.route("/delete/<no>")
def delete(no):
"""删"""
message = ""
obj = db_session.query(Student).filter_by(no = no).first()
if obj:
try:
db_session.delete(obj)
db_session.commit()
except Exception as e:
message = e
return render_template("student/retrieve.html", message = message, \
students = db_session.query(Student).all())
@app.route("/update_index/<no>")
def update_index(no):
"""显示修改页面"""
obj = db_session.query(Student).filter_by(no = no).first()
logger.debug(obj)
return render_template("student/update.html", student = obj)
@app.route("/update", methods = ["POST"])
def update():
"""删"""
message = ""
obj = get_student(request.form)
logger.debug(obj)
if not obj["no"]:
message = "信息不完整!"
else:
#创建新记录
try:
logger.debug(obj)
db_session.query(Student).filter_by(no = obj["no"]).update(obj)
db_session.commit()
message = "修改成功!"
except Exception as e:
message = e
return render_template("student/update.html", message = message, student = obj)
@app.route("/retrieve")
def retrieve():
return render_template("student/retrieve.html", students = Student.query.all())
if __name__ == "__main__":
logging.basicConfig(level = logging.DEBUG)
init_db()
app.run(debug = True)
- 实现学生创建页面(
student/create.html
),参考代码如下:
<!DOCTYPE html>
<html>
<body>
<h3>学生表 - 增</h3>
<hr />
<div class="alert alert-danger">
{{message}}
</div>
<form action="/create" method="POST">
<label for="name">学号</label><br>
<input type="text" name="no" placeholder="学号"/><br>
<label for="city">姓名</label><br>
<input type="text" name="name" placeholder="姓名"/><br>
<label for="addr">性别</label><br>
<textarea name="gender" placeholder="性别"></textarea><br>
<label for="pin">年龄</label><br>
<input type="text" name="age" placeholder="年龄"/><br>
<input type="submit" value="Submit" />
</form>
</body>
</html>
- 实例学生修改页面(
student/update.html
),参考代码如下:
<!DOCTYPE html>
<html>
<body>
<h3>学生表 - 改</h3>
<div class="alert alert-danger">
{{message}}
</div>
<form action="/update" method="POST">
<label for="name">学号</label><br>
<input type="text" name="no" placeholder="学号" value="{{student.no}}"/><br>
<label for="city">姓名</label><br>
<input type="text" name="name" placeholder="姓名" value="{{student.name}}"/><br>
<label for="addr">性别</label><br>
<textarea name="gender" placeholder="性别">{{student.gender}}</textarea><br>
<label for="pin">年龄</label><br>
<input type="text" name="age" placeholder="年龄" value="{{student.age}}"/><br>
<input type="submit" value="Submit" />
</form>
</body>
</html>
- 实现数据查询页面(
student/retrieve.html
),参考代码如下:
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<h3>学生表 - 查</h3>
<div class="alert alert-danger">
{{ message }}
</div>
<a href="/create" target="_blank">新建</a>
<table>
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for student in students %}
<tr>
<td>{{student.no}}</td>
<td>{{student.name}}</td>
<td>{{student.gender}}</td>
<td>{{student.age}}</td>
<td>
<a href="/update_index/{{student.no}}">修改</a>
<a href="/delete/{{student.no}}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>