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


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 = 'my_new_email@example.com'
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 .


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='my_new_email@example.com')))
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.


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}

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.


2
db.session.merge(user)adicionar este código funcionou para mim, FYI.
Jeff Bluemel de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.