#27564 closed Cleanup/optimization (wontfix)
`refresh_from_db()` should return the model instance instead of None
Reported by: | Tom Forbes | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.10 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
It is mildly annoying that refresh_from_db
returns None instead of self
. In some scenarios (especially involving tests) it would be quite nice to be able to do:
assert model.refresh_from_db().status == SomeEnum.SomeStatus
With lists of models it's also nice to be able to do:
assert all(model.refresh_from_db().status == Something for model in list_of_models)
Currently because the refresh_from_db
returns None you cannot do this.
Change History (4)
comment:1 by , 8 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|
comment:2 by , 8 years ago
I've noticed that Python tends to return None
for functions that mutate the object in place and return a new object for non-mutating functions. Just one example:
>>> type([1].sort()) <class 'NoneType'> >>> type(sorted([1])) <class 'list'>
It may not be a hard rule, but could be considered as a guideline.
comment:3 by , 8 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
It's definitely a strong Python design guideline that mutating-in-place methods do not also return self
. Personally I wouldn't mind if refresh_from_db
only returned an updated object, and didn't mutate the existing instance, but that ship has sailed. I don't think it should do both.
comment:4 by , 8 years ago
In fact the reason why refresh_from_db
exists is not to return an updated object, but instead to refresh it in place so that other pieces of code that have kept a reference to this instance see the updated data.
To return a copy, Thing.objects.get(pk=thing.pk)
is hardly longer than thing.refresh_from_db()
and (in my opinion) should be preferred because it's explicit.
A shorter and more idiomatic way to write:
assert all(model.refresh_from_db().status == Something for model in queryset)
is
assert all(model.status == Something for model in queryset.all())
(The .all()
creates a new queryset that forces a new database query.)
If refresh_from_db()
returns the updated instance, it will be used in situations when it isn't necessary and where the regular, safer APIs that don't involve in place mutations are a better choice.
I'm not sure. I thought it might have been discussed before, but if so, I can't find it.
Model.save()
doesn't returnself
either which seems like a similar situation. Can you think of anywhere else in Django (or Python) where this pattern is used?Considerations:
obj
on which therefresh_from_db()
is called is updated, or if it's required to doobj = obj.refresh_from_db()
.