Skip to main content

Using django admin date hierarchy queries free!

Project description

https://badge.fury.io/py/django-admin-lightweight-date-hierarchy.svg https://github.com/hakib/django-admin-lightweight-date-hierarchy/actions/workflows/main.yml/badge.svg?branch=master https://codecov.io/gh/hakib/django-admin-lightweight-date-hierarchy/branch/master/graph/badge.svg

Django Admin date_hierarchy with zero queries

NOTE: Some of the functionality provided by this extension is included as part of Django starting at version 2.1.

The built-in date_hierarchy tag performs a query to find the dates for which there is data. On large tables this query can be very expensive.

To prevent additional queries, set date_hierarchy_drilldown = False on the ModelAdmin. When drill-down is disabled the tag will generate a default range of dates based solely on the selected hierarchy level - without performing a query.

Default options for hierarchy levels:

  • None - +-3 years from current year.

  • Year - all months of the selected year.

  • Month - all days of the selected month.

When date_hierarchy_drilldown = True or when not set the default behaviour is preserved.

Support

Python>=3.6

Django>=2.2

Quickstart

Install django-admin-lightweight-date-hierarchy:

pip install django-admin-lightweight-date-hierarchy

Add it to your INSTALLED_APPS:

INSTALLED_APPS = (
    ...
    'django_admin_lightweight_date_hierarchy',
    ...
)

Add the following to any ModelAdmin with date_hierarchy to prevent the default drill-down behaviour:

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    date_hierarchy = 'created'
    date_hierarchy_drilldown = False

To change the default dates generated by the template tag for any level in the hierarchy, implement a function called get_date_hierarchy_drilldown(self, year_lookup=None, month_lookup=None) on the ModelAdmin. The function receives the date hierarchy filter and is expected to return a list of dates to offer for drill-down.

For example, a custom drill-down that offers only past dates:

import datetime
import calendar

from django.utils import timezone
from django.contrib import admin


@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    date_hierarchy = 'created'
    date_hierarchy_drilldown = False

    def get_date_hierarchy_drilldown(self, year_lookup, month_lookup):
        """Drill-down only on past dates."""

        today = timezone.now().date()

        if year_lookup is None and month_lookup is None:
            # Past 3 years.
            return (
                datetime.date(y, 1, 1)
                for y in range(today.year - 2, today.year + 1)
            )

        elif year_lookup is not None and month_lookup is None:
            # Past months of selected year.
            this_month = today.replace(day=1)
            return (
                month for month in (
                    datetime.date(int(year_lookup), month, 1)
                    for month in range(1, 13)
                ) if month <= this_month
            )

        elif year_lookup is not None and month_lookup is not None:
            # Past days of selected month.
            days_in_month = calendar.monthrange(year_lookup, month_lookup)[1]
            return (
                day for day in (
                    datetime.date(year_lookup, month_lookup, i + 1)
                    for i in range(days_in_month)
                ) if day <= today
            )

Blog Post

More about the process of developing date hierarchy drill-down in this blog post scaling django admin date hierarchy.

RangeBasedDateHierarchyListFilter

Django filters the queryset for a given level in the date hierarchy using a database function to extract the relevent date part. For example, when filtering a queryset on a created date field for November 2017, Django will execute the following query:

SELECT
    ...
FROM
    app_model
WHERE
    created BETWEEN '2017-01-01 00:00:00' AND '2017-12-31 23:59:59.999999'
    AND EXTRACT('month', created) = 11

A function is opaque to the database optimizer. If you have a range-based (btree) index on the field, using EXTRACT does not limit the range at all, and so the index is not utilized properly which might lead to a sub optimal execution plan.

There are several approaches to tackle this issue. For example, in databases that support function based indexes the developer can add an index on the specific function to try and improve the performace of the query. The downside to this approach is having to maintain additional indexes for each level of the hierarchy. Additional indexes slow down insert and update operations, and take up space.

Another approach is to simplify the condition used by Django to filter the queryset for any given level in the hierarchy:

SELECT
    ...
FROM
    app_model
WHERE
    created >= '2017-11-01 00:00:00'
    AND created < '2017-12-01 00:00:00'

This is what RangeBasedDateHierarchyListFilter does.

To achieve the above query, add the following to your ModelAdmin:

from django.contrib import admin
from django_admin_lightweight_date_hierarchy.admin import RangeBasedDateHierarchyListFilter


@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    date_hierarchy = 'created'

    list_filter = (
        RangeBasedDateHierarchyListFilter,
    )

Blog Post

More about the motivation and the performace of RangeBasedDateHierarchyListFilter in this blog post Django Admin Range-Based Date Hierarchy.

Running Tests

source <YOURVIRTUALENV>/bin/activate
(venv) $ pip install tox
(venv) $ tox

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

Built Distribution

File details

Details for the file django-admin-lightweight-date-hierarchy-1.0.1.tar.gz.

File metadata

  • Download URL: django-admin-lightweight-date-hierarchy-1.0.1.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.10.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

File hashes

Hashes for django-admin-lightweight-date-hierarchy-1.0.1.tar.gz
Algorithm Hash digest
SHA256 10f3d98632036c6a0a6f01b96acecdf27a68c63f8fbbf4ffb57c29c984efa89e
MD5 f2d1278376f1bf7b33acd9b639a83e55
BLAKE2b-256 725c1b813eab2b3340f4b3fa2afed33c819abade319d9eb061e36d580fb744b3

See more details on using hashes here.

File details

Details for the file django_admin_lightweight_date_hierarchy-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: django_admin_lightweight_date_hierarchy-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.10.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

File hashes

Hashes for django_admin_lightweight_date_hierarchy-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f1d0b130790eb3e75db112e01de0d3fc5f98d242a313484f9eb0a2e118cc32a9
MD5 812cccede2d28d1a11fa1471a943085c
BLAKE2b-256 1794870c883e1e5393bc063093acf30ffb96c1a8f026afc6e619687c1b81657e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page