#14948 closed (fixed)
Broken routers in 1.2.4: type object 'ModelBase' has no attribute '_meta'
| Reported by: | shell_dweller | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.2 |
| Severity: | Keywords: | router, ManyToManyField, blocker, regression | |
| Cc: | s.kuzmenko@…, django@…, fwenzel@…, james@…, conrad666@…, typeshige@…, brian@…, django@…, hgeerts@… | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | yes |
| Easy pickings: | no | UI/UX: | no |
Description
There is a problem with using routers in the latest security release 1.2.4. The details are somewhat murky for a lay person but here's the gist of it:
- The site has a routing scheme setup as described in http://docs.djangoproject.com/en/1.2/topics/db/multi-db/#using-routers
- Attempt to save any model with a ManyToManyField fails in router when trying to execute db_for_write:
def db_for_write(self, model, **hints):
if model._meta.app_label == 'my_app_label':
return 'my_db_name'
return None
Error message is "type object 'ModelBase' has no attribute '_meta'".
It seems that the error occurs in django/db/models/fields/related.py, line 624 where self.through.__class__ returns ModelBase whereas prior to 1.2.4 it used to be a user defined class.
Here's the stack trace:
[ snip ]
File "/usr/lib/python2.4/site-packages/django/forms/models.py", line 375, in save
fail_message, commit, construct=False)
File "/usr/lib/python2.4/site-packages/django/forms/models.py", line 87, in save_instance
save_m2m()
File "/usr/lib/python2.4/site-packages/django/forms/models.py", line 83, in save_m2m
f.save_form_data(instance, cleaned_data[f.name])
File "/usr/lib/python2.4/site-packages/django/db/models/fields/related.py", line 1144, in save_form_data
setattr(instance, self.attname, data)
File "/usr/lib/python2.4/site-packages/django/db/models/fields/related.py", line 730, in __set__
manager.clear()
File "/usr/lib/python2.4/site-packages/django/db/models/fields/related.py", line 506, in clear
self._clear_items(self.source_field_name)
File "/usr/lib/python2.4/site-packages/django/db/models/fields/related.py", line 624, in _clear_items
db = router.db_for_write(self.through.__class__, instance=self.instance)
File "/usr/lib/python2.4/site-packages/django/db/utils.py", line 134, in _route_db
chosen_db = method(model, **hints)
File "/path/to/my/app/routers.py", line 10, in db_for_write
if model._meta.app_label == 'my_label':
AttributeError: type object 'ModelBase' has no attribute '_meta'
Attachments (3)
Change History (24)
comment:1 by , 15 years ago
| Cc: | added |
|---|
comment:2 by , 15 years ago
(assuming you have created a registered a router that uses "model._meta.object_name", of course)
comment:3 by , 15 years ago
| Cc: | added |
|---|
I can confirm this. A simple workaround would probably be to catch this in the router, but this would be a duct-tape fix.
comment:4 by , 15 years ago
| Cc: | added |
|---|
comment:5 by , 15 years ago
| Cc: | added |
|---|
comment:6 by , 15 years ago
| Cc: | added |
|---|
comment:7 by , 15 years ago
| milestone: | → 1.3 |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
Ok - this is a pretty major regression.
comment:8 by , 15 years ago
| Cc: | added |
|---|
comment:9 by , 15 years ago
| Keywords: | blocker regression added |
|---|
comment:11 by , 15 years ago
| Cc: | added |
|---|
follow-up: 13 comment:12 by , 15 years ago
This bug broke my site when I upgraded to 1.2.4, forcing me to roll back to 1.2.1 (after being deluged hundreds of errors in a few minutes). I am surprised more people haven't spoken up. Thanks for the hard work.
comment:13 by , 15 years ago
Replying to intrepidweb:
This bug broke my site when I upgraded to 1.2.4, forcing me to roll back to 1.2.1 (after being deluged hundreds of errors in a few minutes). I am surprised more people haven't spoken up. Thanks for the hard work.
You should be able to at least upgrade to 1.2.3 without encountering this problem.
comment:14 by , 15 years ago
The router check on rel.through may have been broken for some time but was hidden because the ConnectionRouter catched it's AttributeError
We can thank the following ticket for showing us this bug: http://code.djangoproject.com/ticket/14870
The patch cannot be reverted since the router call is broken and needs to be fixed.
On my project the error was raised in a different code path.
File "/home/harm/django12/django/core/management/commands/loaddata.py", line 174, in handle
obj.save(using=using)
File "/home/harm/django12/django/core/serializers/base.py", line 168, in save
setattr(self.object, accessor_name, object_list)
File "/home/harm/django12/django/db/models/fields/related.py", line 730, in __set__
manager.clear()
File "/home/harm/django12/django/db/models/fields/related.py", line 506, in clear
self._clear_items(self.source_field_name)
File "/home/harm/django12/django/db/models/fields/related.py", line 624, in _clear_items
db = router.db_for_write(self.through.__class__, instance=self.instance)
File "/home/harm/django12/django/db/utils.py", line 134, in _route_db
chosen_db = method(model, **hints)
File "/home/harm/lascon/lascon/router.py", line 18, in db_for_write
if model._meta.app_label == 'exact' and model._meta.object_name != 'ExactProfile':
AttributeError: type object 'ModelBase' has no attribute '_meta'
comment:15 by , 15 years ago
| Cc: | added |
|---|
by , 15 years ago
| Attachment: | django-1.2-router_related_accessor.patch added |
|---|
patch with testcase for django-1.2, trunk will need to be patched as well
comment:16 by , 15 years ago
| Has patch: | set |
|---|
comment:17 by , 15 years ago
comment:18 by , 15 years ago
| Patch needs improvement: | set |
|---|
Actually the fix for #13668 is a subset of the fixes proposed here. What would be needed to close this ticket is a test case for the django/db/models/base.py modifications, currently the tests proposed in the patch attached to this ticket, passes irrespective of if the changes to that file are present.
by , 15 years ago
| Attachment: | 14948-1.2.X-r15186.diff added |
|---|
Patch by Harm Geerts updated to 1.2.x banch status as of now
by , 15 years ago
| Attachment: | django-1.2-router_related_accessor-2.patch added |
|---|
new patch based on changes from #13668 with tests to cover changes in django.db.models.base
comment:19 by , 15 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
(In [15207]) [1.2.X] Fixed #14948 -- Fixed a couple of cases where invalid model classes were passed to the database router when collecting reverse foreign key and many to many relationships. Thanks shell_dweller for the report and Harm Geerts for the patch.
This also enhances tests added in r15186.
Code in SVN trunk doesn't suffer from this problem because it was refactored in r14507.
Same problem here - an easy way to reproduce:
bash-3.2$ ./manage.py shell Python 2.5.4 (r254:67917, Dec 23 2008, 14:57:27) [GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from django.contrib.auth.models import User >>> user = User() >>> user.username = "testuser" >>> user.save() >>> user.delete() Traceback (most recent call last): File "<console>", line 1, in <module> File "/path/to//django/db/models/base.py", line 660, in delete self._collect_sub_objects(seen_objs) File "/path/to//django/db/models/base.py", line 625, in _collect_sub_objects db = router.db_for_write(f.rel.through.__class__, instance=self) File "/path/to//django/db/utils.py", line 134, in _route_db chosen_db = method(model, **hints) File "/path/to/my/app/routers.py", line 35, in db_for_write object_name = model._meta.object_name AttributeError: type object 'ModelBase' has no attribute '_meta' >>>