Flask-SQLalchemy atualiza as informações de uma linha

121

Como posso atualizar as informações de uma linha?

Por exemplo, eu gostaria de alterar a coluna de nome da linha que tem o id 5.

Pocorschi
fonte

Respostas:

205

Recupere um objeto usando o tutorial mostrado na documentação do Flask-SQLAlchemy . Assim que tiver a entidade que deseja alterar, altere a própria entidade. Então db.session.commit(),.

Por exemplo:

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

O Flask-SQLAlchemy é baseado no SQLAlchemy, portanto, verifique também os documentos do SQLAlchemy .

Mark Hildreth
fonte
2
Obrigado Mark. Outra coisa. Já vi isso ser feito assim 'db.add (user)' e depois 'dv.session.commit ()'. Por que os dois funcionam? e qual é a diferença?
pocorschi de
11
Isso tem a ver com as diferenças entre objetos transientes, desanexados e anexados em SQLAlchemy (consulte sqlalchemy.org/docs/orm/session.html#what-does-the-session-do ). Além disso, leia o comentário de Michael Bayer na lista de discussão ( groups.google.com/group/sqlalchemy/browse_thread/thread/… ) para mais informações.
Mark Hildreth
1
Se você ainda estiver confuso sobre as diferenças depois de ler tudo isso, considere fazer outra pergunta.
Mark Hildreth
se o tipo de dados da coluna for json, use o método abaixo. bashelton.com/2014/03/…
Aram
@MarkHildreth Não consegui atualizar um valor de data e hora para o campo, o que devo fazer? coluna é uesd_at = db.Column(db.DateTime)que acabei de executar, obj.used_at = datetime.datetime.now() db.session.commit()mas não o valor definido para o campo.
Rukeith
96

Há um método updateno objeto BaseQuery em SQLAlchemy, que é retornado por filter_by.

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

A vantagem de usar em updatevez de alterar a entidade surge quando há muitos objetos a serem atualizados.

Se você quiser dar add_userpermissão a todos os admins,

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

Observe que filter_byleva argumentos de palavra-chave (use apenas um =) em vez de usar filteruma expressão.

Devi
fonte
1
na primeira consulta, o resultado é denominado como admin, o que pode ser enganoso, pois o resultado será o número de linhas atualizadas. Não é?
Vikas Prasad
e há uma maneira de obter os Useritens afetados pela consulta, não o número de usuários afetados?
Vikas Prasad
número de linhas correspondidas
Vikas Prasad
18

Isso não funciona se você modificar um atributo em conserva do modelo. Os atributos conservados devem ser substituídos para acionar as atualizações:

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}
Bevan
fonte
1
Qual é a melhor abordagem nesses casos?
kampta
Você teria que copiar datae reatribuir.
sas
@sas O que você quer dizer?
Mote Zart
Você precisará copiar e atribuir à propriedade de dados para acionar o mecanismo de atualização. Dê uma olhada na resposta abaixo:user.data = data
sas
9

Apenas atribuir o valor e confirmá-los funcionará para todos os tipos de dados, exceto os atributos JSON e Pickled. Como o tipo em conserva é explicado acima, anotarei uma maneira um pouco diferente, mas fácil de atualizar 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

Digamos que o modelo seja como o acima.

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

Isso adicionará o usuário ao banco de dados MySQL com os dados {"country": "Sri Lanka"}

A modificação de dados será ignorada. Meu código que não funcionou é o seguinte.

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

Em vez de passar pelo árduo trabalho de copiar o JSON para um novo dicionário (não atribuí-lo a uma nova variável como acima), o que deveria ter funcionado, encontrei uma maneira simples de fazer isso. Existe uma maneira de sinalizar o sistema que os JSONs mudaram.

A seguir está o código de trabalho.

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

Isso funcionou como um encanto. Há outro método proposto junto com este método aqui. Espero ter ajudado alguém.

Hareendra Chamara Philips
fonte
2
db.session.merge(user)adicionar este código funcionou para mim, FYI.
Jeff Bluemel de