flask-day5-6:类视图|app.add_url_rule|标准类视图及继承|装饰器与视图类视图函数|蓝本|二级域名|ORM之SQLALchemy新建表查删改|执行原生SQL语句

类视图

app.add_url_rule方法

除了装饰器@app.route(rule)可以将方法暴露给client外,还可以采用app.add_url_rule方法暴露方法

@app.route('/')
def hello_world():
    print(url_for("profile"))   # profile是app.add_url_rule方法的endpoint参数定义的,代表my_profile方法
    return 'Hello World!'
def my_profile():
    context = {
        'name':'zhangsan',
        'sex':'male',
        'age':18
    }
    return render_template("profile.html", **context)

app.add_url_rule("/profile/", view_func=my_profile)

profile.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
这是个人信息页面:
<ul>
<li>    姓名:{{ name }}</li>
<li>性别:{{ sex }}</li>
<li>年龄:{{ age }}</li>
</ul>
</body>
</html>

避坑:view_func=my_profile就是暴露函数my_profile,使能通过访问http://host:port/profile/访问到该函数,my_profile不需要引号或括号。
app.add_url_rule("/profile/", view_func=my_profile)可以加入endpoint参数,如:

app.add_url_rule("/profile/", endpoint="profile",view_func=my_profile)

当你写了 endpoint=‘profile’ 那么在 hello_world方法中获取路由地址必须通过 url_for(‘jack’);
如果没有写endpoint 可以通过 url_for(‘my_profile’) 获取到 /profile/.

标准类视图

标准类视图是继承自flask.views.View,并且在子类中必须实现dispatch_request方法,这个方法类似于视图函数,也要返回一个基于Response或者其子类的对象。以下将用一个例子进行讲解:

#app.py
class login(View):                    #1. 定义类,继承自flask.views.View
    def dispatch_request(self):       #2. 必须有此方法,除了名称有要求外,其他写法与视  图函数一样
        context = {
            'username': "zhangwuji",
            'password': "123456"
        }
        return render_template("login.html", **context)

app.add_url_rule("/login", view_func=login.as_view("login"))  #3.使用add_url_rule将类方法映射到url,从而实现类视图

类视图的继承

  1. 场景:login类视图和register类视图都差不多,可以新建一个common类作为被继承者。方法是:
#app.py
class common(View):                  
    def __init__(self):              #定义类属性
        self.context = {             #self.context就是login,register类方法里的内容
            'username': "zhangwuji",
            'password': "123456"
        }

class login(common):   #继承common类
    def dispatch_request(self):
        return render_template("login.html", **self.context)  #**self.context调用common类的属性

class register(common):
    def dispatch_request(self):
		self.context.update({                #使用或修改父类common的context内容
            "username":"zhaomin",
            "age":20
        })    	
        return render_template("register.html", **self.context)


app.add_url_rule("/login", view_func=login.as_view("login"))
app.add_url_rule("/register", view_func=register.as_view("register"))
  1. 使用类视图返回json
#app.py
class Jsonview(View):           #1.定义类
    def dispatch_request(self):   #3-1使用子类get_data方法获取数据,并进行json化
        return jsonify(self.get_data())
    def get_data(self):         #3-2 如果出错,则报错
        raise NotImplementedError

class ListView(Jsonview):
    def get_data(self):             #2.将数据返回父类,父类获取后进行jsonify
        return {
            "username": "zhouzhiruo",
            "age": 18,
            "door": "ermei"
        }
app.add_url_rule("/list", view_func=ListView.as_view("list"))

使用装饰器修饰视图类和视图函数

  1. 视图函数装饰器
    step 1:视图函数settings
@app.route("/settings")
def settings():
    return "设置页面"

step 2: 增加装饰器,实现验证功能
装饰器的作用:用户通过http://…/settings?username=zhaomin访问才能调用函数settings,从而实现验证功能

def loginRequired(func):
    def wrapper(*args, **kwargs):
        username = request.args.get("username")
        password = request.args.get("password")
        if username and username=="zhaomin":
            return func(*args,**kwargs)
        else:
            return "请先登录"
    return wrapper

step3:将装饰器加载在settings上:

@app.route("/settings")
@loginRequired           #装饰器必须放在其他装饰器之后,靠近函数
def settings():
    return "设置页面"

检验:
(1) 访问http://127.0.0.1:5000/settings,提示“请先登录”,缺少验证
(2)访问http://127.0.0.1:5000/settings?username=abc,提示“请先登录”,验证错误
(3)访问http://127.0.0.1:5000/settings?username=zhaomin,成功调用,显示“

蓝本(可理解成模块)

基本使用

之前我们写的url和视图函数都是处在同一个文件app.py,如果项目比较大的话,这显然不是一个合理的结构,而蓝图可以优雅的帮我们实现这种需求。通过blueprint模块对项目进行拆分,如豆瓣项目拆分成电影,阅读,音乐等模块,独立开发独立访问:访问时用douban.com/book,douban.com/book/list的形式:
step 1:
项目中新建package,在其中新建book.py,music.py用于子模块
step 2:
以book模块为例,book.py的代码 :

@book_bp.route("/")
def book():
    return "这是阅读首页"

@book_bp.route("/list")
def listBook():
    return "这是阅读列表"

step 3: (关键词:url_predix="/book")
将book.py变成蓝本:
http://127.0.0.1:5000/book

from flask import Blueprint   # 1.导入蓝本模块
book_bp = Blueprint("book", __name__, url_prefix="/book")   #2.将book.py变成类似app.py的模块,book_bp就是蓝图的实例

@book_bp.route("/")       # 3.对应http://127.0.0.1:5000/book
def book():
    return "这是阅读首页"

@book_bp.route("/list")  # 4.对应http://127.0.0.1:5000/book/list
def listBook():
    return "这是阅读列表"

step4: 通过__init__将book_bp暴露出去

from .book import book_bp   

step5:设置app.py,使其可以与book_bp通信
app.py

from flask import Flask
from blueprints import book_bp  #1. 将book_bp导入
app = Flask(__name__)
app.register_blueprint(book_bp)    #2.注册book_bp

@app.route('/')
def index():
    return '这是豆瓣首页'
if __name__ == '__main__':
    app.run()

完成。访问http://127.0.0.1:8888/ 调用app.py的index(),访问http://127.0.0.1:8888/book 调用book.py的book(),访问http://127.0.0.1:8888/book/list 调用book.py的listBook().实现主模块与子模块的拆分。

模板与静态资源的拆分

每个模块可以使用自己的模板目录和静态资源目录,只需在Blueprint函数中指定目录地址即可

book_bp = Blueprint("book", __name__, url_prefix="/book", template_folder="./book_templates",
                    static_folder="./book_static")

@book_bp.route("/listTemplates")
def listFromTemplates():
    return render_template("booklist.html")    # 访问地址http://127.0.0.1:8888/book/listTemplates,返回book_tempalates目录的booklist.html

查找顺序:
return render_template(“booklist.html”) 中会先在templates目录下查看有无该模板,如果没有再到指定的book_templates目录下找该模板;
静态资源由模板文件指定,如booklist.html的<link type=“text/css” rel=“stylesheet” href={{ url_for(“static”,filename=“css.css”) }} >指定的css.css文件是在app的static目录,<link type=“text/css” rel=“stylesheet” href={{ url_for(“book.static”,filename=“css.css”) }} >指向的是book.py蓝图中指定的static目录(注:=由于已指定,不用写目录全称,只要写book.static即可=)

二级域名 (关键词:Blueprint(“data”,name,subdomain=“data”)

与url_prefix设置方式不一样的地方只有两处:一是要映射主机名,第二是要在data.py的Blueprint(subdomain=‘data’)

  1. 将ip地址映射到域名上 打开本地hosts文件,增加两行:127.0.0.1 lai.com 127.0.0.1 data.lai.com
  2. 在app.py上进行映射主机名,访问地址改成:http://lai.com:8888
from flask import Flask
from blueprints import data_bp
app = Flask(__name__)
app.config['SERVER_NAME'] = 'lai.com:8888'  #映射主机名
app.register_blueprint(data_bp)

@app.route('/')
def index():
    return '这是豆瓣首页'

if __name__ == '__main__':
    app.run()
  1. data.py
from flask import render_template, Blueprint
data_bp = Blueprint('data', __name__, template_folder="./data_templates", subdomain='data',static_folder='./data_static')    # 与前缀url的不同之处是设置subdomain="data",不再设置url_prefix

@data_bp.route("/")
def data():
    return render_template("index.html")

@data_bp.route("/list")
def data_list():
    return "this is data_list page"

4.init

from .data import data_bp

ORM

为了实现继承重用,在进行关系数据库操作时不直接使用sql语言,而是使用ORM模型(对象关系模型).
其思想基于对象与关系的对应:类-数据表,类的属性对应表的字段,实例对应表的记录.
好处:减少出错,增加复用

使用SQLALchemy操作数据库之前要安装如下模块:
pymysql,mysql
pip install mysql
pip install pymysql

创建表

create.py

# ---coding:utf-8----
# 文件名: sqlalchemy_create.py
# @Time:2020/4/19 11:47
from sqlalchemy import create_engine, Column, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base

HOSTNAME = '120.24.*.*'
PORT = '3306'
DATABASE = 'school'
USERNAME = 'python'
PASSWORD = '*'
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)                            

engine = create_engine(DB_URI)                #  1. create_engine得到操作数据库的相关信息
Base = declarative_base(engine)   # 2. declarative_base将上述信息生成一个类,该类具有创建表的功能
class Book(Base):                   #3.Book类继承自Base类
    __tablename__ = "book"
    id = Column(Integer,primary_key=True,autoincrement=True)
    name = Column(String(50))
    author = Column(String(20))
    brief = Column(Text())

Base.metadata.create_all()            #4.建表
# Base.metadata.drop_all()  #5. 如果需要更改Book类,直接修改是无效的,需要先删除类,再执行一次修改后的类方法

此处有坑
运行上述代码后,成功创建了一个表book.复制所有代码粘贴到新建py中,发现无法创建新表,如book1,必须要关掉create.py后才能正常运行创建新表.

查删改
# ---coding:utf-8----
# 文件名: sqlalchemy_create.py
# @Time:2020/4/19 11:47
from sqlalchemy import create_engine, Column, Integer, String, Text, or_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

HOSTNAME = '120.24.*.*'
PORT = '3306'
DATABASE = 'school'
USERNAME = 'python'
PASSWORD = '*'
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URI)
Base = declarative_base(engine)  # Base是一个类,由declarative_base基于engine生成,
session = sessionmaker(engine)()  # sessionmaker(engine)生成一个具有操作engine的类,session是它的实例

class Book(Base):
    __tablename__ = "book"
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))
    author = Column(String(20))
    brief = Column(Text())
    def __str__(self):
        return "书名:%s,作者:%s,简介:%s"% (self.name,self.author,self.brief)
# Base.metadata.drop_all()
Base.metadata.create_all()

def add_data():              #增加记录(即ORM中的对象)
    b1 = Book(name="西游记", author="吴承恩", brief="西天取经")   #1.实例化对象
    b2 = Book(name="红楼梦", author="曹雪芹", brief="贾府风月")
    b3 = Book(name="藏秘排油", author="郭德纲", brief="减肥314")
    session.add(b1)                 #2.通过session添加
    session.add_all([b2,b3])
    session.commit()                #3.执行

def query_data():    # 查询记录可使用filter_by或filter后者功能更强大
    # all_books = session.query(Book).all()
    # all_books = session.query(Book).filter_by(name="西游记",author="吴承恩").all()
    # all_books = session.query(Book).filter(Book.name == "西游记").all()
    # all_books = session.query(Book).filter_by(name="西游记", author="吴承恩").all()
    # all_books = session.query(Book).filter(or_(Book.name=="西游记", Book.author=="郭德纲")).all()
    all_books = session.query(Book).filter(Book.author!="").all()

    for b in all_books:
        print(b)


def update_data():  #修改记录
    # book = session.query(Book).filfirst()
    book = session.query(Book).filter_by(author="郭德纲").first()
    book.brief = "减肥产品抢购一空,观众表示不服"
    session.commit()

def del_data():  # 删除记录
    book = session.query(Book).filter_by(author="吴承恩").first()
    session.delete(book)
    session.commit()


if __name__ == "__main__":
    # add_data()
    # update_data()
    del_data()
    query_data()

SQLALchemy使用原生sql语句

# ---coding:utf-8----
# 文件名: constants.py
# @Time:2020/4/19 15:59
from sqlalchemy import create_engine

HOSTNAME = '120.24.*.*'
PORT = '3306'
DATABASE = 'school'
USERNAME = 'python'
PASSWORD = '*'
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
#连接数据库
engine = create_engine(DB_URI, echo=True)
# 使用with语句连接数据库,如果发生异常会被捕获
with engine.connect() as con:   
# 先删除authors表
    con.execute("drop table if exists authors")
# 创建一个users表,有自增长的id和name
    con.execute("create table authors(id int primary key auto_increment,name varchar(30))")
    # 插入两条数据到表中
    con.execute("insert into authors(name) value('岳云鹏')")
    con.execute("insert into authors(name) value('张九龄')")
# 执行查询操作
    result = con.execute("select * from authors")
# 从查找的结果中遍历
    for a in result:
        print(a)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值