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 [email protected].
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,
)