Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Authors
- Anton Kulikov (`bigtimecriminal <https://github.com/bigtimecriminal>`_)
- Ben Lawson (`blawson <https://github.com/blawson>`_)
- Benjamin Mampaey (`bmampaey <https://github.com/bmampaey>`_)
- Berke Agababaoglu (`bagababaoglu <https://github.com/bagababaoglu>`_)
- Bheesham Persaud (`bheesham <https://github.com/bheesham>`_)
- `bradford281 <https://github.com/bradford281>`_
- Brian Armstrong (`barm <https://github.com/barm>`_)
Expand Down
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Unreleased

- Made ``skip_history_when_saving`` work when creating an object - not just when
updating an object (gh-1262)
- Improve performance of the latest_of_each method of the manager

3.7.0 (2024-05-29)
------------------
Expand Down
39 changes: 11 additions & 28 deletions simple_history/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,34 +62,17 @@ def latest_of_each(self):

Returns a queryset.
"""
# If using MySQL, need to get a list of IDs in memory and then use them for the
# second query.
# Does mean two loops through the DB to get the full set, but still a speed
# improvement.
backend = connection.vendor
if backend == "mysql":
history_ids = {}
for item in self.order_by("-history_date", "-pk"):
if getattr(item, self._pk_attr) not in history_ids:
history_ids[getattr(item, self._pk_attr)] = item.pk
latest_historics = self.filter(history_id__in=history_ids.values())
elif backend == "postgresql":
latest_pk_attr_historic_ids = (
self.order_by(self._pk_attr, "-history_date", "-pk")
.distinct(self._pk_attr)
.values_list("pk", flat=True)
)
latest_historics = self.filter(history_id__in=latest_pk_attr_historic_ids)
else:
latest_pk_attr_historic_ids = (
self.filter(**{self._pk_attr: OuterRef(self._pk_attr)})
.order_by("-history_date", "-pk")
.values("pk")[:1]
)
latest_historics = self.filter(
history_id__in=Subquery(latest_pk_attr_historic_ids)
)
return latest_historics
# Subquery for finding the items which are having the latest history_date in
# the group which is identified by the '_pk_attr'.
# For the latest entries, this query should not return any result.
later_historical_entries = self.filter(
models.Q(**{self._pk_attr: models.OuterRef(self._pk_attr)}),
models.Q(history_date__gt=models.OuterRef("history_date")),
)

# Filter the query to only return items in which the 'later_historical_entries'
# subquery does not return any results.
return self.filter(~models.Exists(later_historical_entries))

def _select_related_history_tracked_objs(self):
"""
Expand Down