Flask-SQLalchemy memperbarui informasi baris

122

Bagaimana cara memperbarui informasi baris?

Misalnya saya ingin mengubah kolom nama dari baris yang memiliki id 5.

pocorschi
sumber

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 = '[email protected]'
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.

Mark Hildreth
sumber
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='[email protected]')))
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.

Devi
sumber
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}
Bevan
sumber
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.

Hareendra Chamara Philips
sumber
2
db.session.merge(user)menambahkan kode ini berhasil untuk saya, FYI.
Jeff Bluemel