Flask-SQLalchemyは行の情報を更新します


回答:


205

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のドキュメントも必ずチェックしてください。


2
マークありがとう。もう1つ。私はそれがこの 'db.add(user)'から 'dv.session.commit()'のように行われるのを見てきました。なぜ両方が機能するのですか?違いは何ですか?
pocorschi

11
これは、SQLAlchemyの一時オブジェクト、デタッチオブジェクト、およびアタッチオブジェクトの違いに関係しています(sqlalchemy.org/docs/orm/session.html#what-does-the-session-doを参照)。また、詳細については、メーリングリスト(groups.google.com/group/sqlalchemy/browse_thread/thread/…)に関するMichael Bayerのコメントを参照してください。
Mark Hildreth、2011

1
違いを読んでもまだ混乱している場合は、別の質問をすることを検討してください。
Mark Hildreth、2011

列のデータ型がjsonの場合、以下のメソッドを使用します。bashelton.com/2014/03/...
アラム

@MarkHildrethフィールドの日時値を更新できませんでした。どうすればよいですか?列はuesd_at = db.Column(db.DateTime)私が実行するだけobj.used_at = datetime.datetime.now() db.session.commit()ですが、フィールドに設定された値ではありません。
18

96

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すべてのに許可を与える場合はadmin

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

が式をfilter_by取るのではなく、キーワード引数を取る(1つだけ使用する=)ことに注意してくださいfilter


1
最初のクエリでは、結果はという名前になりますが、結果はadmin更新された行数になるため、誤解を招く可能性があります。だよね?
Vikas Prasad

User影響を受けるユーザーの数ではなく、クエリによって影響を受けるアイテムを取得する方法はありますか?
Vikas Prasad

一致した
Vikas Prasad

18

これは、モデルのpickle化された属性を変更する場合は機能しません。更新をトリガーするには、漬物属性を置き換える必要があります。

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}

1
そのような場合の最善のアプローチは何ですか?
kampta 2016年

コピーdataして再割り当てする必要があります。
sas

@sasどういう意味ですか?
Mote Zart

更新メカニズムをトリガーするには、コピーしてdataプロパティに割り当てる必要があります。以下の答えを見て:user.data = data
SAS

9

値を割り当ててコミットするだけで、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を新しいdictにコピーするという面倒な作業(上記のように新しい変数に割り当てるのではなく)を行う代わりに、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()

これは魅力のように働きました。この方法と一緒に提案された別の方法がここ にあります私がいくつかを助けたことを願っています。


2
db.session.merge(user)このコードを追加することは私のために働きました、FYI。
ジェフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.