flask 杂记2_html

 添加属性

@property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw):
        self._password = generate_password_hash(raw)

=========自定义上下文管理器的一种方法

flask 杂记2_flask_02

 

 上下文管理器的一种应用

class SQLAlchemy(_SQLAlchemy):
    @contextmanager
    def auto_commit(self, throw=True):
        try:
            yield
            self.session.commit()
        except Exception as e:
            self.session.rollback()
            current_app.logger.exception('%r' % e)
            if throw:
                raise e

 

 ========表单自定义验证,自定义验证定义了即会被自动调用

flask 杂记2_flask_03

 

class RegisterForm(EmailForm):
    nickname = StringField('昵称', validators=[
        DataRequired(), Length(2, 10, message='昵称至少需要两个字符,最多10个字符')])

    password = PasswordField('密码', validators=[
        DataRequired(), Length(6, 20)])

    def validate_email(self, field):
        if User.query.filter_by(email=field.data).first():
            raise ValidationError('电子邮件已被注册')

 

 =====================

防止参数为空:用DataRequired

from wtforms.validators import DataRequired
class Base(db.Model):
    __abstract__ = True   #这是个基类,不想让sqlalchemy创建
    create_time = Column('create_time', Integer)
    status = Column(SmallInteger, default=1)
def set_attrs(self, attrs):
    for key, value in attrs.items():
        if hasattr(self, key) and key != 'id':
setattr(self, key, value)

flask 杂记2_自定义_04

 

 

flask 杂记2_html_05

 

 

配置文件中的key一定要是大写,小写会找不到

flask 杂记2_自定义_06

 

 flask 杂记2_html_07

 

 

=============

返回json字符串可以用jsonify

static_url_path: 访问静态资源的url前缀

当装饰器和请求方式完全相同时,那么执行的是第一个,如果装饰器相同但是请求方式不相同,那么它们将是独立的个体

 

# 通过url_map可以查看整个flask中的路由信息
    print(app.url_map)

 

路由中参数类型:

flask 杂记2_自定义_08

 

 示例:@app.route("/goods/<int:goods_id>")

定义自己的类型转换器:​​https://mp.weixin.qq.com/s/eyfuFdOcMJiEuCAWGNpLag​

from werkzeug.routing import BaseConverter
class MobileConverte(BaseConverter)

 request对象中保存了一次HTTP请求的一切信息

flask 杂记2_flask_09

 flask 杂记2_自定义_10

 flask 杂记2_html_11

 

 

 

 postman 下载地址:  ​https://www.getpostman.com/downloads/​

当我们从前端发送的数据如果是表单的数据就可以直接从form里面进行提取,如果不是表单数据那我们无法form中提取东西,我们只能从data当中去提取请求体当中的数据

 http://127.0.0.1:5000/post?city=hunan url中的参数通过request.args.get("city")得到

上传文件主要用了request当中属性files

 abort函数:它可以终止视图函数的执行并且还可以返回给前端特定的信息,若传递状态码则,必须是http标准状态码

自定义错误处理方法 :@app.errorhandler(404)

通过元组的形式,返回自定义的响应信息

flask 杂记2_flask_12

 

 除了一些规定的状态码,我们也可以返回自定义的状态码

通过make_response 设置返回内容
app.route("/index")
def index():
    resp = make_response("index page")
    resp.status = "666"
    resp.headers["city"] = "hn"

# 设置cookie
 resp.set_cookie("Itcast", "python")

    return resp
返回json数据
@app.route("/index")
def index():
    data = {
        "name":"javaandpython",
        "age":20
    }
    return jsonify(data)

jsonify不仅可以帮我们把字典转为json格式,还能帮我们把响应头中的Content-Type设置为application/json

  cookie的默认有效期是临时cookie,浏览器关闭就会失效

resp.set_cookie("Itcast", "python", max_age=3600) 通过max_age设置有效期单位是秒

获取cookie:c = request.cookies.get("Itcast")

删除cookie
@app.route("/delete_cookie")
def delete_cookie():
    resp = make_response("del success")
    resp.delete_cookie()
    return resp

其实在删除cookie当中,并不是真正的删除,只是把当前需要删除的cookie的有效期设置为了创建时候的时间,所以相当于是删除了cookie

在Flask当中如果我们需要使用session,那么我们必须配置app当中的SECRET_KEY参数,否则程序会报错。参数的值我们可以任意编写

app.config["SECRET_KEY"] = "123FIISUODFNOSAIFNHASIJDdasd"

 request:封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。

    session:用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息

 利用“上下文对象”将request对象作为全局变量,此时这个request对象就是在这个线程中的全局变量。但是如果这个对象是在A线程当中那么他就是A线程中的全局变量,在其他线程(B线程,C线程...)当中不是全局变量,这样就可以保证对象不会混淆

request和session都属于请求上下文对象

current_app和g都属于应用上下文对象。

 

1.before_first_request : 在第一次请求之前运行,只执行一次,如链接数据库

2.before_request : 在每一次请求都会执行,可以在这里做权限校验操作,比如说某用户是黑名单用户,黑名单用户登录系统将遭到拒绝访问,可以使用before_request进行权限校验。

3.after_request :在请求之后运行,会接收一个参数,这个参数就是前面的请求处理完毕之后, 返回的响应数据,如果需要对响应做额外处理,可以再这里进行。

4.teardown_request :每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息

 

userlog 把user.id当作外键,则选要在user定义时,需要加上外键关系

class User(db.Model):
    __tablename__ = "user"
    __table_args__ = {"useexisting": True}
    id = db.Column(db.Integer, primary_key=True)  # 编号
    name = db.Column(db.String(100), unique=True)  # 昵称
    pwd = db.Column(db.String(100))  # 密码
    email = db.Column(db.String(100), unique=True)  # 邮箱
    phone = db.Column(db.String(11), unique=True)  # 电话号码
    info = db.Column(db.Text)  # 个性简介
    face = db.Column(db.String(255), unique=True)  # 头像
    addtime = db.Column(db.DateTime, index=True, default=datetime.now)  # 添加时间
    uuid = db.Column(db.String(255), unique=True)  # 唯一标志符
    userlogs = db.relationship('UserLog', backref='user')  # 会员日志外键关系
    comments = db.relationship('Comment', backref='user')  # 评论外键关系关联
    moviecols = db.relationship('MovieCol', backref='user')  # 电影收藏外键关系关联


# 定义会员登录日志模型
class UserLog(db.Model):
    __tablename__ = "userlog"
    __table_args__ = {"useexisting": True}
    id = db.Column(db.Integer, primary_key=True)  # 编号
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))  # 所属会员
    ip = db.Column(db.String(100))  # 登录IP
    addtime = db.Column(db.DateTime, index=True, default=datetime.now)  # 添加时间

 ================

在模板中的操作:
1、静态文件的引入
{{ url_for('static',filename='文件路径')}}
2、定义路由
{{ url_for('模块名.视图名',变量=参数)}}
3、定义数据块
{%block 数据块名称%} .....{% endblock %}

==================

index.html继承了home.html,index.html和home.html 在同级目录,要加上 home

{% extends "home/home.html" %}      <!-- 不能写成这样 {% extends "home.html" %}-->
{% block content %} <h1>Helo,World!</h1> {% endblock %}

 =============把一个页面添加到另一个页面

{% include "home/menu.html" %}

================

# 登录装饰器
def user_login_req(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if "user" not in session:
            return redirect(url_for("home.login", next=request.url)) #登陆之后,跳到用户想访问的页面
        return f(*args, **kwargs)
    return decorated_function

 ====================

def login():
    form = LoginForm()
    if form.validate_on_submit():
        data = form.data
        user = User.query.filter_by(name=data["name"]).first()
        if not user.check_pwd(data["pwd"]):
            flash("密码错误!", "err")
            return redirect(url_for("home.login"))
        session["user"] = user.name
        session["user_id"] = user.id
        userlog = UserLog(
            user_id=user.id,
            ip=request.remote_addr    # 获取用户的登陆地址
        )
        db.session.add(userlog)
        db.session.commit()
        return redirect(url_for("home.user"))
    return render_template("home/login.html", form=form)  # 是相对templates的相对地址

 =============

from werkzeug.security import generate_password_hash
pwd=generate_password_hash(data["pwd"]) #密码加密
from werkzeug.security import check_password_hash
return check_password_hash(self.pwd, pwd) #密码是否与数据库中的一致

==============

if request.method == "GET":    # 给它们赋初始值

===========

Response(resp, mimetype='application/json')  #告诉浏览器资源的类型,浏览器根据资源类型决定如何处理服务器返回的内容

==========多表关联查询

page_data = Comment.query.join(
        Movie
    ).join(
        User
    ).filter(
        Movie.id == movie.id,
        User.id == Comment.user_id
    ).order_by(
        Comment.addtime.desc()
    ).paginate(page=page, per_page=10)

 ==========添加多条记录

db.session.add_all(user_list)
db.session.commit()

 =======跨域访问


跨域是指:浏览器A服务器B获取的静态资源,包括Html、Css、Js,然后在Js中通过Ajax访问C服务器的静态资源或请求。即:浏览器A从B服务器拿的资源,资源中想访问服务器C的资源

pip install Flask-Cors

​from flask_cors import CORS​

=================

 Flask-Limiter对flask的路由功能提供访问速率限制的功能。访问的信息可以存储到应用本身的内存里,或者存储到redis、memcache里

from flask_limiter import Limiter

======性能调试工具:每行代码的执行时间==========
javascript:void(0)
from line_profiler import LineProfiler
from line_profiler import LineProfiler
import random
 
def do_other_stuff(numbers):
    s = sum(numbers)
 
def do_stuff(numbers):
    do_other_stuff(numbers)
    l = [numbers[i]/43 for i in range(len(numbers))]
    m = ['hello'+str(numbers[i]) for i in range(len(numbers))]
 
numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)

这样做的话,只能显示子函数的总时间
为了能够同时显示函数每行所用时间和调用函数每行所用时间,加入add_function就能够解决
from line_profiler import LineProfiler
import random
 
def do_other_stuff(numbers):
    s = sum(numbers)
 
def do_stuff(numbers):
    do_other_stuff(numbers)
    l = [numbers[i]/43 for i in range(len(numbers))]
    m = ['hello'+str(numbers[i]) for i in range(len(numbers))]
 
numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp.add_function(do_other_stuff)   # add additional function to profile
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()

 =========

@app.route("/index/") 写成这样的话,/index和/index/都能访问此视图函数
@app.route("/index") 写成这样的话,/index/是无法访问的
打开debug=TRUE模式后,后端的修改会导致flask重启,是修改立即生效
添加路由函数的另一种方法:app.add_url_rule('/index',view_func=hello) 基于类的视图需要这样添加视图函数