Flask-SQLalchemy memperbarui informasi baris


Jawaban:


206

Ambil objek menggunakan tutorial yang ditampilkan di dokumentasi Flask-SQLAlchemy . Setelah Anda memiliki entitas yang ingin Anda ubah, ubah entitas itu sendiri. Kemudian db.session.commit(),.

Sebagai contoh:

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 didasarkan pada SQLAlchemy, jadi pastikan untuk memeriksa Dokumen SQLAlchemy juga.


2
Terima kasih Mark. Satu hal lagi. Saya telah melihatnya dilakukan seperti ini 'db.add (user)' lalu 'dv.session.commit ()'. Mengapa keduanya bekerja? dan apa bedanya?
pocorschi

11
Ini ada hubungannya dengan perbedaan antara objek transient, detached, dan attachment di SQLAlchemy (lihat sqlalchemy.org/docs/orm/session.html#what-does-the-session-do ). Baca juga komentar Michael Bayer di milis ( groups.google.com/group/sqlalchemy/browse_thread/thread/… ) untuk info lebih lanjut.
Mark Hildreth

1
Jika Anda masih bingung tentang perbedaannya setelah membaca di sana, pertimbangkan untuk mengajukan pertanyaan lain.
Mark Hildreth

jika tipe data kolom adalah json, gunakan metode di bawah ini. bashelton.com/2014/03/…
Aram

@MarkHildreth Saya tidak dapat memperbarui nilai datetime ke bidang, apa yang harus saya lakukan? kolom adalah uesd_at = db.Column(db.DateTime)Saya baru saja menjalankan obj.used_at = datetime.datetime.now() db.session.commit()Tapi tidak menetapkan nilai ke lapangan.
Rukeith

96

Ada metode updatepada objek BaseQuery di SQLAlchemy, yang dikembalikan oleh filter_by.

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

Keuntungan menggunakan updatelebih dari perubahan entitas datang ketika ada banyak objek yang akan diperbarui.

Jika Anda ingin memberikan add_userizin kepada semua admin,

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

Perhatikan bahwa filter_bymengambil argumen kata kunci (gunakan hanya satu =) sebagai lawan filteryang mengambil ekspresi.


1
di kueri pertama, hasilnya dinamai sebagai admin, yang mungkin menyesatkan karena hasilnya adalah jumlah baris yang diperbarui. Bukan?
Vikas Prasad

dan adakah cara, di mana saya bisa mendapatkan Useritem yang terpengaruh oleh kueri, bukan jumlah pengguna yang terpengaruh?
Vikas Prasad

jumlah baris yang cocok
Vikas Prasad

18

Ini tidak bekerja jika Anda mengubah atribut acar model. Atribut acar harus diganti untuk memicu pembaruan:

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
Apa pendekatan terbaik dalam kasus seperti itu?
kampta

Anda harus menyalin datadan menetapkannya kembali.
sas

@sas Apa maksudmu?
Mote Zart

Anda harus menyalin dan menetapkan ke properti data untuk memicu mekanisme pembaruan. Silahkan lihat pada jawaban di bawah ini:user.data = data
sas

9

Hanya menetapkan nilai dan menerapkannya akan berfungsi untuk semua tipe data kecuali atribut JSON dan Acar. Karena jenis acar dijelaskan di atas, saya akan mencatat cara yang sedikit berbeda tetapi mudah untuk memperbarui 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

Misalkan modelnya seperti di atas.

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

Ini akan menambahkan pengguna ke dalam database MySQL dengan data {"country": "Sri Lanka"}

Mengubah data akan diabaikan. Kode saya yang tidak berfungsi adalah sebagai berikut.

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

Alih-alih melalui pekerjaan menyakitkan menyalin JSON ke dict baru (tidak menugaskannya ke variabel baru seperti di atas), yang seharusnya berhasil, saya menemukan cara sederhana untuk melakukannya. Ada cara untuk menandai sistem yang telah diubah JSON.

Berikut ini adalah kode kerja.

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

Ini bekerja seperti pesona. Ada metode lain yang diusulkan bersama dengan metode ini di sini Harapan saya telah membantu seseorang.


2
db.session.merge(user)menambahkan kode ini berhasil untuk saya, FYI.
Jeff Bluemel
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.