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.