84

So, i have a file models.py in MyApp folder:

from django.db import models
class Model_One(models.Model):
    ...
class Model_Two(models.Model):
    ...
...

It can be about 10-15 classes. How to find all models in the MyApp and get their names?

Since models are not iterable, I don't know if this is even possible.

cezar
  • 11,616
  • 6
  • 48
  • 84
Feanor
  • 3,568
  • 5
  • 29
  • 49
  • 7
    @downvoter, want to share why you downvoted? There is nothing wrong with this question (+1 to make balance) – juliomalegria Jan 02 '12 at 15:57
  • 1
    I disagree with the downvote. Grep isn't suitable if you want to know the models at runtime. The get_app and get_models are perfect in that case. – Alasdair Jan 02 '12 at 17:25
  • "know the models at runtime"? What does this mean? – S.Lott Jan 02 '12 at 17:49
  • 3
    @S.Lott That was maybe not the best choice of words. If I want to iterate through an app's models in a view, I think it's preferable to use the `get_app` and `get_models` functions, rather than grepping the source code and hardcoding a list that needs to be maintained. – Alasdair Jan 05 '12 at 19:11
  • @S.Lott, I want to write django admin command to make teammates be able to quickly retreive list of models for any app. Or u can say, u know all models of admin or auth app from Django core? – Feanor Jan 05 '12 at 20:12
  • 2
    okay, Mr. Grammar. It was a short version of "you", every english speaking man can read this. But i will use your advice in future – Feanor Jan 06 '12 at 17:40

8 Answers8

113

From Django 1.7 on, you can use this code, for example in your admin.py to register all models:

from django.apps import apps
from django.contrib import admin
from django.contrib.admin.sites import AlreadyRegistered

app_models = apps.get_app_config('my_app').get_models()
for model in app_models:
    try:
        admin.site.register(model)
    except AlreadyRegistered:
        pass
Sjoerd
  • 74,049
  • 16
  • 131
  • 175
94

UPDATE

for newer versions of Django check Sjoerd answer below

Original answer from 2012: This is the best way to accomplish what you want to do:

from django.db.models import get_app, get_models

app = get_app('my_application_name')
for model in get_models(app):
    # do something with the model

In this example, model is the actual model, so you can do plenty of things with it:

for model in get_models(app):
    new_object = model() # Create an instance of that model
    model.objects.filter(...) # Query the objects of that model
    model._meta.db_table # Get the name of the model in the database
    model._meta.verbose_name # Get a verbose name of the model
    # ...
fzzylogic
  • 2,183
  • 1
  • 19
  • 25
juliomalegria
  • 24,229
  • 14
  • 73
  • 89
  • 13
    Since django 1.7, you should use the new application loading system: `from django.apps import apps` containing these methods. `django.db.models.loading` will be removed in django 1.9. – Ben Feb 17 '15 at 09:58
  • I'm still using django 1.6.x so this answer is useful for me. Question: given a model from get_models, how does one get the name that can be subsequently passed in to get_model(app_name, model_name)? I need this because I want to get the list of all model names as strings in one place, and pass the names in to another piece of code that then call get_model. – Bogatyr Oct 28 '15 at 06:18
37

Best answer I found to get all models from an app:

from django.apps import apps
apps.all_models['<app_name>']  #returns dict with all models you defined
cezar
  • 11,616
  • 6
  • 48
  • 84
pedrotorres
  • 1,222
  • 2
  • 13
  • 26
  • 1
    Use `dict(apps.all_models[''])` should you need to print it, otherwise you would get `OrderedDict()` as a response. – Giampaolo Ferradini May 02 '20 at 01:28
  • @GiampaoloFerradini - I am getting a list like `{'materials': , ...}`. How do I get only the model names (for instance, **Materials**) from the list? – Love Putin Not War Jun 08 '20 at 03:15
  • @user12379095 you do something like e.g. `for k in m_d: print(k)` where `m_d` is your dictionary of the apps models, that you define as `m_d = dict( apps.all_models['your_app_name'] – Giampaolo Ferradini Jun 09 '20 at 13:21
  • @user12379095 if you need the exact model field including caps, you would use `for k in m_d: print(m_d[k].__name__)` (the rest of the code remains the same) – Giampaolo Ferradini Jun 09 '20 at 13:29
  • 1
    @GiampaoloFerradini - Thanks. The way I solved it was to create a pandas dataframe out of the list and then display as html. Thanks again. – Love Putin Not War Jun 09 '20 at 13:30
  • @GiampaoloFerradini - Just now realized that the model names being picked up are in **smallcase** (the way the model names are stored in the DB). Is there a way to pick up the native **Django** name of the models (i.e. as they are defined in models.py)? – Love Putin Not War Jun 11 '20 at 10:25
  • @GiampaoloFerradini - Please check the way I am doing it now (in my answer below). Thanks for all the help. – Love Putin Not War Jun 12 '20 at 06:55
9

Taking off from @pedrotorres solution with some prudent inputs from @GiampaoloFerradini, this is what I am using finally:

from django.apps import apps

app_models = [model.__name__ for model in apps.get_models()] # Returns a "list" of all models created
3

An alternative is to use Content Types.

Each models for each application in INSTALLED_APPS get an entry in the ContentType models. This allow you, for exemple, to have a foreign key to a model.

>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.filter(app_label="auth")
<QuerySet [<ContentType: group>, <ContentType: permission>, <ContentType: user>]>
>>> [ct.model_class() for ct in ContentType.objects.filter(app_label="auth")]
[<class 'django.contrib.auth.models.Group'>, <class 'django.contrib.auth.models.Permission'>, <class 'django.contrib.auth.models.User'>]
gkr
  • 469
  • 7
  • 11
2

Here's a quick-and-dirty, no-coding solution using dumpdata and jq:

python manage.py dumpdata oauth2_provider | jq -r '.[] | .model' | uniq

You could also clean up the jq command to get the format just to your liking.


Bonus: you can see counts of the different types of objects by adding the -c flag to uniq.

mgalgs
  • 15,671
  • 11
  • 61
  • 74
  • @Feanor https://meta.stackexchange.com/questions/121908/i-know-this-question-is-like-two-years-old-but – mgalgs May 19 '17 at 18:54
1

I came here because I want to automatically extract fixtures for every app.

This prints out commands to dump fixtures for all objects in your project. (I have moved my apps within an apps directory.)

from django.apps import apps
from django.conf import settings

print(
    '\n'.join(
        [
            '\n'.join(
                [
                    f'PYTHONPATH=.:apps django-admin dumpdata {app}.{model} --settings=my_project.settings > apps/{app}/fixtures/{model}.json'
                    for model in apps.all_models[app]
                ]
            )
            for app in settings.INSTALLED_APPS
        ]
    )
)

Check you've activated your virtual environment so you're using the right django-admin. (Check with which django-admin.py.)

Only tangentially related to the original question, but might be useful for someone stumbling across this for the same reason I did. I'm on Django 2.2.4, haven't tested it elsewhere.

Chris
  • 5,664
  • 6
  • 44
  • 55
  • 1
    It might be helpful if you indicate what reason you needed it for that is different from the original question. Also, wouldn't you be able to just `from django.conf import settings` and then iterate on `settings.INSTALLED_APPS` instead of having to "copy your app list from your settings file" ? – Rayanth Dec 27 '19 at 01:30
1

For my own use-case that had me stumble on this question, I was looking to see what app a model came from (for use with database router checks and whether to allow relationships, in case of different databases having the same model name).

For my case, it turns out that every model has a meta tag that indicates what app it came from. This may be helpful to others in the same situation.

For example, if a function is passed the model model, the app that defined that model is found in model._meta.app_label as a string. So for a database router, you could declare:

def allow_relation(self, obj1, obj2, **hints):
    """Determine whether to allow ForeignKey relationships between two objects"""
    # if neither object is from MyApp, then this router doesn't care. 
    if 'MyApp' not in [obj1._meta.app_label, obj2._meta.app_label]:
        return None  # None means "no opinion" so other routers can still chime in
    else:
        # at least one object is from MyApp, so allow foreignkey relationships.
        return True
Rayanth
  • 267
  • 2
  • 9
  • It was not until much later that I learned of the limitations or outright inability of doing cross-database relationships, so i've ultimately ditched the premise of the idea -- but the `_meta.app_label` could still be handy in other aspects. – Rayanth Jan 02 '20 at 21:20