Scenario: I’m writing unit tests for an API. (Which, wooooo tests.)

For ~reasons~, one of the test functions needs to loop over a list of the app’s model classes – but only the ones that get imported into views.py for inclusion in a viewset.

Why not just hard-code the list into the test case, I hear you asking. Sure, I could do that, I’ve done worse things in my life.* But then I found the Python standard library’s inspect function.

Some just furious Googling and a bit of shell-tinkering later, I had a two-step process outlined:

  1. Using inspect.getmembers(), fetch a list of objects in my_cool_app/views.py, passing inspect.isclass as the predicate argument to return only classes.
  2. Filter out anything that isn't an instance of the django.db.models.base.ModelBase class. (I used a list comprehension.)

Off to the races:

# from tests.py
import my_cool_app.views as mcp_views
import inspect
from django.db.models.base import ModelBase as django_mb

# inspect.getmembers() returns a tuple --> we want [1]
models_to_test = [x[1] for x in inspect.getmembers(mcp_views, inspect.isclass) if isinstance(x[1], django_mb)]

# bang bang, y'all
for my_cool_model in models_to_test:
    qs = my_cool_model.objects.all()
    # test test test
    # test test test
    # test? test!
    # (spoiler, tests all passed)

Further reading:

*You have no idea.