Hello,
This mail is the continuation of this question: https://groups.google.com/forum/#!topic/sqlalchemy/Ba7urbeZBqQ The problem being different, I prefer to open a new topic. I am currently meeting a problem regarding generic associations and the use of MutableList associated to the array type of postgres. I coded two versions of the same case: - the first one uses a generic association. The attribute "text" should be a MutableList but suddenly becomes a "List" during the first commit. The next changes are therefore not longer detected and the data are not actualized in the database - the second example is a classical relationship. In this case, the attribute "text" is a MutableList and don't changes during the commits. Everything works as it should and the data are actualized in the database It will be easier to see the problem with the two examples and their output. The examples are attached. *Example 1 - Generic Association Code (don't works as it should):* Output: >>> Text before commit 1: ['Rex is a', 'good dog...'] Type before commit 1: <class 'sqlalchemy.ext.mutable.MutableList'> Commit 1 Type after commit 1: <class 'list'> We append duck sentence : ['Rex is a', 'good dog...', 'but I prefer ducks.' ] Commit 2 Text after commit 2 : ['Rex is a', 'good dog...'] >>> *Example 2 - Classical relationship (works fine):* Output: >>> Text before commit 1: ['Rex is a', 'good dog...'] Type before commit 1: <class 'sqlalchemy.ext.mutable.MutableList'> Commit 1 Type after commit 1: <class 'sqlalchemy.ext.mutable.MutableList'> We append duck sentence : ['Rex is a', 'good dog...', 'but I prefer ducks.' ] Commit 2 Text after commit 2 : ['Rex is a', 'good dog...', 'but I prefer ducks.'] >>> I don't know if it helps but I noticed that the __init__ method of the class Description doesn't have exactly the same behavior in the two examples: - in the Generic Association Code example, the "self.text = MutableList()" in the __init__ method of the class Description is not really important. It could also be "self.text = []" instead. In all cases, text is a MutableList. - in the Classical relationship example, if the __init__ method of the class Description contains "self.text = MutableList()", the attribute text will be a MutableList and if the __init__ method contains "self.text = []", it will be a List. Does someone have an explanation ? Thank you ! -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import as_declarative, declared_attr from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.dialects import postgresql from sqlalchemy.ext.mutable import MutableList @as_declarative() class Base(object): """Base class which provides automated table name and surrogate primary key column. """ @declared_attr def __tablename__(cls): return cls.__name__.lower() id = Column(Integer, primary_key=True) class Description(Base): text = Column(MutableList.as_mutable(postgresql.ARRAY(String)), nullable = False) parent_id = Column(Integer, ForeignKey('animal.id')) parent = relationship("Animal", back_populates="description") def __init__(self, name): self.text = MutableList() self.text.append(name) def __repr__(self): return self.text class Animal(Base): name = Column(String) description = relationship("Description", uselist=False, back_populates="parent") def __init__(self, name): self.name = name engine = create_engine('postgresql://LOGIN:PASSWORD@localhost/DATABASE_NAME') Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() rex = Animal("Rex") d1 = Description("Rex is a") session.add(rex) session.add(d1) rex.description = d1 rex.description.text.append("good dog...") print("Text before commit 1: ", rex.description.text) print("Type before commit 1: ", type(rex.description.text)) print("Commit 1") session.commit() print("Type after commit 1: ", type(rex.description.text)) print("We append duck sentence : ", rex.description.text) rex.description.text.append("but I prefer ducks.") print("Commit 2") session.commit() print("Text after commit 2 : ", rex.description.text)
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import as_declarative, declared_attr from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.dialects import postgresql from sqlalchemy.ext.mutable import MutableList @as_declarative() class Base(object): """Base class which provides automated table name and surrogate primary key column. """ @declared_attr def __tablename__(cls): return cls.__name__.lower() id = Column(Integer, primary_key=True) class Description(): text = Column(MutableList.as_mutable(postgresql.ARRAY(String)), nullable = False) def __init__(self, text): self.text = MutableList() self.text.append(text) def __repr__(self): return self.text class HasDescription(object): @declared_attr def description(cls): cls.Description = type( "%sDescription" % cls.__name__, (Description, Base,), dict( __tablename__="%s_description" % cls.__tablename__, parent_id=Column(Integer, ForeignKey("%s.id" % cls.__tablename__)), parent=relationship(cls, back_populates="description") ) ) return relationship(cls.Description, uselist=False, back_populates="parent") class Animal(HasDescription, Base): name = Column(String) def __init__(self, name): self.name = name engine = create_engine('postgresql://LOGIN:PASSWORD@localhost/DATABASE_NAME') Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() rex = Animal("Rex") d1 = Animal.Description("Rex is a") session.add(rex) session.add(d1) rex.description = d1 rex.description.text.append("good dog...") print("Text before commit 1: ", rex.description.text) print("Type before commit 1: ", type(rex.description.text)) print("Commit 1") session.commit() print("Type after commit 1: ", type(rex.description.text)) print("We append duck sentence : ", rex.description.text) rex.description.text.append("but I prefer ducks.") print("Commit 2") session.commit() print("Text after commit 2 : ", rex.description.text)