Code Monkey home page Code Monkey logo

django-admin-lightweight-date-hierarchy's Introduction

Django Admin lightweight date hierarchy

image

image

image

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.7

Django 3.2, 4.2, >=5

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

django-admin-lightweight-date-hierarchy's People

Contributors

bluetech avatar browniebroke avatar ernestasga avatar hakib avatar nitinnain avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

django-admin-lightweight-date-hierarchy's Issues

(Django 4.1) Error templates.E003 during system check

  • django-admin-lightweight-date-hierarchy version: 1.0.1
  • Django version: 4.1
  • Python version: 3.10.5
  • Operating System: Windows 10

Description

After updating Django to version 4.1, the system check procedure throws error templates.E003 because of duplicate "admin_list" template tag module.

What I Did

command launched:

python manage.py runserver 8000

end of stacktrace:

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
?: (templates.E003) 'admin_list' is used for multiple template tag modules: 'django.contrib.admin.templatetags.admin_list', 'django_admin_lightweight_date_hierarchy.templatetags.admin_list'

System check identified 1 issue (0 silenced).

Report issue upstream

Hello! This seems like a nice package, but its starting point seems to be a clear bug in Django.
Would you mind reporting it upstream so that all django users may benefit from a fix?

In the worst case if it can’t be changed for some reasons you’d still get to clarify why this is needed with a link to upstream discussion.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.