18

After a database is constructed in SQLAlchemy, I want to get all of the models, which is to say, the classes which represent them

>>> db
<SQLAlchemy engine='postgresql:///example'>
>>> ???
[<db.Model 'User'>, <db.Model 'Comment'>, <db.Model 'Article'>]

Can this be achieved? How?

I can get the tables decently, just not the models. Eg:

>>> for t in db.metadata.tables.items():
 print(t)

this gives the tables just not the models themselves

asked Oct 22, 2014 at 18:46

6 Answers 6

14

There are several related questions, but I didn't see any exact duplicates.

Using your code to get the table names, and this question's accepted answer to get the classes, we can match the classes to the tablenames that are registered on your database.

classes, models, table_names = [], [], []
for clazz in db.Model._decl_class_registry.values():
 try:
 table_names.append(clazz.__tablename__)
 classes.append(clazz)
 except:
 pass
for table in db.metadata.tables.items():
 if table[0] in table_names:
 models.append(classes[table_names.index(table[0])])

Where models is the list of models registed on your database.

The try catch is required because a <sqlalchemy.ext.declarative.clsregistry._ModuleMarker object> will be included in the for clazz in ... loop, and it doesn't have a __tablename__ attribute.

answered Oct 22, 2014 at 22:45
Sign up to request clarification or add additional context in comments.

Comments

11

If you only need the classes, there is an simpler solution. I came up with it based on Celeo’s answer:

from flask import current_app
# This is to be generic (ie. no need to pass your actual SQLAlchemy instance)
# This way you can include it even in your own extension.
db = current_app.extensions['sqlalchemy'].db
[cls for cls in db.Model._decl_class_registry.values()
 if isinstance(cls, type) and issubclass(cls, db.Model)]

This doesn’t need all those extra helper variables, just queries the class registry, and filters out everything that is not a model.

answered Jun 20, 2017 at 11:10

Comments

11

In SQLAlchemy 1.4, the _decl_class_registry.values() method has removed, you can use db.Model.registry.mappers instead:

models = {
 mapper.class_.__name__: mapper.class_
 for mapper in db.Model.registry.mappers
}

See the details in this issue.

answered Jun 1, 2021 at 10:45

Comments

0

this works in my case: slightly shorter; more readable

models = []
for name, thing in db_table_creation.__dict__.iteritems():
 if isinstance(thing, sqlalchemy.ext.declarative.DeclarativeMeta) and hasattr(thing, '__tablename__'):
 models.append(thing)
answered Sep 7, 2015 at 17:57

where'd db_table_creation come from
0

Here is my variation of Celeo’s answer with typing and succinct intermediary steps:

from ??? import db # Import from wherever you have this, or use GergelyPolonkai's method to get a db object.
from typing import List, Dict, Union
from flask_sqlalchemy import DefaultMeta
from sqlalchemy.ext.declarative.clsregistry import _ModuleMarker
registered_classes: List[Union[DefaultMeta, _ModuleMarker]] = \
 [x for x in db.Model._decl_class_registry.values()]
registered_models: List[DefaultMeta] = \
 [x for x in registered_classes if isinstance(x, DefaultMeta)]
tables: List[DefaultMeta] = \
 [x for x in registered_models if hasattr(x, '__tablename__')]
answered Apr 16, 2019 at 19:32

Comments

0

A simple way to do is:

import inspect
import mymodels
for name, obj in inspect.getmembers(mymodels):
 if inspect.isclass(obj) and hasattr(obj, '__tablename__'):
 print("model: %s %s"%(name,obj))
answered Jun 21, 2023 at 23:13

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.