Flask-SQLalchemy อัปเดตข้อมูลของแถว


122

ฉันจะอัปเดตข้อมูลของแถวได้อย่างไร

ตัวอย่างเช่นฉันต้องการเปลี่ยนคอลัมน์ชื่อของแถวที่มีรหัส 5

คำตอบ:


207

เรียกวัตถุโดยใช้ที่กวดวิชาที่ปรากฏในเอกสารขวด-SQLAlchemy เมื่อคุณมีเอนทิตีที่คุณต้องการเปลี่ยนแปลงแล้วให้เปลี่ยนตัวเอนทิตีนั้นเอง จากนั้นdb.session.commit().

ตัวอย่างเช่น:

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 ขึ้นอยู่กับ SQLAlchemy ดังนั้นอย่าลืมตรวจสอบเอกสาร SQLAlchemyด้วย


2
ขอบคุณมาร์ค อีกอย่างหนึ่ง ฉันเคยเห็นมันทำแบบนี้ 'db.add (user)' แล้วก็ 'dv.session.commit ()' ทำไมทั้งสองทำงาน? และอะไรคือความแตกต่าง?
pocorschi

11
สิ่งนี้เกี่ยวข้องกับความแตกต่างระหว่างอ็อบเจ็กต์ชั่วคราวแยกออกและแนบใน SQLAlchemy (ดูsqlalchemy.org/docs/orm/session.html#what-does-the-session-do ) นอกจากนี้โปรดอ่านความคิดเห็นของ Michael Bayer ในรายชื่ออีเมล ( groups.google.com/group/sqlalchemy/browse_thread/thread/… ) สำหรับข้อมูลเพิ่มเติม
Mark Hildreth

1
หากคุณยังคงสับสนเกี่ยวกับความแตกต่างหลังจากอ่านจบแล้วให้ลองถามคำถามอื่น
Mark Hildreth

หากชนิดข้อมูลคอลัมน์เป็น json ให้ใช้วิธีการด้านล่าง bashelton.com/2014/03/…
อร่าม

@MarkHildreth ฉันไม่สามารถอัปเดตค่าวันที่และเวลาลงในฟิลด์ได้ฉันควรทำอย่างไร uesd_at = db.Column(db.DateTime)ฉันเพิ่งเรียกใช้คอลัมน์obj.used_at = datetime.datetime.now() db.session.commit()แต่ไม่ได้ตั้งค่าลงในฟิลด์
Rukeith

96

มีวิธีการที่เป็นupdateวัตถุ BaseQuery ใน SQLAlchemy filter_byซึ่งถูกส่งกลับโดย

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

ข้อได้เปรียบของการใช้updateการเปลี่ยนเอนทิตีเกิดขึ้นเมื่อมีวัตถุจำนวนมากที่ต้องอัปเดต

หากคุณต้องการที่จะให้add_userได้รับอนุญาตให้กับทุกadminวินาที

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

ข้อสังเกตที่filter_byใช้อาร์กิวเมนต์คำหลัก (ใช้เพียงข้อเดียว=) ซึ่งตรงข้ามกับfilterนิพจน์ที่ใช้


1
ในแบบสอบถามแรกผลลัพธ์จะถูกตั้งชื่อเป็นadminซึ่งอาจทำให้เข้าใจผิดเนื่องจากผลลัพธ์จะเป็นจำนวนแถวที่อัปเดต ไม่ใช่เหรอ?
Vikas Prasad

และมีวิธีไหนบ้างที่ฉันจะได้รับUserรายการที่ได้รับผลกระทบจากข้อความค้นหาไม่ใช่จำนวนผู้ใช้ที่ได้รับผลกระทบ
Vikas Prasad

จำนวนแถวที่ตรงกัน
Vikas Prasad

18

สิ่งนี้ใช้ไม่ได้หากคุณแก้ไขแอตทริบิวต์ดองของโมเดล ควรเปลี่ยนแอตทริบิวต์ของดองเพื่อเรียกการอัปเดต:

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
แนวทางที่ดีที่สุดในกรณีเช่นนี้คืออะไร?
kampta

คุณจะต้องคัดลอกdataและกำหนดใหม่
SAS

@sas คุณหมายถึงอะไร?
Mote Zart

คุณจะต้องคัดลอกและกำหนดให้กับคุณสมบัติข้อมูลเพื่อทริกเกอร์กลไกการอัปเดต มีลักษณะที่คำตอบด้านล่าง:user.data = data
SAS

9

เพียงแค่กำหนดค่าและยอมรับจะใช้ได้กับข้อมูลทุกประเภทยกเว้น JSON และแอตทริบิวต์ Pickled เนื่องจากมีการอธิบายประเภทของดองไว้ข้างต้นฉันจะจดบันทึกวิธีการอัปเดต 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

สมมติว่าโมเดลเหมือนข้างบน

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

การดำเนินการนี้จะเพิ่มผู้ใช้ลงในฐานข้อมูล MySQL ที่มีข้อมูล {"country": "Sri Lanka"}

การแก้ไขข้อมูลจะถูกละเว้น รหัสของฉันที่ใช้ไม่ได้มีดังนี้

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

แทนที่จะต้องผ่านงานที่เจ็บปวดในการคัดลอก JSON ไปยัง dict ใหม่ (ไม่ได้กำหนดให้กับตัวแปรใหม่ตามด้านบน) ซึ่งควรจะได้ผลฉันพบวิธีง่ายๆในการทำเช่นนั้น มีวิธีตั้งค่าสถานะระบบว่า JSON มีการเปลี่ยนแปลง

ต่อไปนี้เป็นรหัสการทำงาน

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

สิ่งนี้ได้ผลเหมือนมีเสน่ห์ มีวิธีอื่นที่เสนอพร้อมกับวิธีนี้ที่นี่ หวังว่าฉันจะช่วยได้บ้าง


2
db.session.merge(user)การเพิ่มรหัสนี้ใช้ได้ผลสำหรับฉัน FYI
Jeff Bluemel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.