4 votes

Utilisation de inspect pour obtenir l'historique des relations d'un modèle

Je suis capable d'utiliser la fonction inspect de sqlalchemy pour trouver l'historique d'un modèle spécifique, pour toute valeur normale. Cependant, lorsque je tente d'obtenir l'historique d'une relation (ou de la colonne ForeignKey qui lui est associée), seule la nouvelle valeur est affichée, et non la valeur précédente.

Existe-t-il un moyen rapide d'obtenir la valeur précédente d'une relation comme celle-ci, ou dois-je utiliser une autre fonction ou créer ma propre fonction ?

Le code de base que j'utilise ressemble à

class Person(db.Model):
  id = db.Column(db.Integer(), primary_key=True)
  name = db.Column(db.String(80))
  phone_id = db.Column(db.Integer(), db.ForeignKey("phone_number.id"))
  phone = db.relationship("PhoneNumber")
class PhoneNumber(db.Model):
  id = db.Column(db.Integer(), primary_key = True)
  type = db.Column(db.String(20))
  number = db.Column(db.String(11))

p = Person()
p.name = "Frank"
phone1 = PhoneNumber("Mobile", "1234567890") #__init__ function handles these args
phone2 = PhoneNumber("Home", "9876543210")
p.phone = phone1
db.session.add_all([p, phone1, phone2])
db.session.commit()
p.phone = phone2
history = db.inspect(p).attrs.get("phone").history
# history is sqlalchemy.orm.attributes.History(([<PhoneNumber('Home', '9876543210')>], (), ()))
# history.added is ([<PhoneNumber('Home', '9876543210')>])
# history.deleted is () but should be ([<PhoneNumber('Mobile', '1234567890')>])

5voto

zzzeek Points 22617

L'"ancienne" valeur d'un attribut scalaire n'est généralement pas chargée depuis la base de données si elle n'est pas déjà présente, car cela constitue un gaspillage (dans ce cas, session.commit() fait expirer tous les attributs, de sorte que Person.phone est déchargé lorsque la nouvelle valeur est attribuée). Il existe des exceptions, notamment lorsque la colonne est une colonne de clé primaire, ou pour une relation scalaire autre qu'une simple relation many-to-one. Ce chargement de l'"ancienne" valeur peut être forcé en utilisant l'option "active_history" sur l'attribut en question.

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer(), primary_key=True)
    name = Column(String(80))
    phone_id = Column(Integer(), ForeignKey("phone_number.id"))
    phone = relationship("PhoneNumber", active_history=True)

class PhoneNumber(Base):
    __tablename__ = 'phone_number'
    id = Column(Integer(), primary_key=True)
    type = Column(String(20))
    number = Column(String(11))

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

session = Session(e)

p = Person()
p.name = "Frank"
phone1 = PhoneNumber(type="Mobile", number="1234567890")
phone2 = PhoneNumber(type="Home", number="9876543210")
p.phone = phone1
session.add_all([p, phone1, phone2])
session.commit()
p.phone = phone2
history = inspect(p).attrs.get("phone").history

assert history == ([phone2], (), [phone1])

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X