Flask-SQLalchemy aktualizuje informacje w wierszu


Odpowiedzi:


206

Pobierz obiekt, korzystając z samouczka przedstawionego w dokumentacji Flask-SQLAlchemy . Gdy masz już encję, którą chcesz zmienić, zmień samą jednostkę. Następnie db.session.commit().

Na przykład:

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

Flask-SQLAlchemy jest oparty na SQLAlchemy, więc koniecznie zapoznaj się również z dokumentami SQLAlchemy .


2
Dzięki Mark. Jeszcze jedno. Widziałem to w następujący sposób: „db.add (użytkownik)”, a następnie „dv.session.commit ()”. Dlaczego oba działają? a jaka jest różnica?
pocorschi

11
Ma to związek z różnicami między obiektami przejściowymi, odłączonymi i dołączonymi w SQLAlchemy (patrz sqlalchemy.org/docs/orm/session.html#what-does-the-session-do ). Przeczytaj także komentarz Michaela Bayera na liście mailingowej ( groups.google.com/group/sqlalchemy/browse_thread/thread/… ), aby uzyskać więcej informacji.
Mark Hildreth,

1
Jeśli po przeczytaniu nadal nie masz pewności co do różnic, rozważ zadanie kolejnego pytania.
Mark Hildreth,

jeśli typ danych kolumny to json, użyj poniższej metody. bashelton.com/2014/03/…
Aram

@MarkHildreth Nie mogłem zaktualizować wartości daty i godziny w polu, co mam zrobić? kolumna jest uesd_at = db.Column(db.DateTime)po prostu uruchomiona, obj.used_at = datetime.datetime.now() db.session.commit()ale nie wartość ustawiona na pole.
Rukeith

96

W updateobiekcie BaseQuery w SQLAlchemy istnieje metoda , która jest zwracana przez filter_by.

admin = User.query.filter_by(username='admin').update(dict(email='my_new_email@example.com')))
db.session.commit()

Zaletą używania updatenad zmianą jednostki jest sytuacja, gdy istnieje wiele obiektów do zaktualizowania.

Jeśli chcesz add_userzezwolić wszystkim admin,

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

Zauważ, że filter_byprzyjmuje argumenty słów kluczowych (użyj tylko jednego =), w przeciwieństwie do tego, filterktóry przyjmuje wyrażenie.


1
w pierwszym zapytaniu wynik jest nazwany as admin, co może być mylące, ponieważ wynikiem będzie liczba zaktualizowanych wierszy. Prawda?
Vikas Prasad

i czy istnieje sposób, w jaki mogę uzyskać Userelementy, których dotyczy zapytanie, a nie liczbę użytkowników, których dotyczy zapytanie?
Vikas Prasad

liczba dopasowanych
Vikas Prasad

18

To nie zadziała, jeśli zmodyfikujesz marynowany atrybut modelu. Marynowane atrybuty należy wymienić, aby wywołać aktualizacje:

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
Jakie jest najlepsze podejście w takich przypadkach?
kampta

Musisz go skopiować datai przypisać.
sas

@sas Co masz na myśli?
Mote Zart

Będziesz musiał skopiować i przypisać do właściwości data, aby uruchomić mechanizm aktualizacji. Spójrz na odpowiedź poniżej:user.data = data
sas

9

Samo przypisanie wartości i zatwierdzenie ich zadziała dla wszystkich typów danych oprócz atrybutów JSON i Pickled. Ponieważ typ marynowany jest wyjaśniony powyżej, zanotuję nieco inny, ale łatwy sposób aktualizacji 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

Powiedzmy, że model jest taki jak powyżej.

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

Spowoduje to dodanie użytkownika do bazy danych MySQL z danymi {"country": "Sri Lanka"}

Modyfikowanie danych zostanie zignorowane. Mój kod, który nie zadziałał, jest następujący.

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

Zamiast przechodzić przez bolesną pracę polegającą na kopiowaniu JSON do nowego dyktu (nie przypisując go do nowej zmiennej jak wyżej), co powinno zadziałać, znalazłem prosty sposób na zrobienie tego. Istnieje sposób na oznaczenie systemu, że zmieniły się JSON.

Poniżej znajduje się działający kod.

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

To zadziałało jak urok. Jest jeszcze inna metoda zaproponowana wraz z tej metody tutaj nadzieję, że pomogliśmy kogoś.


2
db.session.merge(user)dodanie tego kodu zadziałało dla mnie, FYI.
Jeff Bluemel,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.