pythondjangopython-3.xdjango-models

Django admin.site.register throws TypeError for models class


This is a follow-on question to this question.

I would like to automate the import of classes from a django models.py file and then register each with admin.site.register(). Here is my code:

from django.contrib import admin
import inspect
from . import models 

for name, obj in inspect.getmembers(models):
    if inspect.isclass(obj):
        admin.site.register(obj)

This code throws a TypeError: 'type' object is not iterable.

The OP marked this question as answered and I've found several other examples where this code is presented. I've also reviewed the documentation here and didn't see anything that would indicate that this is wrong.

Full Traceback:

Bills-MacBook-Pro:Pro billarmstrong$ python manage.py runserver/anaconda3/lib/python3.6/site-packages/django/db/models/base.py:309:RuntimeWarning: Model 'ProWP.p_item' was already registered. Reloading models is not advised as it can lead to inconsistencies, most notably with related models.  new_class._meta.apps.register_model(new_class._meta.app_label, new_class)/anaconda3/lib/python3.6/site-packages/django/db/models/base.py:309:RuntimeWarning: Model 'ProWP.p_item' was already registered. Reloading models is not advised as it can lead to inconsistencies, most notably with related models.
  new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0x108f1dea0>
Traceback (most recent call last):
  File "/anaconda3/lib/python3.6/site-packages/django/utils/autoreload.py", line 225, in wrapper
    fn(*args, **kwargs)
  File "/anaconda3/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 112, in inner_run
    autoreload.raise_last_exception()
  File "/anaconda3/lib/python3.6/site-packages/django/utils/autoreload.py", line 248, in raise_last_exception
    raise _exception[1]
  File "/anaconda3/lib/python3.6/site-packages/django/core/management/__init__.py", line 327, in execute
    autoreload.check_errors(django.setup)()
  File "/anaconda3/lib/python3.6/site-packages/django/utils/autoreload.py", line 225, in wrapper
    fn(*args, **kwargs)
  File "/anaconda3/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/anaconda3/lib/python3.6/site-packages/django/apps/registry.py", line 120, in populate
    app_config.ready()
  File "/anaconda3/lib/python3.6/site-packages/django/contrib/admin/apps.py", line 23, in ready
    self.module.autodiscover()
  File "/anaconda3/lib/python3.6/site-packages/django/contrib/admin/__init__.py", line 26, in autodiscover
    autodiscover_modules('admin', register_to=site)
  File "/anaconda3/lib/python3.6/site-packages/django/utils/module_loading.py", line 47, in autodiscover_modules
    import_module('%s.%s' % (app_config.name, module_to_search))
  File "/anaconda3/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/billarmstrong/Documents/GitHub/Core/WebDataCollect/Pro/ProWP/admin.py", line 7, in <module>
    admin.site.register(obj)
  File "/anaconda3/lib/python3.6/site-packages/django/contrib/admin/sites.py", line 102, in register
    for model in model_or_iterable:
TypeError: 'type' object is not iterable

After runserver a second time there is a new warning - but that wasn't part of the original error. I included everything for reference. The p_item is a class object in models.py

Final Edit

The warning noted above was a result of a sloppy cut/paste that duplicated a class. It is irrelevant to the original question or the answer below.


Solution

  • At a guess, there are not only django.db.models.Model classes imported. Probably, your local models module contains a few more items, including other classes (which makes the if inspect.isclass pass). You may want to perform an additional issubclass(obj, django.models.Model) or similar check.

    The fact that it works in the linked question, suggests you have additional code in your local models.py module, possibly through from imports (making it hard to notice). But an additional check to see that obj is an actual Django model (as mentioned above), is probably safer than trying to remove that extra code.

    All in all, try the following (untested):

    from django.contrib import admin
    from django.db.models import Model
    import inspect
    from . import models 
    
    for name, obj in inspect.getmembers(models):
        if inspect.isclass(obj) and issubclass(obj, Model):
            admin.site.register(obj)