1

I know an easy way to get all proper SQLA columns from a class A (that inherits from db.Model) - I can do A.__table__.columns at runtime. However, A also has several association proxies, and I don't know of an elegant way to get a list of those (other than just running on all of the class' attributes). Is there maybe a way to use SQLA's inspect for this?

I'm using python 2.7 and Flask-SQLAlchemy.

mcouthon
  • 140
  • 7

1 Answers1

3

There is a way using the runtime inspection API. With it you wouldn't even need to poke at the internals of A through __table__:

from sqlalchemy import inspect

inspect(A).columns

For a list of association proxies you could for example do

from sqlalchemy.ext.associationproxy import AssociationProxyExtensionType

proxies = [desc for desc in inspect(A).all_orm_descriptors
           if desc.extension_type is AssociationProxyExtensionType.ASSOCIATION_PROXY]

all_orm_descriptors is a collection of InspectionAttr attributes, which includes mapped attributes as well as attributes declared by extensions. To differentiate between extensions, and non-extensions, inspect the InspectionAttr.extension_type constant attribute.

Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
  • @everilae Thanks, that helped a lot! I wasn't familiar with `all_orm_descriptors`. One thing, however, that I had to work around was the fact that the association proxy objects returned from the inspection were partial. I couldn't access most of their attributes (like `remote_attr` or `local_attr`), as I'd get an error stating that: `Class object expected, got 'None'.` I worked around it by getting the name of the proxy, and then using `getattr`. Any further suggestions maybe? – mcouthon Jan 16 '17 at 10:39
  • 1
    The error is raised if you try to access `attr`, `remote_attr`, or `local_attr` of the `AssociationProxy` [descriptor object](https://docs.python.org/3/howto/descriptor.html) before you've first accessed it through the model class or an instance. Descriptors don't get a reference to the class they are bound to during class construction. Instead the class and possible instance are passed to `__get__` method of the descriptor when accessed, like doing `the_proxy.__get__(None, A)`. The `AssociationProxy` instance seems to store a reference on 1st call, after which you can access the `attr` etc. – Ilja Everilä Jan 16 '17 at 11:04
  • See [Invoking Descriptors](https://docs.python.org/3/howto/descriptor.html#invoking-descriptors) for further details about how they do their thing. – Ilja Everilä Jan 16 '17 at 11:07
  • Thanks for another clarification! I ended up doing what you've suggested - calling `desc.__get__(None, cls)`, and this seems to work fine. – mcouthon Jan 16 '17 at 11:16