python-Flask框架进阶

Flask-SQL Alchemy

Flask-SQL Alchemy 是一个为Flask应用提供SQL Alchemy 支持的扩展库。SQL Alchemy 是Python中的一种ORM(对象关系映射)工具,可以将类映射到数据库表。

在 Flask 中使用 MySQL 数据库,可以使用 SQL Alchemy 和 Alembic 这两个扩展来创建模型和执行数据库迁移。

安装扩展:

pip install flask flask-sqlalchemy flask-migrate

配置 Flask 应用:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/database'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#设置为 True 时,Flask SQLAlchemy 会自动追踪对象的修改,并在需要时自动更新数据库。这种自动追踪功能在一些情况下可能会有性能问题,因为它需要通过比较对象状态来确定对象是否被修改。

db = SQLAlchemy(app)

# 定义数据模型

migrate = Migrate(app, db)

在上述代码中,你需要将 'username''password''database' 替换为你的 MySQL 数据库的实际连接信息。

创建模型:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return '<User {}>'.format(self.username)

在这个示例中,我们创建了一个名为 User 的模型,包含了 id、username 和 email 字段。

常用字段类型

db.String(length):用于存储字符串,length参数指定最大长度,例如 db.String(80) 表示最大长度为80个字符的字符串。
db.Integer:用于存储整数。
db.Float:用于存储浮点数。
db.Boolean:用于存储布尔值,表示True或False。
db.Date:用于存储日期。
db.DateTime:用于存储日期和时间。
db.Time:用于存储时间。
db.Text:用于存储大文本数据,例如长文章或备注。

常用列属性

unique :唯一  
nullable :可以为空
primary_key:指定列为主键。
default:设置列的默认值。
autoincrement:指定列为自增长列。

执行数据库迁移操作:

  • 首次迁移:

    # Error: No such command 'db'
    # 解决办法 set FLASK_APP=realproject(真实环境配置的项目名:例如app.py)
    flask db init
    
    flask db migrate
    flask db upgrade
    
    
  • 后续迁移:

    flask db migrate
    flask db upgrade
    
    

这些命令会创建一个用于存储迁移脚本的 migrations 文件夹,并在 MySQL 数据库中创建相应的表。

这样,你就可以使用 db 对象来执行数据库操作,例如插入、查询等。

基础的查找、更新、删除、过滤以及多表查询等常规操作,可以使用 SQL Alchemy 提供的查询API和SQL Alchemy ORM的功能。

查找数据:

# 查找单个对象
user = User.query.filter_by(username='john').first()

# 查找多个对象
users = User.query.filter_by(is_active=True).all()

# 根据主键查找对象
user = User.query.get(1)

# 使用过滤器和逻辑操作符查找对象
users = User.query.filter(User.age > 18, User.age < 30).all()

更新数据:

# 更新单个对象的属性
user = User.query.get(1)
user.username = 'new_username'
db.session.commit()

# 使用过滤器更新多个对象的属性
User.query.filter_by(is_active=True).update({'is_active': False})
db.session.commit()

删除数据:

# 删除单个对象
user = User.query.get(1)
db.session.delete(user)
db.session.commit()

# 根据过滤器删除多个对象
User.query.filter_by(is_active=False).delete()
db.session.commit()

过滤查询结果:

# 返回指定字段
users = User.query.with_entities(User.username, User.email).all()

# 按字段排序
users = User.query.order_by(User.username.asc()).all()

# 使用逻辑操作符过滤数据
users = User.query.filter(User.age > 18, User.age < 30).all()
from sqlalchemy import and_, or_, not_

# 查询满足多个条件的记录
result = db.session.query(Table).filter(and_(condition1, condition2)).all()

# 查询满足任一条件的记录
result = db.session.query(Table).filter(or_(condition1, condition2)).all()

# 查询不满足条件的记录
result = db.session.query(Table).filter(not_(condition)).all()

# 使用 IN 操作符
users = User.query.filter(User.username.in_(['john', 'jane'])).all()

多表查询:

使用join

result = db.session.query(Table1, Table2).join(Table2, Table1.table2_id==Table2.id).all()

使用relationship定义模型关系

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(120), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    user = db.relationship('User', backref='posts')

user = User.query.filter_by(username='john').first()
posts = user.posts  # 获取用户的所有帖子  posts是由backref='posts'决定的 

post = Post.query.filter_by(title='example').first()
author = post.user  # 获取帖子的作者

user = db.relationship('User', backref='posts') 是 SQL Alchemy 中定义模型之间关系的一种方式。这行代码表示在当前模型(假设是"Post"模型)中创建了一个名为 “user” 的关系字段,该字段可以用于访问该模型与 “User” 模型之间的关系。

backref='posts' 参数定义了反向引用,它会在 “User” 模型中创建一个名为 “posts” 的字段,通过该字段可以访问与该用户相关的所有帖子。

Flask-login

Flask-Login 可以进行登录、注册和注销登录。

首先,你需要安装 Flask-Login 扩展。可以使用以下命令来安装它:

pip install flask-login

对一个使用flask-login的应用最重要的一部分是login manager类。

login_manager = LoginManager()
login_manager.init_app(app)

它必须提供一个user_loader回调。

@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)

接受一个用户的ID作为参数,并且返回响应的用户对象。如果ID无效的话,他应该返回None。

参数user_loader标记的函数虽然在程序中没有显示调用,在用户登录时会自动获取,用于后续账号的管理

用户类

要简便的实现用户类,可以从UserMixin继承,他提供了对所有这些方法的默认实现。

user = UserMixin()
user.id = username
login_user(user) # 记录登录信息

你用来标识用户的类需要实现这些属性和方法:

四个方法:

is_authenticated()`、`is_active()`、`is_anonymous()`、`get_id()

  • is_authenticated() 当用户通过验证时,也即提供有效证明是返回true。
  • is_active() 可以直接返回true。
  • is_anonymous() 如果是匿名用户,返回true。真实用户返回False。
  • get_id() 返回一个能唯一识别用户的,并能用于user_loader回调中加载用户的Unicode ID。

需要用户登入的视图可以用login_required装饰器来装饰。

login_manager.login_view = 'login'  # 设置您的登录页面的路由名称

@app.route('/settings')
@login_required
def settings():
    pass

当用户需要登出时,使用logout_user方法。

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(somewhere)

会话产生的任何cookie都会被清理干净。此时再访问@login_required标注的函数

接下来,以下是一个简单的示例代码,演示了如何使用 Flask-Login 进行用户登录、注册和注销登录的功能:

from flask import Flask, render_template, request, redirect, url_for
from flask_login import LoginManager, UserMixin, login_user, current_user, logout_user

app = Flask(__name__)
app.secret_key = 'secret_key'

login_manager = LoginManager()
login_manager.init_app(app)

# 模拟用户数据库
users = {'admin': {'password': 'admin123'}}

class User(UserMixin):
    pass

@login_manager.user_loader
def user_loader(username):
    if username not in users:
        return

    user = User()
    user.id = username
    return user

@app.route('/')
def index():
    return '欢迎访问首页'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        if username in users and users[username]['password'] == password:
            user = User()
            user.id = username
            login_user(user)
            return redirect(url_for('index'))

        return '无效的用户名或密码'

    return render_template('login.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        if username in users:
            return '用户名已存在'

        users[username] = {'password': password}
        return '注册成功'

    return render_template('register.html')

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run()

这只是一个基本示例,你可以根据实际需求进行修改和扩展。你还需要创建相应的 HTML 模板,例如登录表单的模板 login.html 和注册表单的模板 register.html 。在模板中,你可以使用表单元素和相应的请求方法来获取用户输入的用户名和密码。

当用户成功登录后,会话将被存储在客户端,并且 Flask-Login 会为当前用户提供 current_user 对象,你可以在视图函数中使用它来判断用户是否已经登录。

在注销登录函数中,logout_user() 函数将会注销当前用户的登录信息。

记得在实际使用时,你需要将 your_secret_key 替换为一个随机的密钥字符串,用于保护用户会话。

页面实战总结

taskkill /F /PID 17824  #杀死进程ID  17824进程ID
netstat -ano | findstr :5000 查找对应端口号

创建数据表

from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:000000@localhost/demo'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置为 True 时,Flask SQLAlchemy 会自动追踪对象的修改,并在需要时自动更新数据库。这种自动追踪功能在一些情况下可能会有性能问题,因为它需要通过比较对象状态来确定对象是否被修改。

db = SQLAlchemy()
db.init_app(app)
migrate = Migrate(app, db)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), unique=False, nullable=False)
    display_name = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self): # 用于查询对象显示
        return f'<User {self.username}>'

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    price = db.Column(db.Integer, unique=False, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return f'<Book {self.name}>'

migrate = Migrate(app, db)

记得迁移数据库

flask db init  flask db migrate  flask db upgrade

创建登录注册表单

将表单数据创建在forms.py文件中

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, EqualTo, Length

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=3, max=20)])
    display_name = StringField('display_name', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])

class LoginForm(FlaskForm):
    username = StringField('UserName', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    # Email = StringField('Email', validators=[DataRequired(),Email()])


  • DataRequired():这是一个必需验证器,用于确保字段不能为空。如果输入为空,将显示一条错误消息。
  • Email():这是一个验证电子邮件格式的验证器。它检查输入是否符合电子邮件的格式规范。
  • Length(min=3, max=20):这是一个长度验证器,用于检查输入的字符数是否在指定的范围内。在这种情况下,字段的长度必须介于3和20之间。
  • EqualTo(‘password’):这是一个验证器,用于确保两个字段的值相等。在这种情况下,confirm_password字段的值必须与password字段的值相等。

创建登录注册视图

from flask import Flask, render_template, redirect, flash
from forms import RegistrationForm, LoginForm

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret-key'

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 在这里处理注册逻辑,比如保存用户信息到数据库
        flash('Account created successfully! You can now log in.', 'success')
        return redirect('/login')
    return render_template('register.html', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        # 在这里处理登录逻辑,比如验证用户名和密码
        flash('Logged in successfully!', 'success')
        return redirect('/')
    return render_template('login.html', form=form)

@app.route('/logout')
def logout():
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run()

编写登录注册视图

from flask import Flask, render_template, redirect, flash, url_for
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

from forms import RegistrationForm, LoginForm

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:000000@localhost/demo'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy()
db.init_app(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), unique=False, nullable=False)
    display_name = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    price = db.Column(db.Integer, unique=False, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return f'<Book {self.name}>'

migrate = Migrate(app, db)

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 在这里处理注册逻辑,比如保存用户信息到数据库

        user = User(username=form.username.data, password=form.password.data, display_name=form.display_name.data)
        db.session.add(user)
        db.session.commit()

        return redirect('/login')
    return render_template('c_register.html', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        # 查询数据库以验证用户名和密码
        username = form.username.data
        password = form.password.data
        print(User.query.filter_by(username=username))
        user = User.query.filter_by(username=username).first()
        if user and user.password == password:
            flash('Logged in successfully!', 'success')
            return redirect('/')
        # 在这里处理登录逻辑,比如验证用户名和密码
        # flash('Logged in successfully!', 'success')

    return render_template('c_login.html', form=form)

@app.route('/', methods=['GET', 'POST'])
def home():
    return '主页'

@app.route('/logout')
def logout():
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run()


创建模板

Login模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>Login</h2>
<form method="POST" action="{{ url_for('login') }}">
{{ form.csrf_token }}
<div class="form-group">
  <label for="{{ form.username.id }}">{{ form.username.label }}</label>
  {{ form.username(class="form-control") }}
  {% for error in form.username.errors %}
    <span class="text-danger">{{ error }}</span>
  {% endfor %}
</div>
<div class="form-group">
  <label for="{{ form.password.id }}">{{ form.password.label }}</label>
  {{ form.password(class="form-control") }}
  {% for error in form.password.errors %}
    <span class="text-danger">{{ error }}</span>
  {% endfor %}
</div>
<input type="submit" value="Login">
</form>

</body>
</html>

Register模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <h2>Register</h2>
  <form method="POST" action="{{ url_for('register') }}">
    {{ form.csrf_token }}
    <div class="form-group">
      {{ form.username.label }} {{ form.username }}
      {% for error in form.username.errors %}
        <span class="text-danger">{{ error }}</span>
      {% endfor %}
    </div>
    <div class="form-group">
      {{ form.password.label }} {{ form.password }}
      {% for error in form.password.errors %}
        <span class="text-danger">{{ error }}</span>
      {% endfor %}
    </div>
      <div class="form-group">
      {{ form.confirm_password.label }} {{ form.confirm_password }}
      {% for error in form.confirm_password.errors %}
        <span class="text-danger">{{ error }}</span>
      {% endfor %}
    </div>
    <div class="form-group">
      {{ form.display_name.label }} {{ form.display_name }}
      {% for error in form.display_name.errors %}
        <span class="text-danger">{{ error }}</span>
      {% endfor %}
    </div>
    <input type="submit" value="Register">
  </form>
</body>
</html>

编写登录信息记录

from flask import Flask, render_template, redirect, flash, url_for
from flask_login import LoginManager, logout_user, login_required, UserMixin, login_user
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy

from forms import RegistrationForm, LoginForm

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:000000@localhost/demo'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
login_manager = LoginManager()
login_manager.init_app(app)
db = SQLAlchemy()
db.init_app(app)
login_manager.login_view = 'login'

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), unique=False, nullable=False)
    display_name = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    price = db.Column(db.Integer, unique=False, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return f'<Book {self.name}>'

migrate = Migrate(app, db)

@login_manager.user_loader
def load_user(username):
    user = User.query.filter_by(username=username)
    if user:
        user_mix = UserMixin()
        user_mix.id = username
        return user_mix

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, password=form.password.data, display_name=form.display_name.data)
        db.session.add(user)
        db.session.commit()

        return redirect('/login')
    return render_template('c_register.html', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        # 查询数据库以验证用户名和密码
        username = form.username.data
        password = form.password.data
        print(User.query.filter_by(username=username))
        user = User.query.filter_by(username=username).first()
        if user and user.password == password:
            user_mix = UserMixin()
            user_mix.id = username
            login_user(user_mix)

            flash('Logged in successfully!', 'success')
            return redirect('/')
        # 在这里处理登录逻辑,比如验证用户名和密码
        # flash('Logged in successfully!', 'success')

    return render_template('c_login.html', form=form)

@app.route('/', methods=['GET', 'POST'])
@login_required
def home():
    return '主页'

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

if __name__ == '__main__':
    app.run()

主页数据显示

@app.route('/', methods=['GET', 'POST'])
@login_required
def home():
    user = User.query.filter_by(username=current_user.id).first()
    books = user.books
    Books = Book.query.filter_by(name='python').first()
    c_user = Books.user
    return render_template('index.html', books=books, c_user=c_user)

---------------------------END---------------------------

题外话

当下这个大数据时代不掌握一门编程语言怎么跟的上时代呢?当下最火的编程语言Python前景一片光明!如果你也想跟上时代提升自己那么请看一下.

在这里插入图片描述

感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。


👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述

👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)

若有侵权,请联系删除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值