Skip to content

Instantly share code, notes, and snippets.

@simonw
Last active January 30, 2019 18:55
Show Gist options
  • Save simonw/dd0da256716c0b0ec4efe12a81caec45 to your computer and use it in GitHub Desktop.
Save simonw/dd0da256716c0b0ec4efe12a81caec45 to your computer and use it in GitHub Desktop.
combined_recent() function for union across querysets returning most recent objects. See https://simonwillison.net/2018/Mar/25/combined-recent-additions/
from django.db.models import Value, CharField
def combined_recent(limit, **kwargs):
datetime_field = kwargs.pop('datetime_field', 'created')
querysets = []
for key, queryset in kwargs.items():
querysets.append(
queryset.annotate(
recent_changes_type=Value(
key, output_field=CharField()
)
).values('pk', 'recent_changes_type', datetime_field)
)
union_qs = querysets[0].union(*querysets[1:])
records = []
for row in union_qs.order_by('-{}'.format(datetime_field))[:limit]:
records.append({
'type': row['recent_changes_type'],
'when': row[datetime_field],
'pk': row['pk']
})
# Now we bulk-load each object type in turn
to_load = {}
for record in records:
to_load.setdefault(record['type'], []).append(record['pk'])
fetched = {}
for key, pks in to_load.items():
for item in kwargs[key].filter(pk__in=pks):
fetched[(key, item.pk)] = item
# Annotate 'records' with loaded objects
for record in records:
record['object'] = fetched[(record['type'], record['pk'])]
return records
# recent = combined_recent(
# 20,
# entry=Entry.objects.all(),
# photo=Photo.objects.all(),
# )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment