Changeset View
Changeset View
Standalone View
Standalone View
looper/templatetags/looper_admin_overrides.py
- This file was added.
| """Overrides some admin templatetags.""" | |||||
| import datetime | |||||
| from django.contrib.admin.templatetags import admin_list | |||||
| from django.contrib.admin.templatetags.base import InclusionAdminNode | |||||
| from django.db import models | |||||
| from django.db.models.expressions import F | |||||
| from django.db.models.functions import ExtractQuarter | |||||
| from django.utils import formats | |||||
| from django.utils.text import capfirst | |||||
| from django.utils.translation import gettext as _ | |||||
| def _get_quarters(queryset, field_name: str): | |||||
| return queryset.annotate( | |||||
| datefield=ExtractQuarter(field_name), | |||||
| plain_field=F(field_name) | |||||
| ).values_list( | |||||
| 'datefield', flat=True | |||||
| ).distinct().filter(plain_field__isnull=False).order_by('datefield') | |||||
| def _date_hierarchy_with_quarters(cl): | |||||
| if cl.date_hierarchy: | |||||
| field_name = cl.date_hierarchy | |||||
| year_field = '%s__year' % field_name | |||||
| quarter_field = '%s__quarter' % 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) | |||||
| quarter_lookup = cl.params.get(quarter_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 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, | |||||
| 'title': day, | |||||
| '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')(field_name, 'day') | |||||
| return { | |||||
| 'show': True, | |||||
| 'title': f'{year_lookup}-{int(month_lookup):02}', | |||||
| '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}), # noqa: E501 | |||||
| 'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT')) | |||||
| } for day in days] | |||||
| } | |||||
| elif year_lookup and quarter_lookup: | |||||
| months = getattr(cl.queryset, 'dates')(field_name, 'month') | |||||
| return { | |||||
| 'show': True, | |||||
| 'title': f'Q{quarter_lookup} {year_lookup}', | |||||
| 'back': { | |||||
| 'link': link({year_field: year_lookup}), | |||||
| 'title': str(year_lookup) | |||||
| }, | |||||
| 'choices': [{ | |||||
| 'link': link({year_field: year_lookup, month_field: month.month}), | |||||
| 'title': capfirst(formats.date_format(month, 'YEAR_MONTH_FORMAT')) | |||||
| } for month in months] | |||||
| } | |||||
| elif year_lookup: | |||||
| months = getattr(cl.queryset, 'dates')(field_name, 'month') | |||||
| quarters = _get_quarters(cl.queryset, field_name) | |||||
| return { | |||||
| 'show': True, | |||||
| 'title': f'year {year_lookup}', | |||||
| '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] + | |||||
| [{ | |||||
| 'link': link({year_field: year_lookup, quarter_field: quarter}), | |||||
| 'title': f'Q{quarter} {year_lookup}' | |||||
| } for quarter in quarters] | |||||
| } | |||||
| else: | |||||
| years = getattr(cl.queryset, 'dates')(field_name, 'year') | |||||
| return { | |||||
| 'show': True, | |||||
| 'back': None, | |||||
| 'choices': [{ | |||||
| 'link': link({year_field: str(year.year)}), | |||||
| 'title': str(year.year), | |||||
| } for year in years] | |||||
| } | |||||
| def date_hierarchy_maybe_with_quarters(cl): | |||||
| """Display the date hierarchy for date drill-down functionality. | |||||
| Use date_hierarchy_with_quarters if changelist specifies this option, | |||||
| or just fall back to the unadulterated admin_list.date_hierarchy. | |||||
| """ | |||||
| if cl.date_hierarchy: | |||||
| if getattr(cl, 'date_hierarchy_with_quarters', False): | |||||
| return _date_hierarchy_with_quarters(cl) | |||||
| return admin_list.date_hierarchy(cl) | |||||
| def date_hierarchy_tag(parser, token): | |||||
| """Copy the date_hierarchy_tag from django.contrib.admin to add quarters into it.""" | |||||
| return InclusionAdminNode( | |||||
| parser, token, | |||||
| func=date_hierarchy_maybe_with_quarters, | |||||
| template_name='looper/date_hierarchy.html', | |||||
| takes_context=False, | |||||
| ) | |||||
| admin_list.register.tags['date_hierarchy'] = date_hierarchy_tag | |||||