Flask-SQLalchemy оновити інформацію про рядок


121

Як я можу оновити інформацію про рядок?

Наприклад, я хотів би змінити стовпець імені рядка, який містить id 5.

Відповіді:


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
Спасибі Марку. Ще одна річ. Я бачив це як "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

Існує метод updateна об'єкт BaseQuery в SQLAlchemy, який повертається 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який бере вираз.


1
у першому запиті результат позначається як admin, що може ввести в оману, оскільки результатом буде кількість оновлених рядків. Чи не так?
Вікас Прасад

і чи є спосіб, коли я можу отримати Userзапити на постраждалі елементи, а не на кількість користувачів, яких це стосується?
Вікас Прасад

кількість рядків збігається
Vikas Prasad

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 Що ти маєш на увазі?
Mote Zart

Вам потрібно буде скопіювати та призначити властивість даних, щоб запустити механізм оновлення. Подивіться на відповідь нижче: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": "Шрі-Ланка"}

Змінення даних буде проігноровано. Мій код, який не працював, наступний.

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()

Це спрацювало як шарм. Існує запропоновано поряд з цим методом інший метод тут сподіваюся , що я допоміг який - то один.


2
db.session.merge(user)додавання цього коду працювало для мене, FYI.
Джефф Блумел
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.