Flask / SQL Alchemy原始查询代替类方法

时间:2018-10-23 11:43:06

标签: python flask sqlalchemy flask-sqlalchemy

在我问之前,我会承认这是一个奇怪的问题。 我想知道是否可以使用原始SQL复制Flask / SQL Alchemy类方法,而不是使用方法本身?

长话短说,我和我的队友正在上数据库设计课程,我们现在处于实现阶段,正在基于数据库架构设计对应用程序进行编码。我们希望保持简单,因此我们选择在Python中使用Flask。我们正在关注Flask Mega Tutorial,这是一个入门指南,解释了如何像我们正在做的那样构建基本站点。我们刚刚完成了第5章:用户登录,并且还在继续。

app/routes.py脚本中,本教程执行了一些操作以获取用户信息。这是示例应用程序的示例登录路线:

from flask_login import current_user, login_user
from app.models import User

# ...

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        return redirect(url_for('index'))
    return render_template('login.html', title='Sign In', form=form)

我感兴趣的是行user = User.query.filter_by(username=form.username.data).first()。基本上,该行实例化了User类,它是SQL Alchemy的数据库模型,并从电子邮件地址中获取有关用户的信息。他们进入了。调用这些方法将生成如下的SQL语句:

SELECT `User`.`userID` AS `User_userID`,
       `User`.user_email AS `User_user_email`,
       `User`.user_first_name AS `User_user_first_name`,
       `User`.user_last_name AS `User_user_last_name`,
       `User`.user_password AS `User_user_password`
FROM `User`
WHERE `User`.user_email = 'test@test.com'
LIMIT 1

还有有关user变量本身的一些信息:

>>> print(type(user))
<class 'myapp.models.User'>

>>> pp(user.__dict__)
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7f5a026a8438>,
 'userID': 1,
 'user_email': 'test@test.com',
 'user_first_name': 'SomeFirstName',
 'user_last_name': 'SomeLastName',
 'user_password': 'somepassword'}

在我们的项目中,我们不应该像在实例化的query.filter_by(username=form.username.data).first()类上调用User那样使用生成的SQL语句;我们应该自己编写原始SQL,通常这没有任何意义,但在我们的情况下确实如此。

这可能吗?

1 个答案:

答案 0 :(得分:2)

首先:与您的教授或TA对话。通过不对如此重要的事情进行假设,您将节省时间。如果该类的目标是考虑数据库架构设计,那么使用ORM可能很好。如果您需要编写自己的SQL,则请勿使用ORM开头

要回答技术问题:是的,您可以纯粹将SQLAlchemy用作数据库连接池,可以将其用作从Python对象创建有效SQL语句的工具,还可以用作完整的ORM,以及之间的每个等级。

例如,使用ORM层,您可以告诉Query对象不为您生成SQL,而是接受文本。 SQLAlchemy ORM教程在Using Textual SQL section下对此进行了介绍:

  

通过在text()构造中指定其用法,可以灵活地在查询中使用文字字符串。

对于您的登录示例,仅查询密码如下所示:

user = User.query.from_statement(
    db.text("SELECT * FROM User where user_email=:email LIMIT 1")
).params(email=form.username.data).first()

if user is None or user.check_password(form.password.data):
    # ...

您还可以阅读SQL Expression API(SQLAlchemy库的 core API)以使用Python代码构建查询; Python对象与结果查询之间的关系几乎是一对一的;通常,您通常会先生成表的模型,然后从那里构建SQL,或者可以使用文字:

s = select([
    literal_column("User.password", String)
]).where(
    literal_column("User.user_email") == form.username.data
).select_from(table("User")).limit(1)

并使用Session.execute() method

执行此类对象
results = db.session.execute(s)

如果您想真正射击自己,也可以直接将字符串传递给db.session.execute()

results = db.session.execute("""
    SELECT user_password FROM User where user_email=:email LIMIT 1
    """, {'email': form.username.data})

只知道Session.execute()返回一个ResultProxy() instance,而不是ORM实例。

另外,请知道Flask-Login 不需要您使用ORM 。作为project documentation states

  

但是,它没有:

     
      
  • 在您身上施加特定的数据库或其他存储方法。 您完全负责用户的加载方式。
  •   

因此,您只需创建一个subclass of UserMixin即可在每次查询数据库时手动实例化。

class User(flask_login.UserMixin):
    def __init__(self, id):    # add more attributes as needed
        self.id = id

@login_manager.user_loader
def load_user(user_id):
    # perhaps query the database to confirm the user id exists and
    # load more info, but all you basically need is:
    return User(user_id)

# on login, use

user = User(id_of_user_just_logged_in)
login_user(user)

就是这样。该扩展程序希望查看implement 4 basic methodsUserMixin类提供所有这些实例的实例,而您只需要提供id属性即可。验证用户ID和处理登录的方式由您决定。