标签归档:flask-sqlalchemy

我如何知道是否可以禁用SQLALCHEMY_TRACK_MODIFICATIONS?

问题:我如何知道是否可以禁用SQLALCHEMY_TRACK_MODIFICATIONS?

每次我运行使用Flask-SQLAlchemy的应用程序时,都会收到以下警告,提示该SQLALCHEMY_TRACK_MODIFICATIONS选项将被禁用。

/home/david/.virtualenvs/flask-sqlalchemy/lib/python3.5/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
  warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')

我试图找出此选项的作用,但是Flask-SQLAlchemy文档尚不清楚该跟踪的用途。

SQLALCHEMY_TRACK_MODIFICATIONS

如果设置为True(默认值),Flask-SQLAlchemy将跟踪对象的修改并发出信号。这需要额外的内存,如果不需要,可以将其禁用。

如何确定我的项目是否需要,SQLALCHEMY_TRACK_MODIFICATIONS = True或者是否可以安全地禁用此功能并在服务器上节省内存?

Every time I run my app that uses Flask-SQLAlchemy I get the following warning that the SQLALCHEMY_TRACK_MODIFICATIONS option will be disabled.

/home/david/.virtualenvs/flask-sqlalchemy/lib/python3.5/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
  warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')

I tried to find out what this option does, but the Flask-SQLAlchemy documentation isn’t clear about what uses this tracking.

SQLALCHEMY_TRACK_MODIFICATIONS

If set to True (the default) Flask-SQLAlchemy will track modifications of objects and emit signals. This requires extra memory and can be disabled if not needed.

How do I find out if my project requires SQLALCHEMY_TRACK_MODIFICATIONS = True or if I can safely disable this feature and save memory on my server?


回答 0

您的应用程序很可能没有使用Flask-SQLAlchemy事件系统,因此可以安全地关闭它。您需要审核代码以进行验证-您正在寻找与models_committedbefore_models_committed挂钩的任何内容。如果确实发现您正在使用Flask-SQLAlchemy事件系统,则可能应该更新代码以使用SQLAlchemy的内置事件系统。

要关闭Flask-SQLAlchemy事件系统(并禁用警告),只需添加:

SQLALCHEMY_TRACK_MODIFICATIONS = False

更改为您的应用程序配置,直到更改默认设置为止(很有可能在Flask-SQLAlchemy v3中)。


背景-警告告诉您的是以下内容:

Flask-SQLAlchemy有自己的事件通知系统,该系统在SQLAlchemy之上分层。为此,它跟踪对SQLAlchemy会话的修改。这需要额外的资源,因此该选项SQLALCHEMY_TRACK_MODIFICATIONS允许您禁用修改跟踪系统。当前,该选项默认为True,但将来该默认值将更改为False,从而禁用事件系统。

据我了解,更改的理由有三点:

  1. 使用Flask-SQLAlchemy的事件系统的人并不多,但是大多数人没有意识到他们可以通过禁用它来节省系统资源。因此,更明智的默认设置是禁用它,想要它的人可以打开它。

  2. Flask-SQLAlchemy中的事件系统存在相当多的错误(请参阅下面提到的请求请求中与之相关的问题),需要为很少有人使用的功能进行额外的维护。

  3. 在v0.7中,SQLAlchemy本身添加了一个强大的事件系统,其中包括创建自定义事件的功能。理想情况下,Flask-SQLAlchemy事件系统除了创建一些自定义的SQLAlchemy事件挂钩和侦听器外,无所不用其事,然后让SQLAlchemy自己管理事件触发器。

您可以在有关拉动请求的讨论中看到更多信息,该请求开始触发此警告

Most likely your application doesn’t use the Flask-SQLAlchemy event system, so you’re probably safe to turn off. You’ll need to audit the code to verify–you’re looking for anything that hooks into models_committed or before_models_committed. If you do find that you’re using the Flask-SQLAlchemy event system, you probably should update the code to use SQLAlchemy’s built-in event system instead.

To turn off the Flask-SQLAlchemy event system (and disable the warning), just add:

SQLALCHEMY_TRACK_MODIFICATIONS = False

to your app config until the default is changed (most likely in Flask-SQLAlchemy v3).


Background–here’s what the warning is telling you:

Flask-SQLAlchemy has its own event notification system that gets layered on top of SQLAlchemy. To do this, it tracks modifications to the SQLAlchemy session. This takes extra resources, so the option SQLALCHEMY_TRACK_MODIFICATIONS allows you to disable the modification tracking system. Currently the option defaults to True, but in the future, that default will change to False, thereby disabling the event system.

As far as I understand, the rationale for the change is three-fold:

  1. Not many people use Flask-SQLAlchemy’s event system, but most people don’t realize they can save system resources by disabling it. So a saner default is to disable it and those who want it can turn it on.

  2. The event system in Flask-SQLAlchemy has been rather buggy (see issues linked to in the pull request mentioned below), requiring additional maintenance for a feature that few people use.

  3. In v0.7, SQLAlchemy itself added a powerful event system including the ability to create custom events. Ideally, the Flask-SQLAlchemy event system should do nothing more than create a few custom SQLAlchemy event hooks and listeners, and then let SQLAlchemy itself manage the event trigger.

You can see more in the discussion around the pull request that started triggering this warning.


回答 1

Jeff Widman的详细解释非常完美。

由于在完成此操作之前我曾进行过一些“复制粘贴”的操作,因此我想使下一个穿鞋的操作变得更容易。

在您的代码中,紧接在

app = Flask(__name__)

如果要启用轨道修改,只需添加:

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

否则,如果您使用此功能,则可能需要将值更改为False,以免浪费系统资源。由于您仍在显式设置配置,因此这仍然会使警告保持沉默。

这是具有False值的相同代码段:

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

感谢Jeff Widman提出的建议和详细信息。

Jeff Widman’s detailed explanation is simply perfect.

Since I had some copy’n’paste fights before getting this right I’d like to make it easier for the next one that will be in my shoes.

In your code, immediately after:

app = Flask(__name__)

If you want to enable track modifications simply add:

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

Otherwise, if you are not using this feature, you may want to change the value to False in order not to waste system resources. This will still silence the warning since you’re anyway explicitly setting the config.

Here’s the same snippet with False value:

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

Thanks to Jeff Widman for this added suggestion and details.


回答 2

上面的答案看起来不错。但是,我想在Flask-SQLAlchemy文档中指出这一行,因为SQLALCHEMY_TRACK_MODIFICATIONS = False在我的应用程序配置中设置后,我仍然收到这些警告。

在此页面上:http : //flask-sqlalchemy.pocoo.org/2.3/config/

Flask-SQLAlchemy存在以下配置值。Flask-SQLAlchemy从您的主要Flask配置中加载这些值,可以通过多种方式填充。请注意,其中一些不能在创建引擎后进行修改,因此请确保尽早进行配置,并且不要在运行时进行修改。

换句话说,app.config 创建Flask-SQLAlchemy数据库之前,请确保设置您的数据库。

例如,如果您将应用程序配置为set SQLALCHEMY_TRACK_MODIFICATIONS = False

from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

The above answers look good. However, I wanted to point out this line in the Flask-SQLAlchemy documentation because I was still getting these warnings after setting SQLALCHEMY_TRACK_MODIFICATIONS = False in my application config.

On this page: http://flask-sqlalchemy.pocoo.org/2.3/config/

The following configuration values exist for Flask-SQLAlchemy. Flask-SQLAlchemy loads these values from your main Flask config which can be populated in various ways. Note that some of those cannot be modified after the engine was created so make sure to configure as early as possible and to not modify them at runtime.

In other words, make sure to set up your app.config before creating your Flask-SQLAlchemy database.

For example, if you are configuring your application to set SQLALCHEMY_TRACK_MODIFICATIONS = False:

from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

如何更新SQLAlchemy行条目?

问题:如何更新SQLAlchemy行条目?

假设表有三列:usernamepasswordno_of_logins

当用户尝试登录时,将使用查询之类的内容检查条目

user = User.query.filter_by(username=form.username.data).first()

如果密码匹配,他将继续。我想做的是计算用户登录的次数。因此,无论他何时成功登录,我都希望增加该no_of_logins字段并将其存储回用户表。我不确定如何使用SqlAlchemy运行更新查询。

Assume table has three columns: username, password and no_of_logins.

When user tries to login, it’s checked for an entry with a query like

user = User.query.filter_by(username=form.username.data).first()

If password matches, he proceeds further. What I would like to do is count how many times the user logged in. Thus whenever he successfully logs in, I would like to increment the no_of_logins field and store it back to the user table. I’m not sure how to run update query with SqlAlchemy.


回答 0

user.no_of_logins += 1
session.commit()
user.no_of_logins += 1
session.commit()

回答 1

有几种UPDATE使用方法sqlalchemy

1) user.no_of_logins += 1
   session.commit()

2) session.query().\
       filter(User.username == form.username.data).\
       update({"no_of_logins": (User.no_of_logins +1)})
   session.commit()

3) conn = engine.connect()
   stmt = User.update().\
       values(no_of_logins=(User.no_of_logins + 1)).\
       where(User.username == form.username.data)
   conn.execute(stmt)

4) setattr(user, 'no_of_logins', user.no_of_logins+1)
   session.commit()

There are several ways to UPDATE using sqlalchemy

1) user.no_of_logins += 1
   session.commit()

2) session.query().\
       filter(User.username == form.username.data).\
       update({"no_of_logins": (User.no_of_logins +1)})
   session.commit()

3) conn = engine.connect()
   stmt = User.update().\
       values(no_of_logins=(User.no_of_logins + 1)).\
       where(User.username == form.username.data)
   conn.execute(stmt)

4) setattr(user, 'no_of_logins', user.no_of_logins+1)
   session.commit()

回答 2

举例说明澄清已接受答案的重要问题

直到我自己玩弄它之前,我都不了解它,所以我认为还会有其他人感到困惑。假设您正在id == 6no_of_logins == 30启动时的用户和用户一起工作。

# 1 (bad)
user.no_of_logins += 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 2 (bad)
user.no_of_logins = user.no_of_logins + 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 3 (bad)
setattr(user, 'no_of_logins', user.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 4 (ok)
user.no_of_logins = User.no_of_logins + 1
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 5 (ok)
setattr(user, 'no_of_logins', User.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

重点

通过引用类而不是实例,您可以使SQLAlchemy更加智能地进行增量,使其在数据库端而不是Python端发生。在数据库中执行此操作会更好,因为它不易受到数据损坏的影响(例如,两个客户端尝试同时进行增量操作,而最终结果仅是一次增量而不是两次增量)。我认为,如果您设置了锁或提高了隔离级别,则可以在Python中进行增量操作,但是如果不必这样做,为什么还要打扰呢?

注意事项

如果您要通过产生SQL之类的代码来增加两次SET no_of_logins = no_of_logins + 1,那么您将需要提交或至少刷新两次增加之间的增量,否则总共将只获得一个增量:

# 6 (bad)
user.no_of_logins = User.no_of_logins + 1
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 7 (ok)
user.no_of_logins = User.no_of_logins + 1
session.flush()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

Examples to clarify the important issue in accepted answer’s comments

I didn’t understand it until I played around with it myself, so I figured there would be others who were confused as well. Say you are working on the user whose id == 6 and whose no_of_logins == 30 when you start.

# 1 (bad)
user.no_of_logins += 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 2 (bad)
user.no_of_logins = user.no_of_logins + 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 3 (bad)
setattr(user, 'no_of_logins', user.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 4 (ok)
user.no_of_logins = User.no_of_logins + 1
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 5 (ok)
setattr(user, 'no_of_logins', User.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

The point

By referencing the class instead of the instance, you can get SQLAlchemy to be smarter about incrementing, getting it to happen on the database side instead of the Python side. Doing it within the database is better since it’s less vulnerable to data corruption (e.g. two clients attempt to increment at the same time with a net result of only one increment instead of two). I assume it’s possible to do the incrementing in Python if you set locks or bump up the isolation level, but why bother if you don’t have to?

A caveat

If you are going to increment twice via code that produces SQL like SET no_of_logins = no_of_logins + 1, then you will need to commit or at least flush in between increments, or else you will only get one increment in total:

# 6 (bad)
user.no_of_logins = User.no_of_logins + 1
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 7 (ok)
user.no_of_logins = User.no_of_logins + 1
session.flush()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

回答 3

借助user=User.query.filter_by(username=form.username.data).first()声明,您将获得指定用户的user变量。

现在,您可以像一样user.no_of_logins += 1更改新对象变量的值,并使用session的commit方法保存更改。

With the help of user=User.query.filter_by(username=form.username.data).first() statement you will get the specified user in user variable.

Now you can change the value of the new object variable like user.no_of_logins += 1 and save the changes with the session‘s commit method.


回答 4

我写了电报bot,并且在更新行时遇到了一些问题。如果您有模型,请使用此示例

def update_state(chat_id, state):
    try:
        value = Users.query.filter(Users.chat_id == str(chat_id)).first()
        value.state = str(state)
        db.session.flush()
        db.session.commit()
        #db.session.close()
    except:
        print('Error in def update_state')

为什么要使用db.session.flush()?这就是为什么>>> SQLAlchemy:flush()和commit()有什么区别?

I wrote telegram bot, and have some problem with update rows. Use this example, if you have Model

def update_state(chat_id, state):
    try:
        value = Users.query.filter(Users.chat_id == str(chat_id)).first()
        value.state = str(state)
        db.session.flush()
        db.session.commit()
        #db.session.close()
    except:
        print('Error in def update_state')

Why use db.session.flush()? That’s why >>> SQLAlchemy: What’s the difference between flush() and commit()?


如何在Flask-SQLAlchemy中按ID删除记录

问题:如何在Flask-SQLAlchemy中按ID删除记录

users在MySql数据库中有表。这个表有idname而且age领域。

如何删除某些记录id

现在,我使用以下代码:

user = User.query.get(id)
db.session.delete(user)
db.session.commit()

但是我不想在删除操作之前进行任何查询。有什么办法吗?我知道,我可以使用db.engine.execute("delete from users where id=..."),但是我想使用delete()方法。

I have users table in my MySql database. This table has id, name and age fields.

How can I delete some record by id?

Now I use the following code:

user = User.query.get(id)
db.session.delete(user)
db.session.commit()

But I don’t want to make any query before delete operation. Is there any way to do this? I know, I can use db.engine.execute("delete from users where id=..."), but I would like to use delete() method.


回答 0

你可以这样做,

User.query.filter_by(id=123).delete()

要么

User.query.filter(User.id == 123).delete()

确保作出commitdelete()生效。

You can do this,

User.query.filter_by(id=123).delete()

or

User.query.filter(User.id == 123).delete()

Make sure to commit for delete() to take effect.


回答 1

只想分享另一个选择:

# mark two objects to be deleted
session.delete(obj1)
session.delete(obj2)

# commit (or flush)
session.commit()

http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#deleting

在此示例中,以下代码可以正常工作:

obj = User.query.filter_by(id=123).one()
session.delete(obj)
session.commit()

Just want to share another option:

# mark two objects to be deleted
session.delete(obj1)
session.delete(obj2)

# commit (or flush)
session.commit()

http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#deleting

In this example, the following codes shall works fine:

obj = User.query.filter_by(id=123).one()
session.delete(obj)
session.commit()

回答 2

另一个可能的解决方案,特别是如果要批量删除

deleted_objects = User.__table__.delete().where(User.id.in_([1, 2, 3]))
session.execute(deleted_objects)
session.commit()

Another possible solution specially if you want batch delete

deleted_objects = User.__table__.delete().where(User.id.in_([1, 2, 3]))
session.execute(deleted_objects)
session.commit()

Flask SQLAlchemy查询,指定列名

问题:Flask SQLAlchemy查询,指定列名

如何使用模型在查询中指定所需的列(默认情况下会选择所有列)?我知道如何使用sqlalchmey会话:session.query(self.col1),但是如何使用模型呢?我做不到SomeModel.query()。有办法吗?

How do I specify the column that I want in my query using a model (it selects all columns by default)? I know how to do this with the sqlalchmey session: session.query(self.col1), but how do I do it with with models? I can’t do SomeModel.query(). Is there a way?


回答 0

您可以使用该with_entities()方法来限制要返回结果的列。(文件

result = SomeModel.query.with_entities(SomeModel.col1, SomeModel.col2)

根据您的要求,您可能还会发现递延有用。它们使您可以返回完整的对象,但可以限制导线上的列。

You can use the with_entities() method to restrict which columns you’d like to return in the result. (documentation)

result = SomeModel.query.with_entities(SomeModel.col1, SomeModel.col2)

Depending on your requirements, you may also find deferreds useful. They allow you to return the full object but restrict the columns that come over the wire.


回答 1

session.query().with_entities(SomeModel.col1)

是相同的

session.query(SomeModel.col1)

对于别名,我们可以使用.label()

session.query(SomeModel.col1.label('some alias name'))
session.query().with_entities(SomeModel.col1)

is the same as

session.query(SomeModel.col1)

for alias, we can use .label()

session.query(SomeModel.col1.label('some alias name'))

回答 2

您可以使用load_only函数:

from sqlalchemy.orm import load_only

fields = ['name', 'addr', 'phone', 'url']
companies = session.query(SomeModel).options(load_only(*fields)).all()

You can use load_only function:

from sqlalchemy.orm import load_only

fields = ['name', 'addr', 'phone', 'url']
companies = session.query(SomeModel).options(load_only(*fields)).all()

回答 3

您可以使用Model.query,因为Model(通常是它的基类,尤其是在使用声明性扩展的情况下)已分配Sesssion.query_property。在这种情况下,Model.query相当于Session.query(Model)

我不知道修改查询返回的列的方法(除非使用添加更多的方法add_columns())。
因此,最好的选择是使用Session.query(Model.col1, Model.col2, ...)(如Salil所示)。

You can use Model.query, because the Model (or usually its base class, especially in cases where declarative extension is used) is assigned Sesssion.query_property. In this case the Model.query is equivalent to Session.query(Model).

I am not aware of the way to modify the columns returned by the query (except by adding more using add_columns()).
So your best shot is to use the Session.query(Model.col1, Model.col2, ...) (as already shown by Salil).


回答 4

您可以使用Query.values,Query.values

session.query(SomeModel).values('id', 'user')

You can use Query.values, Query.values

session.query(SomeModel).values('id', 'user')


回答 5

这里的一个例子:

movies = Movie.query.filter(Movie.rating != 0).order_by(desc(Movie.rating)).all()

我在数据库中查询评级为<> 0的电影,然后首先按最高评级对它们进行评级。

在这里看看:在Flask-SQLAlchemy中选择,插入,删除

An example here:

movies = Movie.query.filter(Movie.rating != 0).order_by(desc(Movie.rating)).all()

I query the db for movies with rating <> 0, and then I order them by rating with the higest rating first.

Take a look here: Select, Insert, Delete in Flask-SQLAlchemy


Flask-SQLalchemy更新行的信息

问题:Flask-SQLalchemy更新行的信息

如何更新行的信息?

例如,我想更改ID为5的行的名称列。

How can I update a row’s information?

For example I’d like to alter the name column of the row that has the id 5.


回答 0

使用Flask-SQLAlchemy文档中显示教程来检索对象。拥有要更改的实体后,请更改实体本身。然后,db.session.commit()

例如:

admin = User.query.filter_by(username='admin').first()
admin.email = 'my_new_email@example.com'
db.session.commit()

user = User.query.get(5)
user.name = 'New Name'
db.session.commit()

Flask-SQLAlchemy基于SQLAlchemy,因此请务必同时查看SQLAlchemy文档

Retrieve an object using the tutorial shown in the Flask-SQLAlchemy documentation. Once you have the entity that you want to change, change the entity itself. Then, db.session.commit().

For example:

admin = User.query.filter_by(username='admin').first()
admin.email = 'my_new_email@example.com'
db.session.commit()

user = User.query.get(5)
user.name = 'New Name'
db.session.commit()

Flask-SQLAlchemy is based on SQLAlchemy, so be sure to check out the SQLAlchemy Docs as well.


回答 1

updateSQLAlchemy中的BaseQuery对象有一个方法,由返回filter_by

admin = User.query.filter_by(username='admin').update(dict(email='my_new_email@example.com')))
db.session.commit()

update当要更新的对象很多时,使用更改实体的优势就来了。

如果您想add_user授予所有admins 权限,

rows_changed = User.query.filter_by(role='admin').update(dict(permission='add_user'))
db.session.commit()

注意,filter_by使用关键字参数(仅使用一个=),而不是filter使用表达式。

There is a method update on BaseQuery object in SQLAlchemy, which is returned by filter_by.

admin = User.query.filter_by(username='admin').update(dict(email='my_new_email@example.com')))
db.session.commit()

The advantage of using update over changing the entity comes when there are many objects to be updated.

If you want to give add_user permission to all the admins,

rows_changed = User.query.filter_by(role='admin').update(dict(permission='add_user'))
db.session.commit()

Notice that filter_by takes keyword arguments (use only one =) as opposed to filter which takes an expression.


回答 2

如果您修改模型的腌制属性,这将不起作用。腌制的属性应被替换以触发更新:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from pprint import pprint

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqllite:////tmp/users.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    data = db.Column(db.PickleType())

    def __init__(self, name, data):
        self.name = name
        self.data = data

    def __repr__(self):
        return '<User %r>' % self.username

db.create_all()

# Create a user.
bob = User('Bob', {})
db.session.add(bob)
db.session.commit()

# Retrieve the row by its name.
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {}

# Modifying data is ignored.
bob.data['foo'] = 123
db.session.commit()
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {}

# Replacing data is respected.
bob.data = {'bar': 321}
db.session.commit()
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {'bar': 321}

# Modifying data is ignored.
bob.data['moo'] = 789
db.session.commit()
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {'bar': 321}

This does not work if you modify a pickled attribute of the model. Pickled attributes should be replaced in order to trigger updates:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from pprint import pprint

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqllite:////tmp/users.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    data = db.Column(db.PickleType())

    def __init__(self, name, data):
        self.name = name
        self.data = data

    def __repr__(self):
        return '<User %r>' % self.username

db.create_all()

# Create a user.
bob = User('Bob', {})
db.session.add(bob)
db.session.commit()

# Retrieve the row by its name.
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {}

# Modifying data is ignored.
bob.data['foo'] = 123
db.session.commit()
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {}

# Replacing data is respected.
bob.data = {'bar': 321}
db.session.commit()
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {'bar': 321}

# Modifying data is ignored.
bob.data['moo'] = 789
db.session.commit()
bob = User.query.filter_by(name='Bob').first()
pprint(bob.data)  # {'bar': 321}

回答 3

仅分配值并提交它们将适用于除JSON和Pickled属性以外的所有数据类型。由于上面已经解释了腌制类型,因此我将记下更新JSON的方法略有不同但很简单。

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    data = db.Column(db.JSON)

def __init__(self, name, data):
    self.name = name
    self.data = data

假设模型如上。

user = User("Jon Dove", {"country":"Sri Lanka"})
db.session.add(user)
db.session.flush()
db.session.commit()

这会将用户与数据{“ country”:“ Sri Lanka”}一起添加到MySQL数据库中

修改数据将被忽略。我的无效代码如下。

user = User.query().filter(User.name=='Jon Dove')
data = user.data
data["province"] = "south"
user.data = data
db.session.merge(user)
db.session.flush()
db.session.commit()

与其完成将JSON复制到新字典(而不是像上面那样将其分配给新变量)的繁琐工作,我应该找到了一种简单的方法来完成该工作。有一种方法可以标记JSON已更改的系统。

以下是工作代码。

from sqlalchemy.orm.attributes import flag_modified
user = User.query().filter(User.name=='Jon Dove')
data = user.data
data["province"] = "south"
user.data = data
flag_modified(user, "data")
db.session.merge(user)
db.session.flush()
db.session.commit()

这就像一个魅力。这里还建议了另一种方法 希望对我有帮助。

Just assigning the value and committing them will work for all the data types but JSON and Pickled attributes. Since pickled type is explained above I’ll note down a slightly different but easy way to update JSONs.

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True)
    data = db.Column(db.JSON)

def __init__(self, name, data):
    self.name = name
    self.data = data

Let’s say the model is like above.

user = User("Jon Dove", {"country":"Sri Lanka"})
db.session.add(user)
db.session.flush()
db.session.commit()

This will add the user into the MySQL database with data {“country”:”Sri Lanka”}

Modifying data will be ignored. My code that didn’t work is as follows.

user = User.query().filter(User.name=='Jon Dove')
data = user.data
data["province"] = "south"
user.data = data
db.session.merge(user)
db.session.flush()
db.session.commit()

Instead of going through the painful work of copying the JSON to a new dict (not assigning it to a new variable as above), which should have worked I found a simple way to do that. There is a way to flag the system that JSONs have changed.

Following is the working code.

from sqlalchemy.orm.attributes import flag_modified
user = User.query().filter(User.name=='Jon Dove')
data = user.data
data["province"] = "south"
user.data = data
flag_modified(user, "data")
db.session.merge(user)
db.session.flush()
db.session.commit()

This worked like a charm. There is another method proposed along with this method here Hope I’ve helped some one.


Flask-SQLAlchemy导入/上下文问题

问题:Flask-SQLAlchemy导入/上下文问题

我想构建我的Flask应用,例如:

./site.py
./apps/members/__init__.py
./apps/members/models.py

apps.members 是烧瓶蓝图。

现在,为了创建模型类,我需要拥有该应用程序,例如:

# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(current_app)

class Member(db.Model):
    # fields here
    pass

但是,如果我尝试将该模型导入到我的Blueprint应用程序中,则会感到恐惧RuntimeError: working outside of request context。我如何在这里正确持有我的应用程序?相对导入可能有效,但它们很丑陋,并且有自己的上下文问题,例如:

from ...site import app

# ValueError: Attempted relative import beyond toplevel package

I want to structure my Flask app something like:

./site.py
./apps/members/__init__.py
./apps/members/models.py

apps.members is a Flask Blueprint.

Now, in order to create the model classes I need to have a hold of the app, something like:

# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy

db = SQLAlchemy(current_app)

class Member(db.Model):
    # fields here
    pass

But if I try and import that model into my Blueprint app, I get the dreaded RuntimeError: working outside of request context. How can I get a hold of my app correctly here? Relative imports might work but they’re pretty ugly and have their own context issues, e.g:

from ...site import app

# ValueError: Attempted relative import beyond toplevel package

回答 0

flask_sqlalchemy模块没有要与应用程序马上初始化-你可以这样做,而不是:

# apps.members.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Member(db.Model):
    # fields here
    pass

然后在应用程序设置中,您可以调用init_app

# apps.application.py
from flask import Flask
from apps.members.models import db

app = Flask(__name__)
# later on
db.init_app(app)

这样可以避免周期性导入。

这种模式并没有必要在你把你所有的车型在一个文件中。只需将db变量导入每个模型模块即可。

# apps.shared.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# apps.members.models
from apps.shared.models import db

class Member(db.Model):
    # TODO: Implement this.
    pass

# apps.reporting.members
from flask import render_template
from apps.members.models import Member

def report_on_members():
    # TODO: Actually use arguments
    members = Member.filter(1==1).all()
    return render_template("report.html", members=members)

# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members

reporting = Blueprint("reporting", __name__)

reporting.route("/member-report", methods=["GET","POST"])(report_on_members)

# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting

app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)

注意:这是一些功能的草图 -显然,您可以做很多事来简化开发工作(使用create_app模式,在某些文件夹中自动注册蓝图等)。

The flask_sqlalchemy module does not have to be initialized with the app right away – you can do this instead:

# apps.members.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Member(db.Model):
    # fields here
    pass

And then in your application setup you can call init_app:

# apps.application.py
from flask import Flask
from apps.members.models import db

app = Flask(__name__)
# later on
db.init_app(app)

This way you can avoid cyclical imports.

This pattern does not necessitate the you place all of your models in one file. Simply import the db variable into each of your model modules.

Example

# apps.shared.models
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

# apps.members.models
from apps.shared.models import db

class Member(db.Model):
    # TODO: Implement this.
    pass

# apps.reporting.members
from flask import render_template
from apps.members.models import Member

def report_on_members():
    # TODO: Actually use arguments
    members = Member.filter(1==1).all()
    return render_template("report.html", members=members)

# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members

reporting = Blueprint("reporting", __name__)

reporting.route("/member-report", methods=["GET","POST"])(report_on_members)

# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting

app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)

Note: this is a sketch of some of the power this gives you – there is obviously quite a bit more that you can do to make development even easier (using a create_app pattern, auto-registering blueprints in certain folders, etc.)


回答 1

原来app.pyhttps://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/

...

app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

class Computer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

# Create the database tables.
db.create_all()

...

# start the flask loop
app.run()

我只是将一个app.py拆分为app.py和model.py而不使用Blueprint。在这种情况下,以上答案无效。需要行代码才能工作。

之前

db.init_app(app)

之后

db.app = app
db.init_app(app)

并且,以下链接非常有用。

http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/

an original app.py: https://flask-sqlalchemy.palletsprojects.com/en/2.x/quickstart/

...

app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

class Computer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
...

# Create the database tables.
db.create_all()

...

# start the flask loop
app.run()

I just splitted one app.py to app.py and model.py without using Blueprint. In that case, the above answer dosen’t work. A line code is needed to work.

before:

db.init_app(app)

after:

db.app = app
db.init_app(app)

And, the following link is very useful.

http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/


Flask-SQLAlchemy如何删除单个表中的所有行

问题:Flask-SQLAlchemy如何删除单个表中的所有行

如何使用Flask-SQLAlchemy删除单个表中的所有行?

寻找这样的事情:

>>> users = models.User.query.all()
>>> models.db.session.delete(users)

# but it errs out: UnmappedInstanceError: Class '__builtin__.list' is not mapped

How do I delete all rows in a single table using Flask-SQLAlchemy?

Looking for something like this:

>>> users = models.User.query.all()
>>> models.db.session.delete(users)

# but it errs out: UnmappedInstanceError: Class '__builtin__.list' is not mapped

回答 0

尝试delete

models.User.query.delete()

文档Returns the number of rows deleted, excluding any cascades.

Try delete:

models.User.query.delete()

From the docs: Returns the number of rows deleted, excluding any cascades.


回答 1

DazWorrall的答案是正确的。如果您的代码结构不同于OP的结构,那么以下变体可能会很有用:

num_rows_deleted = db.session.query(Model).delete()

另外,不要忘记在您提交后删除操作才会生效,如以下代码段所示:

try:
    num_rows_deleted = db.session.query(Model).delete()
    db.session.commit()
except:
    db.session.rollback()

DazWorrall’s answer is spot on. Here’s a variation that might be useful if your code is structured differently than the OP’s:

num_rows_deleted = db.session.query(Model).delete()

Also, don’t forget that the deletion won’t take effect until you commit, as in this snippet:

try:
    num_rows_deleted = db.session.query(Model).delete()
    db.session.commit()
except:
    db.session.rollback()

回答 2

烧瓶法术

删除所有记录

#for all records
db.session.query(Model).delete()
db.session.commit()

删除单行

DB是对象Flask-SQLAlchemy类。它将从中删除所有记录,如果要删除特定记录,则filter查询中的try 子句。例如

#for specific value
db.session.query(Model).filter(Model.id==123).delete()
db.session.commit()

按对象删除单个记录

record_obj = db.session.query(Model).filter(Model.id==123).first()
db.session.delete(record_obj)
db.session.commit()

https://flask-sqlalchemy.palletsprojects.com/en/2.x/queries/#deleting-records

Flask-Sqlalchemy

Delete All Records

#for all records
db.session.query(Model).delete()
db.session.commit()

Deleted Single Row

here DB is the object Flask-SQLAlchemy class. It will delete all records from it and if you want to delete specific records then try filter clause in the query. ex.

#for specific value
db.session.query(Model).filter(Model.id==123).delete()
db.session.commit()

Delete Single Record by Object

record_obj = db.session.query(Model).filter(Model.id==123).first()
db.session.delete(record_obj)
db.session.commit()

https://flask-sqlalchemy.palletsprojects.com/en/2.x/queries/#deleting-records


不区分大小写的Flask-SQLAlchemy查询

问题:不区分大小写的Flask-SQLAlchemy查询

我正在使用Flask-SQLAlchemy从用户数据库中查询;但是,虽然

user = models.User.query.filter_by(username="ganye").first()

将返回

<User u'ganye'>

在做

user = models.User.query.filter_by(username="GANYE").first()

退货

None

我想知道是否有一种以不区分大小写的方式查询数据库的方法,以便第二个示例仍会返回

<User u'ganye'>

I’m using Flask-SQLAlchemy to query from a database of users; however, while

user = models.User.query.filter_by(username="ganye").first()

will return

<User u'ganye'>

doing

user = models.User.query.filter_by(username="GANYE").first()

returns

None

I’m wondering if there’s a way to query the database in a case insensitive way, so that the second example will still return

<User u'ganye'>

回答 0

您可以使用过滤器中的lowerupper功能来实现:

from sqlalchemy import func
user = models.User.query.filter(func.lower(User.username) == func.lower("GaNyE")).first()

另一种选择是使用ilike而不是进行搜索like

.query.filter(Model.column.ilike("ganye"))

You can do it by using either the lower or upper functions in your filter:

from sqlalchemy import func
user = models.User.query.filter(func.lower(User.username) == func.lower("GaNyE")).first()

Another option is to do searching using ilike instead of like:

.query.filter(Model.column.ilike("ganye"))

回答 1

如果仅指定所需的列,则可以改善@plaes的答案,这将使查询更短:

user = models.User.query.with_entities(models.User.username).\
filter(models.User.username.ilike("%ganye%")).all()

上面的例子中的情况下是非常有用的一个功能需要使用瓶的jsonify对AJAX的目的,然后在你的JavaScript访问它使用data.result

from flask import jsonify
jsonify(result=user)

Improving on @plaes’s answer, this one will make the query shorter if you specify just the column(s) you need:

user = models.User.query.with_entities(models.User.username).\
filter(models.User.username.ilike("%ganye%")).all()

The above example is very useful in case one needs to use Flask’s jsonify for AJAX purposes and then in your javascript access it using data.result:

from flask import jsonify
jsonify(result=user)

回答 2

你可以做

user = db.session.query(User).filter_by(func.lower(User.username)==func.lower("GANYE")).first()

或者您可以使用ilike函数

 user = db.session.query(User).filter_by(User.username.ilike("%ganye%")).first()

you can do

user = db.session.query(User).filter_by(func.lower(User.username)==func.lower("GANYE")).first()

Or you can use ilike function

 user = db.session.query(User).filter_by(User.username.ilike("%ganye%")).first()

SQLAlchemy ORM转换为Pandas DataFrame

问题:SQLAlchemy ORM转换为Pandas DataFrame

这个话题已经有一段时间没有在这里或其他地方了。是否有将SQLAlchemy <Query object>转换为pandas DataFrame 的解决方案?

Pandas具有使用能力,pandas.read_sql但这需要使用原始SQL。我有两个避免发生这种情况的原因:1)我已经使用ORM拥有了一切(本身就是一个很好的理由),并且2)我正在使用python列表作为查询的一部分(例如:模型类.db.session.query(Item).filter(Item.symbol.in_(add_symbols)在哪里Item)并且add_symbols是列表)。这等效于SQL SELECT ... from ... WHERE ... IN

有什么可能吗?

This topic hasn’t been addressed in a while, here or elsewhere. Is there a solution converting a SQLAlchemy <Query object> to a pandas DataFrame?

Pandas has the capability to use pandas.read_sql but this requires use of raw SQL. I have two reasons for wanting to avoid it: 1) I already have everything using the ORM (a good reason in and of itself) and 2) I’m using python lists as part of the query (eg: .db.session.query(Item).filter(Item.symbol.in_(add_symbols) where Item is my model class and add_symbols is a list). This is the equivalent of SQL SELECT ... from ... WHERE ... IN.

Is anything possible?


回答 0

在大多数情况下,下面的代码应该有效:

df = pd.read_sql(query.statement, query.session.bind)

有关pandas.read_sql参数的更多信息,请参见文档。

Below should work in most cases:

df = pd.read_sql(query.statement, query.session.bind)

See pandas.read_sql documentation for more information on the parameters.


回答 1

为了让新手熊猫程序员更加清楚,这是一个具体示例,

pd.read_sql(session.query(Complaint).filter(Complaint.id == 2).statement,session.bind) 

在这里,我们从id = 2的投诉表(sqlalchemy模型为Complaint)中选择一个投诉

Just to make this more clear for novice pandas programmers, here is a concrete example,

pd.read_sql(session.query(Complaint).filter(Complaint.id == 2).statement,session.bind) 

Here we select a complaint from complaints table (sqlalchemy model is Complaint) with id = 2


回答 2

所选解决方案对我不起作用,因为我不断收到错误消息

AttributeError:’AnnotatedSelect’对象没有属性’lower’

我发现以下工作:

df = pd.read_sql_query(query.statement, engine)

The selected solution didn’t work for me, as I kept getting the error

AttributeError: ‘AnnotatedSelect’ object has no attribute ‘lower’

I found the following worked:

df = pd.read_sql_query(query.statement, engine)

回答 3

如果要使用参数编译查询并说方言特定的参数,请使用以下命令:

c = query.statement.compile(query.session.bind)
df = pandas.read_sql(c.string, query.session.bind, params=c.params)

If you want to compile a query with parameters and dialect specific arguments, use something like this:

c = query.statement.compile(query.session.bind)
df = pandas.read_sql(c.string, query.session.bind, params=c.params)

回答 4

from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('postgresql://postgres:postgres@localhost:5432/DB', echo=False)
Base = declarative_base(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()

conn = session.bind

class DailyTrendsTable(Base):

    __tablename__ = 'trends'
    __table_args__ = ({"schema": 'mf_analysis'})

    company_code = Column(DOUBLE_PRECISION, primary_key=True)
    rt_bullish_trending = Column(Integer)
    rt_bearish_trending = Column(Integer)
    rt_bullish_non_trending = Column(Integer)
    rt_bearish_non_trending = Column(Integer)
    gen_date = Column(Date, primary_key=True)

df_query = select([DailyTrendsTable])

df_data = pd.read_sql(rt_daily_query, con = conn)
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('postgresql://postgres:postgres@localhost:5432/DB', echo=False)
Base = declarative_base(bind=engine)
Session = sessionmaker(bind=engine)
session = Session()

conn = session.bind

class DailyTrendsTable(Base):

    __tablename__ = 'trends'
    __table_args__ = ({"schema": 'mf_analysis'})

    company_code = Column(DOUBLE_PRECISION, primary_key=True)
    rt_bullish_trending = Column(Integer)
    rt_bearish_trending = Column(Integer)
    rt_bullish_non_trending = Column(Integer)
    rt_bearish_non_trending = Column(Integer)
    gen_date = Column(Date, primary_key=True)

df_query = select([DailyTrendsTable])

df_data = pd.read_sql(rt_daily_query, con = conn)

如何在Flask-SQLAlchemy应用中执行原始SQL

问题:如何在Flask-SQLAlchemy应用中执行原始SQL

如何在SQLAlchemy中执行原始SQL?

我有一个在烧瓶上运行的python Web应用程序,并通过SQLAlchemy连接到数据库。

我需要一种运行原始SQL的方法。该查询涉及多个表联接以及内联视图。

我试过了:

connection = db.session.connection()
connection.execute( <sql here> )

但是我不断收到网关错误。

How do you execute raw SQL in SQLAlchemy?

I have a python web app that runs on flask and interfaces to the database through SQLAlchemy.

I need a way to run the raw SQL. The query involves multiple table joins along with Inline views.

I’ve tried:

connection = db.session.connection()
connection.execute( <sql here> )

But I keep getting gateway errors.


回答 0

你有没有尝试过:

result = db.engine.execute("<sql here>")

要么:

from sqlalchemy import text

sql = text('select name from penguins')
result = db.engine.execute(sql)
names = [row[0] for row in result]
print names

Have you tried:

result = db.engine.execute("<sql here>")

or:

from sqlalchemy import text

sql = text('select name from penguins')
result = db.engine.execute(sql)
names = [row[0] for row in result]
print names

回答 1

SQL Alchemy会话对象具有自己的execute方法:

result = db.session.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

您的所有应用程序查询都应通过会话对象,无论它们是否是原始SQL。这样可以确保由事务适当地管理查询,该事务允许将同一请求中的多个查询作为一个单元提交或回滚。使用引擎连接进行事务处理将使您面临更大的隐患,即可能很难检测到可能导致数据损坏的错误的风险。每个请求应仅与一个事务相关联,并且使用db.session可以确保您的应用程序是这种情况。

另请注意,它execute是为参数化查询设计的。使用:val示例中的参数作为查询的任何输入,以保护自己免受SQL注入攻击。您可以通过传递a dict作为第二个参数来提供这些参数的值,其中每个键都是在查询中显示的参数名称。参数本身的确切语法可能会有所不同,具体取决于您的数据库,但是所有主要的关系数据库都以某种形式支持它们。

假设这是一个SELECT查询,它将返回一个可迭代RowProxy对象。

您可以使用多种技术访问各个列:

for r in result:
    print(r[0]) # Access by positional index
    print(r['my_column']) # Access by column name as a string
    r_dict = dict(r.items()) # convert to dict keyed by column names

就个人而言,我更喜欢将结果转换为namedtuples:

from collections import namedtuple

Record = namedtuple('Record', result.keys())
records = [Record(*r) for r in result.fetchall()]
for r in records:
    print(r.my_column)
    print(r)

如果您不使用Flask-SQLAlchemy扩展,您仍然可以轻松使用会话:

import sqlalchemy
from sqlalchemy.orm import sessionmaker, scoped_session

engine = sqlalchemy.create_engine('my connection string')
Session = scoped_session(sessionmaker(bind=engine))

s = Session()
result = s.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

SQL Alchemy session objects have their own execute method:

result = db.session.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

All your application queries should be going through a session object, whether they’re raw SQL or not. This ensures that the queries are properly managed by a transaction, which allows multiple queries in the same request to be committed or rolled back as a single unit. Going outside the transaction using the engine or the connection puts you at much greater risk of subtle, possibly hard to detect bugs that can leave you with corrupted data. Each request should be associated with only one transaction, and using db.session will ensure this is the case for your application.

Also take note that execute is designed for parameterized queries. Use parameters, like :val in the example, for any inputs to the query to protect yourself from SQL injection attacks. You can provide the value for these parameters by passing a dict as the second argument, where each key is the name of the parameter as it appears in the query. The exact syntax of the parameter itself may be different depending on your database, but all of the major relational databases support them in some form.

Assuming it’s a SELECT query, this will return an iterable of RowProxy objects.

You can access individual columns with a variety of techniques:

for r in result:
    print(r[0]) # Access by positional index
    print(r['my_column']) # Access by column name as a string
    r_dict = dict(r.items()) # convert to dict keyed by column names

Personally, I prefer to convert the results into namedtuples:

from collections import namedtuple

Record = namedtuple('Record', result.keys())
records = [Record(*r) for r in result.fetchall()]
for r in records:
    print(r.my_column)
    print(r)

If you’re not using the Flask-SQLAlchemy extension, you can still easily use a session:

import sqlalchemy
from sqlalchemy.orm import sessionmaker, scoped_session

engine = sqlalchemy.create_engine('my connection string')
Session = scoped_session(sessionmaker(bind=engine))

s = Session()
result = s.execute('SELECT * FROM my_table WHERE my_column = :val', {'val': 5})

回答 2

docs:SQL表达式语言教程-使用文本

例:

from sqlalchemy.sql import text

connection = engine.connect()

# recommended
cmd = 'select * from Employees where EmployeeGroup = :group'
employeeGroup = 'Staff'
employees = connection.execute(text(cmd), group = employeeGroup)

# or - wee more difficult to interpret the command
employeeGroup = 'Staff'
employees = connection.execute(
                  text('select * from Employees where EmployeeGroup = :group'), 
                  group = employeeGroup)

# or - notice the requirement to quote 'Staff'
employees = connection.execute(
                  text("select * from Employees where EmployeeGroup = 'Staff'"))


for employee in employees: logger.debug(employee)
# output
(0, 'Tim', 'Gurra', 'Staff', '991-509-9284')
(1, 'Jim', 'Carey', 'Staff', '832-252-1910')
(2, 'Lee', 'Asher', 'Staff', '897-747-1564')
(3, 'Ben', 'Hayes', 'Staff', '584-255-2631')

docs: SQL Expression Language Tutorial – Using Text

example:

from sqlalchemy.sql import text

connection = engine.connect()

# recommended
cmd = 'select * from Employees where EmployeeGroup = :group'
employeeGroup = 'Staff'
employees = connection.execute(text(cmd), group = employeeGroup)

# or - wee more difficult to interpret the command
employeeGroup = 'Staff'
employees = connection.execute(
                  text('select * from Employees where EmployeeGroup = :group'), 
                  group = employeeGroup)

# or - notice the requirement to quote 'Staff'
employees = connection.execute(
                  text("select * from Employees where EmployeeGroup = 'Staff'"))


for employee in employees: logger.debug(employee)
# output
(0, 'Tim', 'Gurra', 'Staff', '991-509-9284')
(1, 'Jim', 'Carey', 'Staff', '832-252-1910')
(2, 'Lee', 'Asher', 'Staff', '897-747-1564')
(3, 'Ben', 'Hayes', 'Staff', '584-255-2631')

回答 3

你可以使用SELECT SQL查询的结果from_statement(),并text()如图所示这里。您不必以这种方式处理元组。作为User具有表名的类的示例,users您可以尝试,

from sqlalchemy.sql import text
.
.
.
user = session.query(User).from_statement(
    text("SELECT * FROM users where name=:name")).\
    params(name='ed').all()

return user

You can get the results of SELECT SQL queries using from_statement() and text() as shown here. You don’t have to deal with tuples this way. As an example for a class User having the table name users you can try,

from sqlalchemy.sql import text

user = session.query(User).from_statement(
    text("""SELECT * FROM users where name=:name""")
).params(name="ed").all()

return user

回答 4

result = db.engine.execute(text("<sql here>"))

<sql here>除非您处于autocommit模式,否则执行但不提交。因此,插入和更新不会反映在数据库中。

要在更改后提交,请执行

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))
result = db.engine.execute(text("<sql here>"))

executes the <sql here> but doesn’t commit it unless you’re on autocommit mode. So, inserts and updates wouldn’t reflect in the database.

To commit after the changes, do

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

回答 5

这是如何从Flask Shell运行SQL查询的简化答案

首先,映射您的模块(如果您的模块/应用程序是principal文件夹中的manage.py,并且您在UNIX操作系统中),请运行:

export FLASK_APP=manage

运行烧瓶壳

flask shell

导入我们需要的::

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
from sqlalchemy import text

运行查询:

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

这将使用具有应用程序的当前数据库连接。

This is a simplified answer of how to run SQL query from Flask Shell

First, map your module (if your module/app is manage.py in the principal folder and you are in a UNIX Operating system), run:

export FLASK_APP=manage

Run Flask shell

flask shell

Import what we need::

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
from sqlalchemy import text

Run your query:

result = db.engine.execute(text("<sql here>").execution_options(autocommit=True))

This use the currently database connection which has the application.


回答 6

您是否尝试过按照文档connection.execute(text( <sql here> ), <bind params here> )所述使用和绑定参数?这可以帮助解决许多参数格式设置和性能问题。也许网关错误是超时?绑定参数往往会使复杂的查询执行得更快。

Have you tried using connection.execute(text( <sql here> ), <bind params here> ) and bind parameters as described in the docs? This can help solve many parameter formatting and performance problems. Maybe the gateway error is a timeout? Bind parameters tend to make complex queries execute substantially faster.


回答 7

如果你想避免的元组,另一种方式是通过调用firstoneall方法:

query = db.engine.execute("SELECT * FROM blogs "
                           "WHERE id = 1 ")

assert query.first().name == "Welcome to my blog"

If you want to avoid tuples, another way is by calling the first, one or all methods:

query = db.engine.execute("SELECT * FROM blogs "
                           "WHERE id = 1 ")

assert query.first().name == "Welcome to my blog"