Reputation: 5417
I'm just two days into learning SQLAlchemy, and have a question regarding mapping of column names. First off, the following statement in the official docs threw me off balance:
Matching columns on name works for simple cases but can become unwieldy when dealing with complex statements that contain duplicate column names or when using anonymized ORM constructs that don’t easily match to specific names. Additionally, there is typing behavior present in our mapped columns that we might find necessary when handling result rows.
Ugh, what?! An example or two of what this paragraph is trying to say would have been great, but never mind; it's a task for another day.
I kind of understood that sometimes the field list generated by our query will not map perfectly with the model, so we can specify expected columns positionally. This got me trying to think up an example where this mapping might be useful. So I thought, how about selecting a column from the table that is calculated on the fly? I simulated this in a sqlite
database using the random()
function like this:
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
password = Column(String)
def __repr__(self):
return "User<name={}, fullname={}, password={}>".format(self.name, self.fullname, self.password)
# Create all tables
Base.metadata.create_all(engine)
ed_user = User(name='ed', fullname='Ed Jones', password='edspassword')
session.add(ed_user)
session.add_all([
User(name='wendy', fullname='Wendy Williams', password='foobar'),
User(name='mary', fullname='Mary Contrary', password='xxg527'),
User(name='fred', fullname='Fred Flinstone', password='blah')
])
session.commit()
stmt = text("SELECT name, id, fullname, random() FROM users WHERE name=:name")
stmt = stmt.columns(User.name, User.id, User.fullname ...
Now what? I can't write a column name because none exists, and I can't add it to the model definition because this column will be created unnecessarily. All I wanted to get some extra information from the database (like NOW()
) that I can use in code.
How can this be done?
Upvotes: 1
Views: 5146
Reputation: 690
Try explicitly listing column
objects. This way "random()" can be any arbitrary SQL calculated column...
# You may have already imported column, but for completeness:
from sqlalchemy import column
# As an example:
find_name = 'wendy'
stmt = text("SELECT name, id, fullname, (random()) as random_value FROM users WHERE name=:name")
stmt = stmt.columns(column('name'), column('id'), column('fullname'), column('random_value'))
users = session.query(column('name'), column('id'), column('fullname'), column('random_value')).from_statement(stmt).params(name = find_name)
for user in users:
print(user.id, user.name, user.fullname, user.random_value)
Upvotes: 1
Reputation: 5417
All right, so I seem to have figured this out myself (damn, that's twice in a day! The SQLAlchemy community here seems dead, which is forcing me to search for answers myself ... not a very bad thing, though!). Here's how I did it:
from sqlalchemy import func
session.query(User.name, User.id, User.fullname, func.current_timestamp()).filter(User.name=='ed').all()
Upvotes: -1
Reputation: 15120
You can use column labels
from sqlalchemy import func
users = session.query(User.id, User.name, User.fullname, func.random().label('random_value'))
for user in users:
print(user.id, user.name, user.fullname, user.random_value)
Upvotes: 2