#26686 closed Bug (fixed)
django.core.checks.model_checks _check_lazy_references raises TypeError with NoneType model_key
| Reported by: | Brett Haydon | Owned by: | nobody |
|---|---|---|---|
| Component: | Core (System checks) | Version: | 1.10 |
| Severity: | Release blocker | Keywords: | |
| Cc: | Alex Hill | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Steps for reproduction
Create poll app or any model
inherit model from django-model-utils model_utils.models.TimeStampedModel
./manage.py makemigrations
In the model import process (None, 'statusmodel') erroneously gets added to the django.core.registry.App._pending_operations. StatusModel is a model in model_utils.models but is not imported into the poll app.
django.core.checks.model_checks._check_lazy_references iterates over the model_key in _pending_operations but can't handle a model_key of NoneType so raises the TypeError.
Being a defaultdict _pending_operations seems the point of weakness here.
Attachments (1)
Change History (8)
comment:1 by , 9 years ago
by , 9 years ago
| Attachment: | django-typeerror.zip added |
|---|
comment:2 by , 9 years ago
Attached my throwaway project. model-utils isn't in installed apps (it doesn't need to be)
pip install django-model-utils (and django 1.10a).
./manage.py makemigrations demoapp
Traceback (most recent call last):
File "./manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
utility.execute()
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/management/__init__.py", line 359, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/management/base.py", line 305, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/management/base.py", line 353, in execute
self.check()
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/management/base.py", line 385, in check
include_deployment_checks=include_deployment_checks,
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/management/base.py", line 372, in _run_checks
return checks.run_checks(**kwargs)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/checks/registry.py", line 81, in run_checks
new_errors = check(app_configs=app_configs)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/checks/model_checks.py", line 156, in check_lazy_references
return _check_lazy_references(apps)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/checks/model_checks.py", line 151, in _check_lazy_references
)), key=lambda error: error.msg)
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/checks/model_checks.py", line 150, in <genexpr>
for func in apps._pending_operations[model_key]
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/checks/model_checks.py", line 145, in build_error
return error_fn(model_key, func, args, keywords) if error_fn else None
File "/Users/bretth/projects/_virtualenvs/django-typeerror/lib/python3.5/site-packages/django/core/checks/model_checks.py", line 117, in signal_connect_error
'model': '.'.join(model_key or ''),
TypeError: sequence item 0: expected str instance, NoneType found
comment:3 by , 9 years ago
| Cc: | added |
|---|---|
| Severity: | Normal → Release blocker |
| Triage Stage: | Unreviewed → Accepted |
Obviously it would be better not to crash, however, isn't it a requirement to put model_utils in INSTALLED_APPS if you want to use any models from it?
After doing that with the sample project, this error is reported, model_utils.fields: (signals.E001) Bound method 'MonitorField._save_initial' was connected to the 'post_init' signal with a lazy reference to the sender 'model_utils.statusmodel', but app 'model_utils' doesn't provide model 'statusmodel'. I'm not sure if it's correct -- the model is there, although it's abstract (no problems with Django 1.9).
comment:4 by , 9 years ago
If you're only using abstract models, you shouldn't need to add to INSTALLED_APPS. This is explicitly allowed in models/base.py
I've found a bug in ModelSignal. It contains a conditional branch for senders of type Model, but it should be checking for BaseModel, since model signals are used with classes, not instances. Fixing that fixes this problem.
The long version of what's happening is:
- _lazy_model_operation works by waiting for models to be registered
- abstract models are never registered with the app registry, so their operations will remain forever pending
- StatusModel is abstract, and has a MonitorField
- MonitorField connects to the `post_init` signal in its `contribute_to_class()` method
- signals use _lazy_model_operation as of 1.10
- the bug means _lazy_model_operation is used by the
post_initsignal even when a model class is provided, not a string.
Incidentally, we currently happily register model signals with abstract senders even though they'll never be sent. Since perfectly reasonable code like the linked code in django-model-utils does this, I don't think a warning is appropriate. I think we should just ignore them explicitly in ModelSignal and document that behaviour. Thoughts?
comment:5 by , 9 years ago
| Has patch: | set |
|---|
Pull request at https://github.com/django/django/pull/6678
Do you have
model_utilsinINSTALLED_APPS? Could you upload the minimal project to reproduce?