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)

Reply via email to