Opened 5 years ago
Closed 4 years ago
#30760 closed Bug (duplicate)
Django admin "view on site" button doesn't respect database routers
Reported by: | zooqooo | Owned by: | nobody |
---|---|---|---|
Component: | contrib.contenttypes | Version: | 2.2 |
Severity: | Normal | Keywords: | Admin, Routers |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I'm using the default admin view 'django.contrib.admin'.
Here is an excerpt from my app_1.models.py
Code highlighting:
class SomeModel(models.Model): name = models.CharField(max_length=50) slug_name = models.SlugField(max_length=75, unique=True) #Some more fields def get_absolute_url(self): return reverse("siteSomeModel", kwargs={"slug": self.slug_name})
Here is an excerpt from my site.routers.py
Code highlighting:
class App_1_DataBaseRouter(): label = "app_1" db = "app_1_db" def db_for_read(self, model, **hints): if model._meta.app_label == self.label: return self.db return None def db_for_write(self, model, **hints): if model._meta.app_label == self.label: return self.db return None def allow_relation(self, obj1, obj2, **hints): if obj1._meta.app_label == self.label and obj2._meta.app_label == self.label: return True if self.label not in [obj1._meta.app_label, obj2._meta.app_label]: return None return False def allow_migrate(self, db, app_label, model_name=None, **hints): if app_label == self.label: return db == self.db if db == self.db: return False return None
when I run in the shell it works
>>>python manage.py shell >>>from app_1.models import SomeModel >>>ob=SomeModel.objects.get(name='Some Name') >>>ob.get_absolute_url() app1/SomeModel/some-name
But when I click on view on site in the admin view I get
OperationalError at /admin/r/18/1/ no such table: app_1_SomeModel
And I can see with Django-debug-toolbar that this is because it is connected to the default database instead of app_1_db. I have no other issues with routing in the admin app or elsewhere
Change History (5)
comment:1 by , 5 years ago
Keywords: | Routers added; Router removed |
---|
follow-up: 3 comment:2 by , 5 years ago
Component: | contrib.admin → contrib.contenttypes |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:3 by , 5 years ago
JIC, have you defined the models' admins as stated in https://docs.djangoproject.com/en/2.2/topics/db/multi-db/#exposing-multiple-databases-in-django-s-admin-interface ?
Replying to Simon Charette:
The issue seems to be in
ContentType.get_object_for_this_type
which forces the use ofself._state.db
.
self._state.db
seems good to me as it stores in which database the object is located
I assume your
ContentType
read database is different from yourSomeModel
read one?
It also seems to me that here is where the problem is, because the admin does not support mult-db out of the box.
JIC, @zooqoo, have you defined the models' admins as stated in https://docs.djangoproject.com/en/2.2/topics/db/multi-db/#exposing-multiple-databases-in-django-s-admin-interface ?
comment:4 by , 4 years ago
The root cause of this though, the db forcing in ContentType.get_object_for_this_type( ) effects otehr users of ContentTypes, so its' a content types isses , not really ad admin issue.
The simple fix is to remove the using(), part of the call chain, which was added in for multi db support, but it's not clear , at least to me, why it was considered necessary. This which will work in this case and in the single db case.
Arguably it might cause a problem in some other cases, but in general I can't see ay strong arguments for overriding the db router.
I propose at the least we should have a version of get_object_for_this_type() , and get_alL_objects_for_this_type() which don't include the using clause, however, we may wish to leave the default behaviour as is for backward compatiblity.
Whether that two new functions or we use a kwarg, I don't have s trong opinion myself on.
comment:5 by , 4 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
The issue seems to be in
ContentType.get_object_for_this_type
which forces the use ofself._state.db
.https://github.com/django/django/blob/72ebe85a269aab4bdb3829de4846b41f90973c5d/django/contrib/contenttypes/models.py#L175
I assume your
ContentType
read database is different from yourSomeModel
read one?The
using
call has been around since multi-db support was added in https://github.com/django/django/commit/ff60c5f9de3e8690d1e86f3e9e3f7248a15397c8#diff-90160d336c65903293180fa2d4a55664R102 10 years ago.Not sure how to solve this one because routing and contenttypes issues are tricky but tentatively accepting.