Flask_BookManageSystem

1. JavaScript

1.1. 函数

var cars = ["Saab", "Volvo", "BMW"];
var txt = "string";
var b2=new Boolean(1);
var x = Math.PI; // 返回PI
var y = Math.sqrt(16); // 返回16的平方根
var num = new Number(value);
try {
    adddlert("Welcome");
}
catch(err) {
    document.getElementById("demo").innerHTML = 
    err.name + "<br>" + err.message;
}

1.2. DOM

在 HTML DOM (Document Object Model) 中 , 每一个元素都是 节点:

  • 文档是一个文档节点
  • 所有的HTML元素都是元素节点
  • 所有 HTML 属性都是属性节点
  • 文本插入到 HTML 元素是文本节点
  • 注释是注释节点。

//HTMLCollection 是 HTML 元素的集合。 //HTMLCollection 对象类似一个包含 HTML 元素的数组列表。 //getElementsByTagName() 方法返回的就是一个 HTMLCollection 对象。

decodeURI() 解码某个编码的 URI。
decodeURIComponent() 解码一个编码的 URI 组件。
encodeURI() 把字符串编码为 URI。
encodeURIComponent() 把字符串编码为 URI 组件。
escape() 对字符串进行编码。
eval() 计算 JavaScript 字符串,并把它作为脚本代码来执行。
isFinite() 检查某个值是否为有穷大的数。
isNaN() 检查某个值是否是数字。
Number() 把对象的值转换为数字。
parseFloat() 解析一个字符串并返回一个浮点数
parseInt() 解析一个字符串并返回一个整数
String() 把对象的值转换为字符串。
unescape() 对由 escape() 编码的字符串进行解码。
方法 描述
assert() 如果断言为 false,则在信息到控制台输出错误信息。
clear() 清除控制台上的信息。
count() 记录 count() 调用次数,一般用于计数。
error() 输出错误信息到控制台
group() 在控制台创建一个信息分组。 一个完整的信息分组以 console.group() 开始,console.groupEnd() 结束
groupCollapsed() 在控制台创建一个信息分组。 类似 console.group() ,但它默认是折叠的。
groupEnd() 设置当前信息分组结束
info() 控制台输出一条信息
log() 控制台输出一条信息
table() 以表格形式显示数据
time() 计时器,开始计时间,与 timeEnd() 联合使用,用于算出一个操作所花费的准确时间。
timeEnd() 计时结束
trace() 显示当前执行的代码在堆栈中的调用路径。
warn() 输出警告信息,信息最前面加一个黄色三角,表示警告

1.3. CSS 选择器

  • 方式一:document. getElementBy
getElementById id 兼容性好,推荐使用 如果存在多个id相同的元素,只会返回第一个
getElementsByTagName 标签名 不兼容ie8及以下版本 返回所有符合条件的元素的集合
getElementsByName name 不兼容ie8及以下版本 返回所有符合条件的元素的集合
getElementsByClassName class 不兼容ie8及以下版本 返回所有符合条件的元素的集合
  • 方式二: doucument.querySelector(’#second’);
.class .intro 选择所有class=“intro"的元素 1
#id #firstname 选择所有id=“firstname"的元素 1
* * 选择所有元素 2
element p 选择所有元素 1
element,element div,p 选择所有元素和元素 1
element element div p 选择元素内的所有元素 1
element>element div>p 选择所有父级是 元素的 元素 2
element+element div+p 选择所有紧接着元素之后的元素 2
[attribute] [target] 选择所有带有target属性元素 2
[attribute=value] [target=-blank] 选择所有使用target="-blank"的元素 2
[attribute~=value] [title~=flower] 选择标题属性包含单词"flower"的所有元素 2
[attribute|=language] [lang|=en] 选择 lang 属性以 en 为开头的所有元素 2

1.4. HTML 修改

  • document.write()直接将内容写入页面的内容流。当文档流执行完毕,会导致页面全部重绘。
  • element.innerHTML将内容写入某个DOM节点,不会导致页面重绘。
  • document.createElement()创建多个元素结构清晰。
// html 设置元素属性值
element.setAttribute('height', '100px');
element.setAttribute('style', 'height: 100px !important');
element.style.setProperty('height', '300px', 'important');
//第1种方法 ,给元素设置style属性  
$("#hidediv").css("display", "block");  
//第2种方法 ,给元素换class,来实现隐藏div,前提是换的class样式定义好了隐藏属性  
$("#hidediv").attr("class", "blockclass");  
//第3种方法,通过jquery的css方法,设置div隐藏  
$("#blockdiv").css("display", "none");  
$("#hidediv").show();//显示div    
$("#blockdiv").hide();//隐藏div 

1.5. js code segment

//-------   全屏
function fullscreen(element) {
    if(element.requestFullscreen) {
        element.requestFullscreen();
    } else if(element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
    } else if(element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen();
    } else if(element.msRequestFullscreen) {
        element.msRequestFullscreen();
    }
}
fullscreen(document.documentElement)
//-------   switchcase
let fruit = 'banana';
let drink;
switch (fruit) {
  case 'banana':
    drink = 'banana juice';
    break;
  case 'papaya':
    drink = 'papaya juice';
    break;
  default:
    drink = 'Unknown juice!'
}
console.log(drink) // banana juice
//-------  object entries
const credits = {
  producer: '大迁世界',
  name: '前端小智',
  rating: 9
}
const arr = Object.entries(credits)
console.log(arr)

2. Flask

2.1. 参数传递

  • 提交表单数据

前端的数据发送与接收 1)提交表单数据 2)提交JSON数据

后端的数据接收与响应 1)接收GET请求数据 2)接收POST请求数据 3)响应请求

GET把参数包含在URL中,POST通过request body传递参数。

// GET请求
var data = {
    "name": "test",
    "age": 1
};
$.ajax({
    type: 'GET',
    url: /your/url/,
    data: data, // 最终会被转化为查询字符串跟在url后面: /your/url/?name=test&age=1
    dataType: 'json', // 注意:这里是指希望服务端返回json格式的数据
    success: function(data) { // 这里的data就是json格式的数据
    },
    error: function(xhr, type) {
    }
});
//--- -- POST请求

var data = {}
//如果页面并没有表单,只是input框,请求也只是发送这些值,那么可以直接获取放到data中
data['name'] = $('#name').val()

//如果页面有表单,那么可以利用jquery的serialize()方法获取表单的全部数据
data = $('#form1').serialize();

$.ajax({
    type: 'POST',
    url: /your/url/,
    data: data,
    dataType: 'json', //注意:这里是指希望服务端返回json格式的数据
    success: function(data) { //这里的data就是json格式的数据
    },
    error: function(xhr, type) {
    }
});

A)参数dataType:期望的服务器响应的数据类型,可以是null, xml, script, json B)请求头中的Content-Tpye默认是Content-Type:application/x-www-form-urlencoded,所以参数会被编码为 name=xx&age=1 这种格式,提交到后端,后端会当作表单数据处理。

  • 提交Json 数据
//----        POST一个json数据

var data = {
    name: "test",
    "age", 1
}
$.ajax({
    type: 'POST',
    url: /your/url/,
    data: JSON.stringify(data), //转化为字符串
    contentType: 'application/json; charset=UTF-8',
    dataType: 'json', //注意:这里是指希望服务端返回json格式的数据
    success: function(data) { //这里的data就是json格式的数据
    },
    error: function(xhr, type) {
    }
});

2.2. 后端接受处理

#---     接受get 请求数据
# get 请求 www.baidu.com/s?name=python&age=12
name = request.args.get('name', '')
age = int(request.args.get('age', '0'))
#---     接受post 请求数据
#---1. 接收表单数据
name = request.form.get('name', '')
age = int(request.form.get('age', '0'))
#---2. 接收json 数据
data = request.get_json()
#---     返回json 数据
from Flask import jsonify
return jsonify({'ok': True})  #return Response(data=json.dumps({'ok': True}), mimetype='application/json')

2.3. 案例

# encoding:utf-8
from flask import Flask, render_template, url_for, request, json,jsonify
app = Flask(__name__)
#设置编码
app.config['JSON_AS_ASCII'] = False
#接收参数,并返回json数据
@app.route('/sendDate', methods=['GET', 'POST'])
def form_data():
   #从request中获取表单请求的参数信息
   title = request.form['title']
   datetime = request.form['datetime']
   quiz = request.form['quiz']
      #此处逻辑代码已经省略...................
   return jsonify({'status': '0', 'errmsg': '登录成功!'})
#测试入口
@app.route('/')
def home():
    return render_template("homepage.html")#homepage.html在templates文件夹下
if __name__ == '__main__':
    app.run()
$.ajax({
          url:'http://127.0.0.1:5000/sendDate',
  data:"title="+data.field['title']+"&datetime="+data.field['datetime']+"&quiz="+data.field['quiz'],
          type:'post',
          dataType:'json',
          success:function(data){ //后端返回的json数据(此处data为json对象)
              alert(data['errmsg']);
          },
          error:function () {
              alert('异常')
          }
      });
<script type="text/javascript">
	function handle(sid){
		var element = document.querySelector("#"+sid+">p");
		console.log(element)
		element.animate({left:'50%',top:'20px'},300)
		setTimeout(function(){
			element.find("a").css({left:'50%',top:0+"px"}).stop(true).animate({left:'50%',top:'20px'},1000)
		},200) 
		//element.css('visibility','hidden');
		//element.classList.add("animated bounce");
		//element.style.setProperty('--animate-duration', '2s');
		console.log("ID:");   //class="animated bounce"
	}

	function myrefresh()
	{
		//window.location.reload();
		$.ajax({
			url:'http://127.0.0.1:5000/getID',
			data:"title=getdata",
			type:'post',
			dataType:'json',
			success:function(data){ //后端返回的json数据(此处data为json对象)  添加动画
				console.log("ID:" + "demo"+data['id']);   //class="animated bounce"
				handle("demo"+data['id'])
			},
			error:function () {
				console.log('异常')
			}
		});
	} //setTimeout()只执行一次,setInterval()可以执行多次。
	setInterval('myrefresh()',2000); //指定1秒刷新一次
</script>

3. BookManageSystem

3.1. flask_script

Flask Script扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell,设置数据库的脚本,cronjobs,及其他运行在web应用之外的命令行任务;使得脚本和系统分开;

from flask_script import Manager  Server
from flask_script import Command  
from debug import app  
manager = Manager(app)  
class Hello(Command):  
    'hello world'  
    def run(self):  
        print 'hello world'  
#自定义命令一:
manager.add_command('hello', Hello())  
# 自定义命令二:
manager.add_command("runserver", Server()) #命令是runserver
if __name__ == '__main__':  
    manager.run()  

3.2. SQLAlchemy

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201114233802590.png

Engine 连接 驱动引擎
Session 连接池,事务 由此开始查询
Model 类定义
Column
Query 若干行 可以链式添加多个条件
Integer int int 整形,32位
String varchar string 字符串
Text text string 长字符串
Float float float 浮点型
Boolean tinyint bool True / False
Date date datetime.date 存储时间年月日
DateTime datetime datetime.datetime 存储年月日时分秒毫秒等
Time time datetime.datetime 存储时分秒
engine = create_engine("mysql://user:password@hostname/dbname?charset=utf8",
                       echo=True,
                       pool_size=8,
                       pool_recycle=60*30
                       )
from sqlalchemy.ext.declarative import declarative_base
#declarative_base()是sqlalchemy内部封装的一个方法,通过其构造一个基类,这个基类和它的子类,可以将Python类和数据库表关联映射起来。
Base = declarative_base()
class Users(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    name = Column(String(64), unique=True)
    email = Column(String(64))

    def __init__(self, name, email):
        self.name = name
        self.email = email  
#创建表,如果存在则忽略,执行以上代码,就会发现在db中创建了users表。
Base.metadata.create_all(engine)

from sqlalchemy.orm import sessionmaker
# 创建session
DbSession = sessionmaker(bind=engine)
session = DbSession()
#---- 增加
add_user = Users("test", "test123@qq.com")
session.add(add_user)
session.commit()
#---- 查询
users = session.query(Users).filter_by(id=1).all()
for item in users:
    print(item.name)
users = session.query(Users).filter_by(Users.id == 1).all()
#---- 修改
session.query(Users).filter_by(id=1).update({'name': "Jack"})
#--- or
users = session.query(Users).filter_by(name="Jack").first()
users.name = "test"
session.add(users)
#--- 删除
delete_users = session.query(Users).filter(Users.name == "test").first()
if delete_users:
    session.delete(delete_users)
    session.commit()
#--- or
session.query(Users).filter(Users.name == "test").delete()
session.commit()
filter filter_by
支持所有比较运算符,相等比较用比较用== 只能使用”=",”!=“和”><"
过滤用类名.属性名 过滤用属性名
不支持组合查询,只能连续调用filter变相实现 参数是**kwargs,支持组合查询
支持and,or和in等

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201114233611631.png

3.3. flask-wtf&&wtf

flask-wtf和wtf主要是用于建立html中的元素和Python中的类的对应关系,通过在Python代码中操作对应的类,对象等从而控制html中的元素。我们需要在python代码中使用flask-wtf和wtf来定义前端页面的表单(实际是定义一个表单类),再将对应的表单对象作为render_template函数的参数传递给相应的template,之后Jinja模板引擎会将相应的template渲染成html文本,再作为http response返回给用户。

# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, PasswordField
from wtforms.validators import DataRequired

# 定义的表单都需要继承自FlaskForm
class LoginForm(FlaskForm):
    # 域初始化时,第一个参数是设置label属性的
    username = StringField('User Name', validators=[DataRequired()]) #比如StringField代表的是<input type="text">元素
    password = PasswordField('Password', validators=[DataRequired()])
    remember_me = BooleanField('remember me', default=False)
# app.py
@app.route('/login')
def login():
    form = LoginForm()
    return render_template('login.html', title="Sign In", form=form)
#LoginForm 对应html 模板
{% extends "layout.html" %}
<html>
    <head>
        <title>Login Page</title>
    </head>
    <body>
        <form action="{{ url_for("login") }}" method="POST">
        <p>
            User Name:<br>
            <input type="text" name="username" /><br>
        </p>
        <p>
            Password:</br>
            <input type="password" name="password" /><br>
        </p>
        <p>
            <input type="checkbox" name="remember_me"/>Remember Me
        </p>
            {{ form.csrf_token }} 
        </form>
    </body>
</html>
#----- 对应template
<!-- 模板的语法应当符合Jinja语法 -->
<!-- extend from base layout -->
{% extends "base.html" %}

{% block content %}
  <h1>Sign In</h1>
  <form action="{{ url_for("login") }}" method="post" name="login">
      {{ form.csrf_token }}
      <p>
          {{ form.username.label }}<br>
          {{ form.username(size=80) }}<br>
      </p>
      <p>
          {{ form.password.label }}<br>
          <!-- 我们可以传递input标签的属性,这里传递的是size属性 -->
          {{ form.password(size=80) }}<br>
      </p>
      <p>{{ form.remember_me }} Remember Me</p>
      <p><input type="submit" value="Sign In"></p>
  </form>
{% endblock %}

3.4. flask_login

  • 首次登录

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201115000918252.png

def login_user(user, remember=False, force=False, fresh=True):
    if not force and not user.is_active:
        return False
    #获取User对象的get_id method,然后执行,从而获取到用户的ID
    user_id = getattr(user, current_app.login_manager.id_attribute)()
    session['user_id'] = user_id
    session['_fresh'] = fresh
    session['_id'] = current_app.login_manager._session_identifier_generator()

    if remember:
        session['remember'] = 'set'
#user对象存储进当前的request context中,_request_ctx_stack是一个LocalStack对象,top属性指向的就是当前的request context。
    _request_ctx_stack.top.user = user
    #通过send来发射此signal,当注册监听此signal的回调函数收到此signal之后就会执行函数。这里send有两个参数,第一个参数是sender对象,此处通过current_app._get_current_object()来获取当前的app对象,即此signal的sender设为当前的应用;第二个参数是该signal携带的数据,此处将user对象做为signal的数据传递给相应的回调函数。
    user_logged_in.send(current_app._get_current_object(), user=_get_user())
    return True

注意:Flask的session是以cookie为基础,但是是在Server端使用secret key并使用AES之类的对称加密算法进行加密的,然后将加密后的cookie发送给客户端。由于是加密后的数据,客户端无法篡改数据,也无法获知session中的信息,只能保存该session信息,在之后的请求中携带该session信息。

  • 非首次登录

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201115001837082.png

@app.route('/')
@app.route('/main')
@login_required
def main():
    return render_template(
        'main.html', username=current_user.username)
        
# login_required 会执行一下代码
# flask_login/utils.py
def login_required(func):
    @wraps(func)
    def decorated_view(*args, **kwargs):
        # 如果request method为例外method,即在EXEMPT_METHODS中的method,可以不必鉴权
        if request.method in EXEMPT_METHODS:
            return func(*args, **kwargs)

        # 如果_login_disabled为True则不必鉴权
        elif current_app.login_manager._login_disabled:
            return func(*args, **kwargs)

        # 正常鉴权
        elif not current_user.is_authenticated:
            return current_app.login_manager.unauthorized()
        return func(*args, **kwargs)
    return decorated_view
# use login manager to manage session
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.session_protection = 'basic'
login_manager.login_view = 'login'       #  没有权限重定向 页面
login_manager.login_message = u"请先登录。"        #自定义 flash 的消息

##当一个请求过来的时候,如果 ctx.user 没有值,那么 flask-login 就会使用 session 中 session['user_id'] 作为参数,调用 login_manager 中使用 user_loader 装饰器设置的 callback 函数加载用户,需要注意的是,如果指定的 user_id 无效,不应该抛出异常,而是应该返回 None。

@login_manager.user_loader
def load_user(admin_id):
    return Admin.query.get(int(admin_id))

@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('您已经登出!')
    return redirect(url_for('login'))

3.5. url_for()

<link rel="stylesheet" href="{{url_for('static',filename='css/index.css')}}">
# 动态路由, student_id:是可变部分
@app.route('/student_list/<student_id>/')
def student_list(student_id):
    return '学生{}号的信息'.format(student_id)
# 动态路由  过滤 string, int, float, path, uuid
@app.route('/student_list/<int:student_id>/')
def article_detail(student_id):
    return '学生{}号的信息'.format(student_id)
# 动态路由   自定义 url_path
@app.route('/<any(student,class):url_path>/<id>/')
def item(url_path, id):
    if url_path == 'student':
        return '学生{}详情'.format(id)
    else:
        return '班级{}详情'.format(id)
  • 给指定函数构造 URL
@app.route('/demo3/')
def demo3():
    school_url = url_for('school', school_level='high', name='college') 
    # 具体要拼接的查询参数 以关键字实参的形式写在url_for里
    print(school_url)  #/school/?shool_level=high&name=college
    return school_url
@app.route('/school/')
def school():
    return 'school message'
  • 访问静态数据
url_for('static', filename='style.css')
#这个文件应该存储在文件系统上的 static/style.css。

3.6. Layui 模板学习使用

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201115094825916.png

3.7. 学习记录

  • 基本代码都有了,学习只关注了flask那登录到主页那部分,其他的处理逻辑没有具体细看。如果不考虑css中 layui 如何使用;
  • 以后自己写python的管理系统,基于这个代码修改;
  • 登录,数据库连接,请求啥的都齐全了;
  • 后续自己编写相关系统的时候可以具体在学习 block 块使用规则。
  • 项目效果; 如果做物联网可以添加卡片式的那种显示效果

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/image-20201115095655445.png

学习链接

0%