Skip to content

[toc]

Django实验

1 实验类型

验证型,2学时,必选实验

2 实验目的

掌握Flask不同类型请求参数的实现方法;熟悉Flask文件上传方法;熟悉ORM框架SQLAlchemy实现表CRUD操作方法。

3 实验内容与要求

使用不同的路由参数方法实现若干不同Web Api;实现文件上传功能;实现表的增删改查。

4 实验环境

Microsoft Edge/Chrome/Firefox等浏览器,Visual Studio CodeREST ClientPython 3.4+Django 4.0+

5 步骤

安装依赖

  1. 创建工作目录(学号),最终目录结构如下(包含创建的各类文件):
学号:.
  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

注:后续代码均在工作目录创建

  1. 创建虚拟环境.venv
py -m venv .venv
  1. 激活虚拟环境:
.venv\scripts\activate
  1. 安装依赖包:

pip install django
pip list
py -m pip freeze > requirements.txt
5. 创建工程my_site

django-admin startproject my_site

路由

编写基于Flask的应用程序实现不同的参数传递方式,Web Api定义如下:

URL 功能 输入 输出
/ 返回login.html登录界面,其中有表单包含参数:username login.html
/hello/<name> 接收参数name,返回收到的参数 name参数 回收到的参数
/login GETPOST方式接收表单参数username,返回收到的参数 username 收到的参数
  1. 在工作目录创建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>
  1. 在工作目录新建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)
  1. 启动服务器
py route.py

注:后续实验启动方式类似不再赘述

  1. 在浏览器中访问http://127.0.0.1:5000,在表单中输入参数,提交后观察返回结果是否正确

模板与静态文件

使用视图函数(render_template)向Jinja2模板(index.html)传递参数(name),使用静态文件(hello.js)显示接收到的参数,Web Api如下:

URL 功能 输入 输出
/ 返回index.html,按需求处理参数 index.html
  1. 创建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>
  1. 创建static/hello.js,使用静态文件处理参数,参考代码如下:
function sayHello(name) {
  alert("Hello " + name)
}
  1. 创建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)
  1. 在浏览器中访问http://127.0.0.1:5000,观察参数是否接收到并点击按钮检查静态文件是否正确工作

文件上传

通过表单向Flask上传文件(以图片为例),Web Api如下:

URL 功能 输入 输出
/ 返回upload.html,提供文件上传界面 upload.html
/upload 接收上传文件并保存至static/upload目录 文件 结果页面:uploaded.html
  1. 创建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>
  1. 创建tempalte/uploaded.html,显示上传的图片,参考代码如下:
<html>

<head>
  <title>File Upload</title>
</head>

<body>
  <p>已上传的图片:</p>
  <img src="static/upload/{{file_name}}">
</body>

</html>
  1. 创建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)
  1. 访问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页面(包含操作结果)
  1. 创建数据库实用函数文件(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)
  1. 创建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}>'
  1. 基于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)
  1. 实现学生创建页面(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>
  1. 实例学生修改页面(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>
  1. 实现数据查询页面(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>