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

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

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


person pocorschi    schedule 14.07.2011    source источник


Ответы (5)


Получите объект, используя руководство, показанное в документации Flask-SQLAlchemy. Когда у вас есть сущность, которую вы хотите изменить, измените саму сущность. Затем db.session.commit().

Например:

admin = User.query.filter_by(username='admin').first()
admin.email = '[email protected]'
db.session.commit()

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

Flask-SQLAlchemy основан на SQLAlchemy, поэтому обязательно ознакомьтесь с Документация по SQLAlchemy.

person Mark Hildreth    schedule 14.07.2011
comment
Спасибо, Марк. Еще одна вещь. Я видел, как это делается так: «db.add(user)», затем «dv.session.commit()». Почему оба работают? а какая разница? - person pocorschi; 15.07.2011
comment
Это связано с различиями между временными, отсоединенными и присоединенными объектами в SQLAlchemy (см. sqlalchemy.org/docs/orm/session.html#what-does-the-session-do). Также прочитайте комментарий Майкла Байера в списке рассылки (groups.google. .com/group/sqlalchemy/browse_thread/thread/) для дополнительной информации. - person Mark Hildreth; 15.07.2011
comment
Если после прочтения вы все еще не понимаете различий, подумайте над тем, чтобы задать еще один вопрос. - person Mark Hildreth; 15.07.2011
comment
если тип данных столбца json, используйте метод ниже. baschelton.com/2014/03/ - person Aram; 21.06.2018
comment
@MarkHildreth Мне не удалось обновить значение даты и времени в поле, что мне делать? столбец uesd_at = db.Column(db.DateTime) Я просто запускаю obj.used_at = datetime.datetime.now() db.session.commit() Но не значение, установленное для поля. - person Rukeith; 30.10.2018
comment
@mark это дает мне исключение, что объект 'dict' не имеет атрибута 'email' - person Ferdous Wahid; 13.12.2018
comment
это только имя обновления или весь ряд? @МаркХилдрет - person Dolphin; 05.10.2020

Существует метод update для объекта BaseQuery в SQLAlchemy, который возвращается filter_by.

num_rows_updated = User.query.filter_by(username='admin').update(dict(email='[email protected]')))
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, который принимает выражение.

person Devi    schedule 20.10.2011
comment
в первом запросе результат называется admin, что может ввести в заблуждение, поскольку результатом будет количество обновленных строк. Не так ли? - person Vikas Prasad; 24.08.2018
comment
и есть ли способ, где я могу получить затронутые User элементы по запросу, а не количество затронутых пользователей? - person Vikas Prasad; 24.08.2018
comment
количество строк, совпадающих - person Vikas Prasad; 24.08.2018
comment
Зачем вам нужно передавать переменную «admin» в функцию обновления? Нигде не используется - person d1spstack; 10.01.2021

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

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}
person Bevan    schedule 13.01.2015
comment
Каков наилучший подход в таких случаях? - person kampta; 31.05.2016
comment
Вам придется скопировать data и переназначить его. - person sas; 25.09.2017
comment
@sas Что ты имеешь в виду? - person Mote Zart; 25.11.2019
comment
Вам нужно будет скопировать и присвоить свойство данных, чтобы запустить механизм обновления. Посмотрите на ответ ниже: user.data = data - person sas; 25.11.2019
comment
Почему изменение данных игнорируется в вашем примере? @Беван - person acebelowzero; 18.11.2020

Простое присвоение значения и его фиксация будут работать для всех типов данных, кроме атрибутов 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()

Это сработало как шарм. Наряду с этим методом предлагается еще один метод здесь Надеюсь, я помог кому-то.

person Hareendra Chamara Philips    schedule 25.11.2017
comment
db.session.merge(user) добавление этого кода сработало для меня, FYI. - person Jeff Bluemel; 22.04.2018

Models.py определяет сериализаторы

def default(o):
   if isinstance(o, (date, datetime)):
      return o.isoformat()

class User(db.Model):
   __tablename__='user'
   id = db.Column(db.Integer, primary_key=True, autoincrement=True)
   .......
   ####

    def serializers(self):
       dict_val={"id":self.id,"created_by":self.created_by,"created_at":self.created_at,"updated_by":self.updated_by,"updated_at":self.updated_at}
       return json.loads(json.dumps(dict_val,default=default))

В RestApi мы можем динамически обновлять запись, передавая данные json в запрос на обновление:

class UpdateUserDetails(Resource):
   @auth_token_required
   def post(self):
      json_data = request.get_json()
      user_id = current_user.id
      try:
         instance = User.query.filter(User.id==user_id)
         data=instance.update(dict(json_data))
         db.session.commit()
         updateddata=instance.first()
         msg={"msg":"User details updated successfully","data":updateddata.serializers()}
         code=200
      except Exception as e:
         print(e)
         msg = {"msg": "Failed to update the userdetails! please contact your administartor."}
         code=500
      return msg
person Ramesh Ponnusamy    schedule 15.09.2020
comment
короче и лучше! - person ANONYMUS; 22.12.2020