在我问之前,我会承认这是一个奇怪的问题。 我想知道是否可以使用原始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,通常这没有任何意义,但在我们的情况下确实如此。
这可能吗?
答案 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)
执行此类对象
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 methods和UserMixin
类提供所有这些实例的实例,而您只需要提供id
属性即可。验证用户ID和处理登录的方式由您决定。