1

Consider the following SQLAlchemy code

class Foo(Base):
    __tablename__ = 'currency'

    id = Column(Integer, primary_key=True)
    name = Column(String(40), nullable=False, unique=True)
    symbol = Column(String(4), nullable=False, unique=True)

    l =  session.query(Foo.symbol, Foo.id).all()

In the last line, I am trying to generate a list of the symbol-id pairs. It produces the following error:

NameError: name 'Foo' is not defined

I tried the following and got the errors as specified:

l = session.query(models.Foo.symbol, models.Foo.id).all()
#note: The Foo object is in the models.py file
#error: NameError: name 'models' is not defined

l = session.query(symbol, id).all()
#error: sqlalchemy.exc.CompileError: Cannot compile Column object until its 'name' is assigned.

l = session.query(self.symbol, self.id).all()
#error: NameError: name 'self' is not defined

So how do I pass in Foo object's column names to the SqlAlhemy query from inside the Foo class?

Why am I doing this? I am then converting the list to a dictionary and only access the dictionary from code throughout the program since its values are seldom changed. So I want to populate it once and then access it many many times without hitting the DB again. And I want to keep it in the Foo Class which I believe is where it belongs.

If there is a better way to do this please do let me know.

10
  • 4
    Don't do this, because it will cause a query at import time. Commented Feb 23, 2018 at 0:22
  • Btw those aren't just normal class attributes, they're descriptors for the ORM. Commented Feb 23, 2018 at 0:25
  • @wim I think that would be fine. Because I am then converting the list to a dictionary and only access the dictionary from code throughout the program since its values are seldom changed. So I want to populate it once and then access it many many times without hitting the DB again. Commented Feb 23, 2018 at 0:25
  • @wim so how do I access these descriptors from within the class? I am trying to encapsulate all the Foo stuff inside Foo and not have them spread all over the place. Commented Feb 23, 2018 at 0:28
  • Well you can't do it like this, because the class doesn't exist yet. Suppose you add another row to the currency table, how do you want Foo.l to be updated? Magic? Commented Feb 23, 2018 at 0:30

1 Answer 1

1

You can't use the class before it has been defined. And you can't use symbol and id yet, even though the names can be correctly resolved from within the class block itself, because the ORM hasn't had a chance to prepare the columns yet. This is one of tasks of declarative Base, and Foo will inherit a metaclass which needs to prepare the model.

Assuming you set up the session correctly, you should be able to dynamically contribute this attribute on the class outside of the class definition block:

class Foo(Base):
    __tablename__ = 'currency'

    id = Column(Integer, primary_key=True)
    name = Column(String(40), nullable=False, unique=True)
    symbol = Column(String(4), nullable=False, unique=True)

Foo.l =  session.query(Foo.symbol, Foo.id).all()
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer and thanks for trying to make sure I was not shooting myself in the foot by this design. This pattern is only useful for very specific data and as you suggested, should generally be avoided. I have implemented as you suggest. Will leave the question open for a few days just to see if others might contribute alternatives.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.