[Django] #32965: Django related manager allways choose db_for_read router and fail update/delete

42 views
Skip to first unread message

Django

unread,
Jul 27, 2021, 5:55:44 AM7/27/21
to django-...@googlegroups.com
#32965: Django related manager allways choose db_for_read router and fail
update/delete
-------------------------------------+-------------------------------------
Reporter: Regressor | Owner: nobody
Type: Bug | Status: new
Component: Database | Version: 3.1
layer (models, ORM) | Keywords: related manager,
Severity: Normal | db_for_read, exception, db, router
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
We have a large project running django 3.1.12. It is use aws aurora rds
cluster for database and we tried to take most of it. Wee need to use read
replicas to be able fast db overload response. So we made routers, started
multiple db config, fixed number read replica lag issues and finally got
error "cannot execute DELETE in a read-only transaction" in simple field
.delete()

So. Example: We have a model with a generic relation:
mentor_binds = GenericRelation('MentorBind',
object_id_field='parent_object_id',
content_type_field='parent_content_type')

And an exception when trying to clean binds:
instance.mentor_binds.all().delete()

The only workaround is to add .using('default') before .delete() /
.update()

I beelive this is a bug in GenericRelatedManager's _apply_rel_filters()
method. There is a string in it:

db = self._db or router.db_for_read(self.model, instance=self.instance)

But I can't say this is the only place with such problem, so I had to add
.using('default') before all .update() and .delete() - ~400 changes

--
Ticket URL: <https://code.djangoproject.com/ticket/32965>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jul 27, 2021, 6:54:19 AM7/27/21
to django-...@googlegroups.com
#32965: Django related manager allways choose db_for_read router and fail
update/delete
-------------------------------------+-------------------------------------
Reporter: Regressor | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 3.1
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: related manager, | Triage Stage:
db_for_read, exception, db, | Unreviewed
router |
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed
* resolution: => invalid


Comment:

Thanks for this report, however IMO it's not a bug. It's
[https://docs.djangoproject.com/en/3.2/topics/db/multi-db/#selecting-a
-database-to-delete-from documented] that `DELETE` will be executed on the
same database that was used to retrieve the object, so you need to use
`using`. I would recommend to use related manager's methods i.e. `clear()`
instead of chaining `all()` and `delete()`, e.g.
`instance.mentor_binds.clear()`, and `set()` instead of `update()`, e.g.
`instance.mentor_binds.set(...)`.

--
Ticket URL: <https://code.djangoproject.com/ticket/32965#comment:1>

Django

unread,
Jul 27, 2021, 7:40:07 PM7/27/21
to django-...@googlegroups.com
#32965: Django related manager allways choose db_for_read router and fail
update/delete
-------------------------------------+-------------------------------------
Reporter: Regressor | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 3.1
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: related manager, | Triage Stage:
db_for_read, exception, db, | Unreviewed
router |
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Regressor):

Replying to [comment:1 Mariusz Felisiak]:


> Thanks for this report, however IMO it's not a bug. It's
[https://docs.djangoproject.com/en/3.2/topics/db/multi-db/#selecting-a
-database-to-delete-from documented] that `DELETE` will be executed on the
same database that was used to retrieve the object, so you need to use
`using`. I would recommend to use related manager's methods i.e. `clear()`
instead of chaining `all()` and `delete()`, e.g.
`instance.mentor_binds.clear()`, and `set()` instead of `update()`, e.g.
`instance.mentor_binds.set(...)`.

Oh. It try to delete/update on read database, but this is not a bug
because it documented. Ok. This automatic database routers has too many
issues to be used in real life. There was ~8000 lines in our project to
start working with read replicas and it still doesn't work as expected. It
looks like we should just disable this config and try aws serverless rds.

--
Ticket URL: <https://code.djangoproject.com/ticket/32965#comment:2>

Reply all
Reply to author
Forward
0 new messages