Hello everyone, I was wondering if it would be possible to extend the admin date_hierarchy logic to also accept a list of field names instead of just a single field name.
This would be useful for models that have multiple date fields that could be equally important to filter by (such as invoices, which typically have 4 associated dates). By modifying the *change_list *admin template and the *date_hierarchy *admin template tag a little (see attachments) I was able to make it accept and use a list of strings. I unfortunately couldn't figure out how to make it also work with a single string, which would be important for not breaking existing configurations. It is aslo worth mentioning that I had to use *--skip-checks* for testing purposes, so the admin checks would also need to be adjusted accordingly. Any thoughts on this? Regards, Adam -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/b14f8f51-214a-48c0-9f03-821e53e61f00n%40googlegroups.com.{% extends "admin/change_list.html" %} {% load custom_admin_list %} {% block date_hierarchy %} {% if cl.date_hierarchy %} {% for date_field in cl.date_hierarchy %} {{ date_field }}: {% date_hierarchy_list cl date_field %} {% endfor %} {% endif %} {% endblock %}
import datetime from django.conf import settings from django.contrib.admin.templatetags.base import InclusionAdminNode from django.contrib.admin.utils import ( get_fields_from_path, ) from django.db import models from django import template from django.utils import formats, timezone from django.utils.text import capfirst from django.utils.translation import gettext as _ register = template.Library() def date_hierarchy_list(cl, field_name): """ Display the date hierarchy for date drill-down functionality. """ if cl.date_hierarchy: field = get_fields_from_path(cl.model, field_name)[-1] if isinstance(field, models.DateTimeField): dates_or_datetimes = "datetimes" qs_kwargs = {"is_dst": True} if settings.USE_DEPRECATED_PYTZ else {} else: dates_or_datetimes = "dates" qs_kwargs = {} year_field = "%s__year" % field_name month_field = "%s__month" % field_name day_field = "%s__day" % field_name field_generic = "%s__" % field_name year_lookup = cl.params.get(year_field) month_lookup = cl.params.get(month_field) day_lookup = cl.params.get(day_field) def link(filters): return cl.get_query_string(filters, [field_generic]) if not (year_lookup or month_lookup or day_lookup): # select appropriate start level date_range = cl.queryset.aggregate( first=models.Min(field_name), last=models.Max(field_name) ) if date_range["first"] and date_range["last"]: if dates_or_datetimes == "datetimes": date_range = { k: timezone.localtime(v) if timezone.is_aware(v) else v for k, v in date_range.items() } if date_range["first"].year == date_range["last"].year: year_lookup = date_range["first"].year if date_range["first"].month == date_range["last"].month: month_lookup = date_range["first"].month if year_lookup and month_lookup and day_lookup: day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup)) return { "show": True, "back": { "link": link({year_field: year_lookup, month_field: month_lookup}), "title": capfirst(formats.date_format(day, "YEAR_MONTH_FORMAT")), }, "choices": [ {"title": capfirst(formats.date_format(day, "MONTH_DAY_FORMAT"))} ], } elif year_lookup and month_lookup: days = getattr(cl.queryset, dates_or_datetimes)( field_name, "day", **qs_kwargs ) return { "show": True, "back": { "link": link({year_field: year_lookup}), "title": str(year_lookup), }, "choices": [ { "link": link( { year_field: year_lookup, month_field: month_lookup, day_field: day.day, } ), "title": capfirst(formats.date_format(day, "MONTH_DAY_FORMAT")), } for day in days ], } elif year_lookup: months = getattr(cl.queryset, dates_or_datetimes)( field_name, "month", **qs_kwargs ) return { "show": True, "back": {"link": link({}), "title": _("All dates")}, "choices": [ { "link": link( {year_field: year_lookup, month_field: month.month} ), "title": capfirst( formats.date_format(month, "YEAR_MONTH_FORMAT") ), } for month in months ], } else: years = getattr(cl.queryset, dates_or_datetimes)( field_name, "year", **qs_kwargs ) return { "show": True, "back": None, "choices": [ { "link": link({year_field: str(year.year)}), "title": str(year.year), } for year in years ], } @register.tag(name="date_hierarchy_list") def date_hierarchy_tag(parser, token): return InclusionAdminNode( parser, token, func=date_hierarchy_list, template_name="date_hierarchy.html", takes_context=False, )