Stright
Stright

Reputation: 47

Why does the attribute 'name' of the sqlalchemy.Column instance disappear?

I'm writing the history of attribute changes for sqlalchemy models. Attributes list, which are important for history, I keep in the class attribute history_attributes.

from sqlalchemy import Integer, Column, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class HistoryAttribute:
    def __init__(self, descriptor, display_name, use_message=False):
        self.name = descriptor.name
        self.display_name = display_name
        self.use_message = use_message
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    first_name = Column(String(100))
    email = Column(String(100))
    history_attributes = (
        HistoryAttribute(descriptor=first_name, display_name='User name'),
        email
    )

print(User.history_attributes[0].name)
>>> None
print(User.history_attributes[1].name)
>>> email

Why does the attribute "name" of the Column instance disappear, if I pass one to constructor of other class? Of course, I can write first_name = Column('first_name', String(100) and code will work fine, but I don't want to add Column.name explicitly. I avoided the problem using namedtuple, which I then pass to the constructor of the HistoryAttribute class, but it's very similar to a crutch.

Upvotes: 1

Views: 202

Answers (2)

Sam Hartman
Sam Hartman

Reputation: 6489

As has been discussed, the issue is that first_name.name is set while the class is being constructed. SQLAlchemy does have a mechanism for deferring an attribute definition until configuration time. Try something like class User(Base): # ... @sqlalchemy.ext.declarative.api.declared_attr def history_attributes(self): return (HistoryAttribute(self.first_name #...))

That will defer the construction of history_attributes until a point where column names are populated

Upvotes: 1

univerio
univerio

Reputation: 20508

It's not that the name attribute disappears, but that it hasn't been initialized yet. Look at the value of first_name as passed to HistoryAttribute: Column(String(100)); it does not contain any mention of the string first_name. SQLAlchemy will fill the name in later after the class is defined.

Upvotes: 3

Related Questions