Flask-SQLalchemy обновляет информацию о строке

122

Как я могу обновить информацию о строке?

Например, я хотел бы изменить столбец имени строки с идентификатором 5.

pocorschi
источник

Ответы:

206

Получите объект, используя руководство, показанное в документации 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
Спасибо, Марк. Еще одно. Я видел, как это делается так: «db.add (пользователь)», затем «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/… ) для получения дополнительной информации.
Марк Хилдрет
1
Если после прочтения вы все еще не уверены в различиях, подумайте о том, чтобы задать другой вопрос.
Марк Хилдрет
если тип данных столбца - json, используйте метод ниже. bashelton.com/2014/03/…
Арам
@MarkHildreth Мне не удалось обновить значение даты и времени в поле, что мне делать? столбец, uesd_at = db.Column(db.DateTime)я просто бегу, obj.used_at = datetime.datetime.now() db.session.commit()но не значение, установленное для поля.
Рукейт
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аргументы ключевого слова (используйте только один =), а не filterвыражение.

Devi
источник
1
в первом запросе результат назван как admin, что может вводить в заблуждение, поскольку результатом будет количество обновленных строк. Не так ли?
Викас Прасад
и есть ли способ получить затронутые Userэлементы по запросу, а не количество затронутых пользователей?
Викас Прасад
количество совпавших
Викас Прасад
18

Это не сработает, если вы измените маринованный атрибут модели. Для запуска обновлений необходимо заменить маринованные атрибуты:

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
Вам придется его скопировать dataи переназначить.
sas
@sas Что ты имеешь в виду?
Mote
Вам нужно будет скопировать и назначить свойство данных, чтобы запустить механизм обновления. Взгляните на ответ ниже: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()

Это добавит пользователя в базу данных MySQL с данными {"country": "Sri Lanka"}.

Изменение данных будет проигнорировано. Мой код, который не сработал, выглядит следующим образом.

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 были изменены.

Ниже приведен рабочий код.

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.
Джефф Блюмел