Python_day25--Flask插件:Flask-SQLAlchemy、Flask-Bootstrap

这篇博客介绍了如何在Flask应用中使用Flask-SQLAlchemy进行数据库操作,包括数据库链接、建表、数据添加和查询。同时,讲解了Flask-Bootstrap的安装和使用,以便快速集成Bootstrap框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Flask-SQLAlchemy

1、ORM    框架

       Web开发中,一个重要的组成部分便是数据库了。Web程序中最常用的莫过于关系型数据库了,也称SQL数据库。另外,文档数据库(如    mongodb)、键值对数据库(如redis)近几年也逐渐在 web开发中流行起来,我们习惯把这两种数据库称为NoSQL数据库。
大多数的关系型数据库引擎(比如MySQL、Postgres和SQLite)都有对应的Python包。在这里,我们不直接使用这些数据库引擎提供的  Python包,而是使用对象关系映射(Object-Relational Mapper,ORM)框架,它将低层的数据库操作指令抽象成高层的面向对象操作。也就是说,如果我们直接使用数据库引擎,我们就要写SQL操作语句,但是,如果我们使用了ORM框架,我们对诸如表、文档此类的数据库实体就可以简化成对Python对象的操作。Python中最广泛使用的ORM框架是SQLAlchemy,它是一个很强大的关系型数据库框架,不仅支持高层的ORM,也支持使用低层的SQL操作,另外,它也支持多种数据库引擎,如MySQL、Postgres和SQLite等。

2、Flask-SQLAlchemy

在Flask中,为了简化配置和操作,我们使用的ORM框架是Flask-SQLAlchemy,这个Flask扩展封装了SQLAlchemy框架。在Flask-SQLAlchemy中,数据库使用URL指定,下表列出了常见的数据库引擎和对应的    URL。

3、安装

首先,我们使用pip安装Flask-SQLAlchemy,安装在你所需要的环境中,本作者使用的是虚拟环境,虚拟环境能比较好的解决依赖问题,

pip install flask-sqlalchemy

 4、应用

1)链接数据库

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:yutao@127.0.0.1/TodoProject"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# app.config['SECRET_KEY'] = 'westos'
app.config['SECRET_KEY'] =  os.urandom(24)
Bootstrap(app)

# 实例化db对象
db = SQLAlchemy(app)

这里有几点需要注意的是:
1、app应用配置项SQLALCHEMY_DATABASE_URI指定了SQLAlchemy所要操作的数据库,这里我们使用的是mysql数据库,引号里是你需要链接的数据库://用户名和密码@本机localhost或远程链接某个数据库,/后面是你要链接数据库的名称;这里特别说一点就是数据库的编码格式问题,当你在创建数据库时可以使用下面这个命令来解决你的编码问题;

create database 数据库名称 default charset utf8;

'SQLALCHEMY_DATABASE_URI'    =====》链接 数据库;

'SQLALCHEMY_TRACK_MODIFICATIONS' ======》Ture

'SECRET_KEY' =====》加密

2、db    对象是    SQLAlchemy    类的实例,表示程序使用的数据库。

3、我们定义的User模型必须继承自db.Model,这里的模型其实就对应着数据库中的表。其中,类变量 __tablename__ 定义了在数据库中使用的表名,如果该变量没有被定义,Flask-SQLAlchemy会使用一个默认名字。

2)建表

在这里我们的建表有了突破性的进展,前面我们一直说mysql是一个关系型数据库,但是没有体现出“关系”二字,在这里我们就要建立有关系的数据表;

我们设想这样的一个场景:我们在公司的内部系统上每一天都会有任务发布,有任务本身和它相关的执行部门,他们两个关系在任务产生的时候就被绑定在了一起,这样也就完成了我们所说的关系,那么我们在数据库中怎样建立数据表之间的关系呢?

外键约束是在两张表中建立的。两张表存在父子关系,即:子表中的某个字段的取值有父表决定的。
结论:在一对多关系中额,外键建立在多的一方

例如:简单的例子在很多的电影网站上都有会员,超级会员,普通会员这三种会员身份,我们需要对普通用户的身份进行关联

# 创建user表
class Users(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    # unique: 指定该列信息是唯一的;
    name = db.Column(db.String(50), unique=True)
    passwd = db.Column(db.String(50))
    # default是默认值l
    add_time = db.Column(db.DateTime, default=datetime.now())
    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))  #和哪张表的哪个表头进行关联





# 创建用户角色(超级会员, 会员, 普通会员)
class Role(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(50), unique=True)
    # 'Users代表的是Role表关联的数据库表'
    # backref=“role”: 反向引用;让Users中有role属性, user.role返回的是role对象。
    users = db.relationship('Users', backref='role')   #上表和这里的进行相关联

    #
    # def __repr__(self):
    #     """如果查询数据表内容, 需要特色化设置时, 使用__repr__"""
    #     return  "<Role %s>" %(self.name)
    


# 1. 创建表
# db.create_all()

 下面的是我们更为复杂的例子:

class Todo(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    # unique: 指定该列信息是唯一的;
    name = db.Column(db.String(50))
    # default是默认值l
    add_time = db.Column(db.DateTime, default=datetime.now())
    status = db.Column(db.Boolean, default=False)
    department_id = db.Column(db.Integer, db.ForeignKey('department.id'))


class Department(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    name = db.Column(db.String(50), unique=True)
    todos = db.relationship('Todo', backref='department')
    users = db.relationship('User', backref='department')


class User(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    # unique: 指定该列信息是唯一的;
    name = db.Column(db.String(50), unique=True)
    # 此处为了用户帐号的安全性, 必须对密码进行加密;
    pwd = db.Column(db.String(100))
    email = db.Column(db.String(20), unique=True)
    phone = db.Column(db.String(20), unique=True)
    info = db.Column(db.Text)  # 个性简介
    addtime = db.Column(db.DateTime, default=datetime.now())
    department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
    userlogs = db.relationship('UserLog', backref="user")

    def check_pwd(self, pwd):
        return check_password_hash(self.pwd, 'westos1')


# 用户登录日志
class UserLog(db.Model):
    id = db.Column(db.Integer, autoincrement=True, 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, default=datetime.now())
    area = db.Column(db.String(100))  # 登录的城市

3)给表中添加信息

1、建表

    # 1). 创建表
    # db.create_all()

2、给表内添加信息

 2). 初始化数据
    parts = ['开发部', '运维部', '人事部']
    partObj = [Department(name=part) for part in parts]
    db.session.add_all(partObj)
    db.session.commit()



    todos = ['打扫卫生', '开发微电影管理系统', '招聘人才']
    todoObj = [Todo(name=todo, department_id=random.choice([1,2,3]) ) for todo in todos]
    db.session.add_all(todoObj)
    db.session.commit()

3、添加用户的测试数据

u1 = User(name="westos1", pwd=generate_password_hash('westos'), department_id=1)
    u2 = User(name="westos2", pwd=generate_password_hash('westos'), department_id=2)
    u3 = User(name="westos3", pwd=generate_password_hash('westos'), department_id=1)

    db.session.add_all([u1, u2, u3])
    db.session.commit()

注意:这里我们用到了哈希加密

什么是哈希加密:HASH主要用于信息安全领域中加密算法,他把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值. 也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系

这里我们用到的加密模块为:

from werkzeug.security import generate_password_hash

相对应的也就有解密模块:

from werkzeug.security import check_password_hash

解密的时候我们需要两个参数:分别是哈希加密后的一串代码,再其次是我们的明文密码,返回值为Ture 或 False

4)查询数据信息

# 查询所有的角色;
print(Role.query.all())

1、 如何显示会员类型与该会员类型包含的所有用户;

roles为对象。对象对应的属性我们都可以看到

roles = Role.query.all()
for role in roles:
    print(role.id, role.name,role.users)

2、显示所有的用户以及用户类别

users = Users.query.all()
for user in users:
    print(user.id, user.name, user.passwd, user.role)

3、根据条件查找符和条件的数据和更新数据;(filter_by(常用), filter)

# 1). 找到所有超级会员的用户;
users = Users.query.filter_by(role_id=1).all()


# 2). 更新所有超级会员的密码为0000000;
for user in users:
    # print(user.passwd)
    user.passwd = "000000"
    print("更新用户%s的密码成功!" %(user.name))
    db.session.add(user)
    db.session.commit()

4、其他的查询信息显示限制条件

users = Users.query.filter_by(role_id=1).limit(10).all()
print(users, len(users))

5、排序: 根据用户创建的时间进行排序(默认情况正序, 如果要逆序desc())

users = Users.query.order_by(desc(Users.add_time)).all()
for u in users[:10]:
    print(u.add_time)

6、limit可以限制查询数据的数量;

users =Users.query.order_by(desc(Users.add_time)).limit(5).all()
print(users)

7、offset: 偏移量, 可以设置查询偏移量,也就是数据的起始位置, 一般与limit结合使用;

print(Users.query.order_by(desc(Users.add_time)).limit(5).offset(2).all())

8、slice: 切片

print(Users.query.order_by(desc(Users.add_time)).slice(1,5).all())

9、分页:第一个参数为页码,第二个参数为每一页显示的内容

page_u = Users.query.paginate(1, 3)
print(page_u.items)
print(dir(page_u))

page_u = Users.query.paginate(2, 3)
print(page_u.items)

10、用户数据更新;

u = Users.query.filter_by(id=1).first()
print(u.id, u.name, u.add_time)

u.name = "西部开源1"
db.session.add(u)
db.session.commit()


u = Users.query.filter_by(id=1).first()
print(u.id, u.name, u.add_time)

 

11、用户信息删除;

u = Users.query.filter_by(id=1).first()
db.session.delete(u)
db.session.commit()


u = Users.query.filter_by(id=1).first()
print(u.id, u.name, u.add_time)

 

二、Flask-Bootstrap

Bootstrap是Twitter开源的一个CSS/HTML框架,它让Web开发变得更加迅速,简单。要想在我们的Flask应用中使用Boostrap,有两种方案可供选择:
第1种,在我们的Jinja2模板中直接引入Bootstrap层叠样式表(CSS)和JavaScript文件,比如bootstrap.min.css,bootstrap.min.js;
第2种,也是更简单的方法,就是使用一个    Flask-Bootstrap    的扩展,它简化了集成Bootstrap 的过程;

1、安装

pip	install	flask-bootstrap

2、使用

from werkzeug.security import check_password_hash

from models import app, Todo, db, Department, User, UserLog
from flask import render_template, redirect, url_for, request, flash, session
from functools import wraps



from urllib.request import  urlopen
import  json

# 通过ip获取该IP的所在城市和国家;
def get_ip_area(ip):
    # 构造url地址, 使用淘宝的API接口
    url = 'http://ip.taobao.com/service/getIpInfo.php?ip=%s' %(ip)
    # 获取页面返回的内容()
    json_data =  urlopen(url).read().decode('utf-8')
    # 将json格式的数据转换为字典格式;
    s_data = json.loads(json_data)
    country = s_data['data']['country']
    if country == 'XX':
        country = ''
    city = s_data['data']['city']
    if city == 'XX':
        city = ''
    return country+city




# 编写一个判断用户是否登录的装饰器
def is_login(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        # 判断不在session(会话)中, 跳转到登录页面;
        if not "user" in session:
            return redirect(url_for('login'))
        return f(*args, **kwargs)

    return wrapper


@app.route('/list/<int:page>/')
@app.route('/list/')
@is_login
def list(page=1):
    todos = Todo.query.paginate(page, per_page=5)
    parts = Department.query.all()
    return render_template('list.html', todos=todos, parts=parts)


@app.route('/done/<int:todo_id>/')
@is_login
def done(todo_id):
    todo = Todo.query.filter_by(id=todo_id).first()
    todo.status = True
    try:
        db.session.add(todo)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        return e
    return redirect(url_for('list', page=1))


@app.route('/undone/<int:todo_id>/')
@is_login
def undone(todo_id):
    todo = Todo.query.filter_by(id=todo_id).first()
    todo.status = False
    try:
        db.session.add(todo)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        return e
    return redirect(url_for('list', page=1))


@app.route('/delete/<int:todo_id>/<int:page>/')
@is_login
def delete(todo_id, page=1):
    u = Todo.query.filter_by(id=todo_id).first()
    db.session.delete(u)
    db.session.commit()
    return redirect(url_for('list', page=page))


@app.route('/add/', methods=['POST'])
@is_login
def add():
    # 通过request获取 表单提交的内容;
    data = request.form
    name = data['todo_name']
    part = data['part']
    # 实例化对象
    todo = Todo(name=name, department_id=part)
    db.session.add(todo)
    db.session.commit()
    return redirect(url_for('list'))


@app.route('/login/', methods=['POST', 'GET'])
def login():
    # 判断用户的HTTP请求方法
    if request.method == 'POST':
        # 1). 接收提交的数据;
        data = request.form
        name = data['name']
        pwd = data['pwd']

        # 2). 判断用户名是否存在, 密码是否正确?
        u = User.query.filter_by(name=name).first()

        if u and check_password_hash(u.pwd, pwd):
            session['user'] = u.name
            session['user_id'] = u.id
            userlog = UserLog(
                user_id=u.id,
                ip=request.remote_addr,
                area=get_ip_area(request.remote_addr)
            )
            db.session.add(userlog)
            db.session.commit()
            return redirect(url_for('list'))
        else:
            # flash: 消息闪现,
            # 如何在前端html页面显示? Jinja2 get_flash_messages()
            # 返回的是一个列表, 想依次显示内容, 需要用到for循环;
            flash('用户或者密码不正确!')
            return redirect(url_for('login'))
    else:
        return render_template('login.html')


@app.route('/logout/')
def logout():
    # 将会话中的key值弹出;
    session.pop('user', None)
    session.pop('user_id', None)
    # 注销跳转到登录页面, 或者公共首页
    return redirect(url_for('login'))


@app.route('/<int:page>')
@app.route('/')
def index(page=1):
    parts = Department.query.all()
    untodos = Todo.query.filter_by(status=False).paginate(page, per_page=5)
    return render_template('index.html', parts=parts, untodos=untodos)


#
#
# #
# @app.route('/add/', methods=['POST'])
# def add():
#     form = request.form
#     print(form)
#     name = form['content']
#     part = form['part']
#     todo = Todo(name = name, department_id=part)
#     db.session.add(todo)
#     db.session.commit()
#     todos = Todo.query.all()
#     return redirect(url_for('list'))


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5008)

初始化Flask-Bootstrap之后,我们的模板通过继承一个基模板,即bootstrap/base.html ,就可以使用Bootstrap了。
新建一个templates文件夹,在该文件夹中添加一个base.html的文件,代码如下: 

{% extends 'bootstrap/base.html' %}


{% block title %}
    首页
{% endblock %}


{% block styles %}
    {{ super() }}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main6.css') }}" type="text/css">
    <style>
        .navbar-default {
            background-color: white;
            border: 0;
            box-shadow: 0px 2px 8px 0px rgba(50, 50, 50, 0.2);

        }

        .navbar-default .navbar-brand {
            font-size: 30px;
            color: #40D2B1;
            height: 70px;
            line-height: 35px;

        }

        .navbar-default .navbar-nav li a {
            font-size: 16px;
            color: #666;
            height: 70px;
            line-height: 35px;
        }

        .navbar-nav li .active {

            background-color: #666;
        }

        .navbar-default .navbar-left {
            padding-top: 10px;
        }


    </style>
{% endblock %}




<!--导航栏内容-->
{% block navbar %}
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                        data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="/">任务管理</a>
            </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
{#                    <li><a href="#"> </a></li>#}
{#                    <li><a href="/add/"><span class="glyphicon glyphicon-plus"></span>&nbsp;&nbsp;增加用户 <span#}
{#                            class="sr-only">(current)</span></a></li>#}
{#                    <li><a href="/delete/"><span class="glyphicon glyphicon-minus"></span>&nbsp;&nbsp;删除用户</a></li>#}
{#                    <li><a href="/list/"><span class="glyphicon glyphicon-hdd"></span>&nbsp;&nbsp;查看用户</a></li>#}
{#                    <li><a href="/query/username/"><span class="glyphicon glyphicon-hdd"></span>&nbsp;&nbsp;用户查询</a>#}
{#                    </li>#}
                </ul>

                <ul class="nav navbar-nav navbar-right">
                    <form class="navbar-form navbar-left" action="/query/username/" method="post">
                        <div class="form-group">
                            <input type="text" class="form-control" name='value' placeholder="Search">
                            <input type="submit" class="form-control" value="查询">
                        </div>
                        {#                    <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span>#}
                        {#                    </button>#}
                    </form>
                    {% block logout %}
                        <li><a href="/login/">登录</a></li>
                    {% endblock %}
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
{% endblock %}


{% block content %}


{% endblock %}

index.html

{% extends 'base.html' %}


{% block content %}
    <div class="col-md-6 col-md-offset-3">
        <table class="table table-bordered">
            <tr>
                <td>部门</td>
                <td>
                    {% for part in parts %}
                        <a href="#" class="btn btn-sm btn-danger" role="button"><span
                                class="glyphicon glyphicon-tags"></span> {{ part.name  }}</a>
                        &nbsp;&nbsp;&nbsp;
                    {% endfor %}
                </td>

            </tr>
            <tr>
                <td>任务类型</td>
                <td>
                    <a href="#" class="btn btn-sm btn-success" role="button"><span
                            class="glyphicon glyphicon-remove"></span> 已完成</a>
                    &nbsp;&nbsp;&nbsp;
                    <button type="button" class="btn btn-sm btn-info"><span
                            class="glyphicon glyphicon-ok"></span> 未完成
                    </button>

                </td>

            </tr>
        </table>


        <h3>紧急任务</h3>

        <span>注意: 登录后进行操作</span>
        <br/>
        <table class="table table-bordered">
            <thead>
            <th>编号</th>
            <th>任务内容</th>
            <th>创建时间</th>
            <th>状态</th>
            <th>所属部门</th>
            <th>删除</th>
            </thead>
            {% for todo in untodos.items %}

                <tr>
                    <td>{{ todo.id }}</td>
                    <td>{{ todo.name }}</td>
                    <td>{{ todo.add_time }}</td>
                    <td>
                        {#      有按钮 :
                                如果状态为True: 则返回完成的按钮;
                            #}
                        {% if todo.status %}
                            <a href="{{ url_for('undone', todo_id=todo.id) }}" class="btn  btn-success"
                               role="button">已完成</a>
                        {% else %}
                            {#      {{ url_for('done', todo_id=todo.id) }} ======== '/done/1/'                      #}

                            <a href="{{ url_for('done', todo_id=todo.id) }}" class="btn  btn-warning"
                               role="button">未完成</a>
                        {% endif %}


                    </td>
                    <td>{{ todo.department.name }}</td>
                    <td>

                        <a class="btn btn-danger"
                           href="{{ url_for('delete', todo_id=todo.id, page=untodos.page) }}"
                           role="button">删除</a>


                    </td>
                </tr>
            {% endfor %}
        </table>

        {#        分页信息#}

        {% from 'macro/page.html' import paginate %}


        {{ paginate('list', untodos) }}


    </div>
{% endblock %}

list.html

{% extends 'base.html' %}
{% block title %}用户显示{% endblock %}
{% block logout %}   <li><a href="/logout/">登出</a></li>{% endblock %}
{% block content %}
    <div class="col-md-8 col-md-offset-2">
    <br/>
    <br/>
    <br/>
    <br/>
    <br/>

        <form class="form-horizontal" action="{{ url_for('add') }}" method="post">
            <div class="form-group">
                {#  添加框                   #}
                <div class="col-sm-9">
                    <input type="text" class="form-control" placeholder="请添加任务" required="required" name="todo_name">
                </div>
                {#    选择框              #}
                <div class="col-sm-2">
                    {#

                            select标签的name属性是为了将用户选择的数据传递给后台;作为key值;
                            option的value属性, 是传递用户选择的值;

                        #}
                    <select class="form-control" name="part">
                        {% for part in parts  %}
                                <option value="{{ part.id }}">{{ part.name }}</option>
                        {% endfor  %}

                    </select>
                </div>

                {#   添加的按钮              #}
                <div class="col-sm-1">
                    <input type="submit" class="btn btn-success" value="添加任务">
                </div>
            </div>

        </form>


        {#        <br/>#}
        {#        <br/>#}
        {#        <br/>#}
        {#        <form class="form-horizontal" method="post" action="/add/">#}
        {#            <div class="form-group">#}
        {#                <div class="col-md-9">#}
        {#                    <input type="text" class="form-control" required="required" name="content" placeholder="添加任务">#}
        {#                </div>#}
        {##}
        {#                <div class="col-md-2">#}
        {##}
        {#                    <select class="form-control" name="part">#}
        {#                        {% for part in parts %}#}
        {#                            <option value="{{ part.id }}">{{ part.name }}</option>#}
        {#                        {% endfor %}#}
        {##}
        {#                    </select>#}
        {##}
        {#                </div>#}
        {#                <button type="submit" class="btn btn-default col-md-1 btn-success ">添加</button>#}
        {#            </div>#}
        {##}
        {#        </form>#}


        <h1>任务显示</h1>
        <table class="table table-bordered">
            <thead>
            <th>编号</th>
            <th>任务内容</th>
            <th>创建时间</th>
            <th>状态</th>
            <th>所属部门</th>
            <th>删除</th>
            </thead>
            {% for todo in todos.items %}

                <tr>
                    <td>{{ todo.id }}</td>
                    <td>{{ todo.name }}</td>
                    <td>{{ todo.add_time }}</td>
                    <td>
                        {#      有按钮 :
                                如果状态为True: 则返回完成的按钮;
                            #}
                        {% if todo.status %}
                            <a href="{{ url_for('undone', todo_id=todo.id) }}" class="btn  btn-success"
                               role="button">已完成</a>
                        {% else %}
                            {#      {{ url_for('done', todo_id=todo.id) }} ======== '/done/1/'                      #}

                            <a href="{{ url_for('done', todo_id=todo.id) }}" class="btn  btn-warning"
                               role="button">未完成</a>
                        {% endif %}


                    </td>
                    <td>{{ todo.department.name }}</td>
                    <td>

                        <a class="btn btn-danger"
                           href="{{ url_for('delete', todo_id=todo.id, page=todos.page) }}"
                           role="button">删除</a>


                    </td>
                </tr>
            {% endfor %}
        </table>

        {#        分页信息#}

        {% from 'macro/page.html' import paginate %}


        {{ paginate('list', todos) }}


    </div>

{% endblock %}

login.html

{% extends 'base.html' %}
{% block title %}用户登录{% endblock %}



{% block content %}
    <div class="col-md-8 col-md-offset-2">


        <form class="form-horizontal" action="{{ url_for('login') }}" method="post">
            <h2>用户登录</h2>

           {%  for error in get_flashed_messages()  %}

            <p style=" color:red;">{{ error }}</p>

            {% endfor %}
            <div class="form-group">
                <label class="col-sm-2 control-label">用户名</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" name="name" placeholder="请输入用户名">
                </div>
            </div>
            <div class="form-group">
                <label class="col-sm-2 control-label">密码</label>
                <div class="col-sm-10">
                    <input type="password" class="form-control" name="pwd" placeholder="请输入密码">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="checkbox">
                        <label>
                            <input type="checkbox"> Remember me
                        </label>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <button type="submit" class="btn btn-default">登录</button>
                </div>
            </div>
        </form>

    </div>


{% endblock %}

 上面的所有的页面都继承与base.html页面,而base.html就是继承于'bootstrap/base.html',

'bootstrap/base.html'就是官方为我们提供的模板,这个模板中有帮我们“挖的坑“我们只需要将其填补上就可以比如

{% extends 'bootstrap/base.html' %}  继承于哪里

{% block title %} 首页 {% endblock %}   浏览器上的头部信息

{% block content %}...... {% endblock %} 正文部分的样式

我们也可以自己刨坑和填坑前面的文章中我们也提到过相关内容:

模板继承语法:
    1. 如何继承某个模板?
            {% extends "模板名称" %}
    
    
    2. 如何挖坑和填坑?
    挖坑: 
        {% block 名称 %}
        
            默认值
        
        {% endblock %}
        
        
    填坑: 
        {% block 名称 %}
        
        {% endblock %}
        
    
    3. 如何调用/继承被替代的模板?
        挖坑: 
        {% block 名称 %}
        
            默认值
        
        {% endblock %}
        
        
    填坑: 
        {% block 名称 %}
            #如何继承挖坑时的默认值?
            {{ super() }}
            
            # 后面写新加的方法.
            ........   
        {% endblock %}
        

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值