Flask-SQLalchemy actualiza la información de una fila

121

¿Cómo puedo actualizar la información de una fila?

Por ejemplo, me gustaría modificar la columna de nombre de la fila que tiene la identificación 5.

pocorschi
fuente

Respuestas:

205

Recupere un objeto usando el tutorial que se muestra en la documentación de Flask-SQLAlchemy . Una vez que tenga la entidad que desea cambiar, cambie la entidad en sí. A continuación, db.session.commit().

Por ejemplo:

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 se basa en SQLAlchemy, así que asegúrese de consultar también SQLAlchemy Docs .

Mark Hildreth
fuente
2
Gracias Mark. Otra cosa. Lo he visto hecho así 'db.add (usuario)' y luego 'dv.session.commit ()'. ¿Por qué funcionan ambos? y cual es la diferencia
pocorschi
11
Esto tiene que ver con las diferencias entre objetos transitorios, separados y adjuntos en SQLAlchemy (consulte sqlalchemy.org/docs/orm/session.html#what-does-the-session-do ). Además, lea el comentario de Michael Bayer sobre la lista de correo ( groups.google.com/group/sqlalchemy/browse_thread/thread/… ) para obtener más información.
Mark Hildreth
1
Si aún está confundido con las diferencias después de leerlo, considere hacer otra pregunta.
Mark Hildreth
si el tipo de datos de la columna es json, utilice el método siguiente. bashelton.com/2014/03/…
Aram
@MarkHildreth No pude actualizar un valor de fecha y hora en el campo, ¿qué debo hacer? La columna es uesd_at = db.Column(db.DateTime)simplemente ejecuto obj.used_at = datetime.datetime.now() db.session.commit()Pero no valor establecido en el campo.
Rukeith
96

Hay un método updateen el objeto BaseQuery en SQLAlchemy, que es devuelto por filter_by.

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

La ventaja de usar updatesobre el cambio de entidad viene cuando hay muchos objetos para actualizar.

Si quieres dar add_userpermiso a todos los admins,

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

Observe que filter_bytoma argumentos de palabras clave (use solo uno =) en lugar de lo filterque toma una expresión.

Devi
fuente
1
en la primera consulta, el resultado se nombra como admin, lo que puede ser engañoso ya que el resultado será el número de filas actualizadas. ¿No es así?
Vikas Prasad
y ¿hay alguna manera de obtener los Userelementos afectados por la consulta, no la cantidad de usuarios afectados?
Vikas Prasad
número de filas coincidentes
Vikas Prasad
18

Esto no funciona si modifica un atributo decapado del modelo. Los atributos en escabeche deben reemplazarse para activar actualizaciones:

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
fuente
1
¿Cuál es el mejor enfoque en tales casos?
kampta
Tendrías que copiarlo datay reasignarlo.
sas
@sas ¿Qué quieres decir?
Mote Zart
Deberá copiar y asignar la propiedad de datos para activar el mecanismo de actualización. Echar un vistazo a la respuesta a continuación:user.data = data
SAS
9

Simplemente asignar el valor y confirmarlos funcionará para todos los tipos de datos, excepto los atributos JSON y Pickled. Dado que el tipo en escabeche se explica anteriormente, anotaré una forma ligeramente diferente pero fácil de actualizar 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

Digamos que el modelo es como el anterior.

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

Esto agregará al usuario a la base de datos MySQL con datos {"country": "Sri Lanka"}

Se ignorará la modificación de datos. Mi código que no funcionó es el siguiente.

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

En lugar de pasar por el doloroso trabajo de copiar el JSON a un nuevo dictado (sin asignarlo a una nueva variable como arriba), que debería haber funcionado, encontré una manera simple de hacerlo. Hay una forma de marcar el sistema de que los JSON han cambiado.

A continuación se muestra el código de trabajo.

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

Funcionó como por arte de magia. Hay otro método propuesto junto con este método aquí Espero haber ayudado a alguien.

Hareendra Chamara Philips
fuente
2
db.session.merge(user)agregar este código funcionó para mí, FYI.
Jeff Bluemel