django's default admin interface made customizable. popup windows replaced by modals. :mage: :zap:

  • By Fabio Caccamo
  • Last update: Jan 2, 2023
  • Comments: 17

django-admin-interface

django-admin-interface is a modern responsive flat admin interface customizable by the admin itself.

django-admin-interface-preview


Features

  • Beautiful default django-theme
  • Themes management and customization (you can customize admin title, logo and colors)
  • Responsive
  • Related modal (instead of the old popup window)
  • Environment name/marker
  • Language chooser
  • List filter dropdown
  • NEW Foldable apps (accordions in the navigation bar)
  • NEW List filter sticky
  • NEW Form controls sticky (pagination and save/delete buttons)
  • Compatibility / Style optimizations for:
    • django-ckeditor
    • django-dynamic-raw-id
    • django-json-widget
    • django-modeltranslation
    • django-tabbed-admin
    • sorl-thumbnail

Installation

  • Run pip install django-admin-interface
  • Add admin_interface, flat_responsive, flat and colorfield to settings.INSTALLED_APPS before django.contrib.admin
INSTALLED_APPS = (
    #...
    'admin_interface',
    'flat_responsive', # only if django version < 2.0
    'flat', # only if django version < 1.9
    'colorfield',
    #...
    'django.contrib.admin',
    #...
)

# only if django version >= 3.0
X_FRAME_OPTIONS = 'SAMEORIGIN'
SILENCED_SYSTEM_CHECKS = ['security.W019']
  • Run python manage.py migrate
  • Run python manage.py collectstatic
  • Restart your application server

Upgrade

  • Run pip install django-admin-interface --upgrade
  • Run python manage.py migrate (add --fake-initial if you are upgrading from 0.1.0 version)
  • Run python manage.py collectstatic --clear
  • Restart your application server

Optional themes

This package ships with optional themes as fixtures, they can be installed using the loaddata admin command. Optional themes are activated on installation.

Django theme (default):

Run python manage.py loaddata admin_interface_theme_django.json

Bootstrap theme:

Run python manage.py loaddata admin_interface_theme_bootstrap.json

Foundation theme:

Run python manage.py loaddata admin_interface_theme_foundation.json

U.S. Web Design Standards theme:

Run python manage.py loaddata admin_interface_theme_uswds.json

Add more themes

You can add a theme you've created through the admin to this repository by sending us a PR. Here are the steps to follow to add:

  1. Export your exact theme as fixture using the dumpdata admin command: python manage.py dumpdata admin_interface.Theme --indent 4 -o admin_interface_theme_{{name}}.json --pks=N

  2. Copy the generated json file into the fixtures folder (making sure its name starts with admin_interface_theme_ to avoid clashes with fixtures that might be provided by other third party apps).

  3. Remove the "pk" from the fixture and make sure the active field is set to true (in this way a theme is automatically activated when installed).

  4. Edit the section above to document your theme.

Add theme support to third-party libraries

You can add theme support to existing third-party libraries using the following css variables:

  • --admin-interface-title-color
  • --admin-interface-logo-color
  • --admin-interface-env-color
  • --admin-interface-header-background-color:
  • --admin-interface-header-text-color
  • --admin-interface-header-link-color
  • --admin-interface-header-link_hover-color
  • --admin-interface-module-background-color
  • --admin-interface-module-background-selected-color
  • --admin-interface-module-text-color
  • --admin-interface-module-link-color
  • --admin-interface-module-link-selected-color
  • --admin-interface-module-link-hover-color
  • --admin-interface-generic-link-color
  • --admin-interface-generic-link-hover-color
  • --admin-interface-save-button-background-color
  • --admin-interface-save-button-background-hover-color
  • --admin-interface-save-button-text-color
  • --admin-interface-delete-button-background-color
  • --admin-interface-delete-button-background-hover-color
  • --admin-interface-delete-button-text-color
  • --admin-interface-related-modal-background-color
  • --admin-interface-related-modal-background-opacity

Screenshots

Admin login

django-admin-interface_login

Admin dashboard

django-admin-interface_dashboard

Admin themes management

django-admin-interface_themes_management

Admin theme customization

django-admin-interface_theme_customization


FAQ

Custom base-site.html

I already have a custom base_site.html, how can I make it work?

You can use django-apptemplates, then add {% extends "admin_interface:admin/base_site.html" %} to your base_site.html

Language Chooser not showing

I have enabled the Language Chooser, but it is not visible in the admin, what should I do?

You must configure multilanguage settings and urls correctly:

LANGUAGES = (
  ('en', _('English')),
  ('it', _('Italiano')),
  ('fr', _('Française')),
  # more than one language is expected here
)
LANGUAGE_CODE = 'en'
USE_I18N = True
MIDDLEWARE = [
  # ...
  'django.middleware.locale.LocaleMiddleware',
  # ...
]
from django.conf.urls.i18n import i18n_patterns
from django.contrib import admin
from django.urls import include, path

# ...

urlpatterns = [
    path('i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(path('admin/', admin.site.urls))

Testing

# create python virtual environment
virtualenv testing_django_admin_interface

# activate virtualenv
cd testing_django_admin_interface && . bin/activate

# clone repo
git clone https://github.com/fabiocaccamo/django-admin-interface.git src && cd src

# install dependencies
pip install -r requirements.txt
pip install -r requirements-test.txt

# run tests
tox
# or
python setup.py test
# or
python -m django test --settings "tests.settings"

License

Released under MIT License.


See also

  • django-colorfield - simple color field for models with a nice color-picker in the admin. 🎨

  • django-extra-settings - config and manage typed extra settings using just the django admin. ⚙️

  • django-maintenance-mode - shows a 503 error page when maintenance-mode is on. 🚧 🛠️

  • django-redirects - redirects with full control. ↪️

  • django-treenode - probably the best abstract model / admin for your tree based stuff. 🌳

  • python-benedict - dict subclass with keylist/keypath support, I/O shortcuts (base64, csv, json, pickle, plist, query-string, toml, xml, yaml) and many utilities. 📘

  • python-codicefiscale - encode/decode Italian fiscal codes - codifica/decodifica del Codice Fiscale. 🇮🇹 💳

  • python-fontbro - friendly font operations. 🧢

  • python-fsutil - file-system utilities for lazy devs. 🧟‍♂️

Github

https://github.com/fabiocaccamo/django-admin-interface

Comments(17)

  • 1

    post_migrate_handler

    Python version 3.8

    Django version 3.2.16

    Package version 0.22.2

    Current behavior (bug description) The current behavior of the post-migration signal (post_migrate_handler) does not take into account any routing of the databases

    from django.conf import settings
    
    
    class DatabaseAppsRouter(object):
        """
    
            arouter to control all database operations on models for different
            databases.
    
            in case an app is not set in settings.DATABASE_APPS_MAPPING, the router
            will fallback to the `default` database.
    
            Settings example:
    
            DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
        """
    
        def db_for_read(self, model, **hints):
            """Point all read operations to the specific database"""
            if model._meta.app_label in settings.DATABASE_APPS_MAPPING:
                return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
    
            return None
    
        def db_for_write(self, model, **hints):
            """Point all write operations to the specific database"""
            if model._meta.app_label in settings.DATABASE_APPS_MAPPING:
                return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
    
            return None
    
        def allow_relation(self, obj1, obj2, **hints):
            """Allow any relation between apps that use the same database"""
            db1 = settings.DATABASE_APPS_MAPPING[obj1._meta.app_label]
            db2 = settings.DATABASE_APPS_MAPPING[obj2._meta.app_label]
    
            if db1 and db2:
                return db1 == db2
    
            return None
    
        def allow_migrate(self, db, app_label, model_name=None, **hints):
            """Make sure that apps only appear in the related database"""
    
            if db in settings.DATABASE_APPS_MAPPING.values():
                return settings.DATABASE_APPS_MAPPING[app_label] == db
    
            elif app_label in settings.DATABASE_APPS_MAPPING:
                return False
    
            return None
    
    
    DATABASES = {
        'default': {
            'ENGINE': 'timescale.db.backends.postgresql',
            'NAME': TIMESCALE_DB_HOST_FORMATTED['Database'],
            'USER': TIMESCALE_DB_HOST_FORMATTED['Username'],
            'PASSWORD': TIMESCALE_DB_HOST_FORMATTED['Password'],
            'HOST': TIMESCALE_DB_HOST_FORMATTED['Host'],
            'PORT': TIMESCALE_DB_PORT,
            'OPTIONS': {
                'client_encoding': 'UTF8',
                # 'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
            }
        },
        'collector': {
            'ENGINE': 'djongo',
            'NAME': 'Database',
            'ENFORCE_SCHEMA': True,
            'CLIENT': {
                'host': MONGO_DB_HOST
            }
        }
    }
    
    
    DATABASE_APPS_MAPPING = {
        'contenttypes': 'default',
        'auth': 'default',
        'admin': 'default',
        'django_cache': 'default',
        'sessions': 'default',
        'staticfiles': 'default',
        'admin_interface': 'default',
        'collector': 'djongo(mongodb)',
        'main': 'default',
    }
    
    DATABASE_ROUTERS = ['routers.DatabaseAppsRouter']
    

    Workaround

    def apply_theme(sender, **kwargs):
        from django.conf import settings
        from admin_interface.models import Theme
        from admin_interface.cache import del_cached_active_theme
    
        del_cached_active_theme()
        theme = Theme.get_active_theme('default')
        theme.logo = ....
        theme.favicon = ....
        theme.save()
    
    
    class MainConfig(AppConfig):
        default_auto_field = 'django.db.models.BigAutoField'
        name = 'main'
        verbose_name = 'analyser configuration'
    
        def ready(self) -> None:
            from admin_interface.models import Theme
    
            Theme.post_migrate_handler = apply_theme
            if 'admin_interface_theme' in connection.introspection.table_names():
                apply_theme(None)
    
  • 2

    Tabbed changeform

    Related to #209

    These are purely visual changes based on a boolean field.

    Significant changes are,

    • Two new fields show_fieldsets_as_tabs & show_inlines_as_tabs and it's migration.
    • headless_* version of fieldsets and inlines templates in order to hide the header. They are exact copies except for the title line.
    • Template tag to fetch headerless_* version of fieldset and inlines when in tabbed mode
    • JS file with basic tab logic
    • Static CSS for tab buttons
  • 3

    Popup for related models creation fires a javascript error when "Related modal" is inactive

    Python version Python 3.7.6

    Django version Django 3.0.4

    Package version django-admin-interface==0.12

    Current behavior (bug description) The Popup for related models creation doesn't work when "Related modal" is inactive, due to this javascript error:

     Uncaught TypeError: Cannot read property 'replace' of undefined
        at windowname_to_id (:8000/static/admin/js/admin/RelatedObjectLookups.js:19)
        at dismissAddRelatedObjectPopup (:8000/static/admin/js/admin/RelatedObjectLookups.js:77)
        at popup_response.js:43
        at popup_response.js:52
    

    Expected behavior Since the standard Django admin is working correctly, this problem seems related to the presence of django-admin-interface.

    I did a very basic setup of a simple Django project to reproduce the error in a simplified enrvironment.

    The project and some screenshots to better explain the problem are available here:

    https://github.com/morlandi/test-admin-interface

  • 4

    Refresh translations + add CI check

    I recreated translations last week and noticed many changes.

    Files should be regenerated so that translators can update translations. I will contribute French!

  • 5

    Replace travis with github actions

    Most projects have left Travis because of the management issues. It seems that tests for PRs here are not run any more. I could convert the config to github actions (example conversions from circleci: https://github.com/caravancoop/configstore/pull/47)

  • 6

    Unreadable text in autocomplete multi-selects

    Python version 3.8

    Django version 3.0.6

    Package version 0.12.2

    Current behavior (bug description) In a multi-select field using autocomplete (django admin feature), selected options are not readable. Django’s autocomplete.css sets a white font color, django-admin-interface inline CSS defines white background color.

    Expected behavior Text should be readable :slightly_smiling_face: I am not sure if the background or text color should change, though; should probably match the behaviour of custom selects.

    A quick workaround:

    .select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] {
      color: inherit;
    
  • 7

    Cache admin settings

    Each call to Theme.get_active_theme makes multiple database calls. Unfortunately, that's called in the get_admin_interface_theme template tag, which appears multiple times on each admin page render.

    We should cache these calls at least per request to speed up performance.

  • 8

    Left/right scrolling broken with django-import-export

    I'm not sure which repo to open this issue on, but when using django-import-export, after importing it takes you to a big table that shows the before & after. With this theme enabled, there is no ability to scroll left and right to see those changes.

    Issue on the other side, just in case: https://github.com/django-import-export/django-import-export/issues/1476

  • 9

    migrate fails at "change_related_modal_background_opacity_type"

    Hi there. Thanks for the great interface. I'm trying to migrate from a function setup with Python 3.6, Django 2.1.5, and admin-interface 0.9.1 . When I run migrate on my development computer I end up with the following traceback. I'm happy to help debug but the process of debugging if I can.

    ` Applying admin_interface.0008_change_related_modal_background_opacity_type...Traceback (most recent call last): File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) psycopg2.OperationalError: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last): File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration state = migration.apply(state, schema_editor) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/migrations/migration.py", line 124, in apply operation.database_forwards(self.app_label, schema_editor, old_state, project_state) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/migrations/operations/fields.py", line 216, in database_forwards schema_editor.alter_field(from_model, from_field, to_field) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 523, in alter_field old_db_params, new_db_params, strict) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/postgresql/schema.py", line 122, in _alter_field new_db_params, strict, File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 663, in _alter_field params, File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 133, in execute cursor.execute(sql, params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute return super().execute(sql, params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute return self._execute_with_wrappers(sql, params, many=False, executor=self._execute) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers return executor(sql, params, many, context) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/utils.py", line 89, in exit raise dj_exc_value.with_traceback(traceback) from exc_value File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) django.db.utils.OperationalError: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last): File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection self.connect() File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/base.py", line 194, in connect self.connection = self.get_new_connection(conn_params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/postgresql/base.py", line 178, in get_new_connection connection = Database.connect(**conn_params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/psycopg2/init.py", line 130, in connect conn = _connect(dsn, connection_factory=connection_factory, **kwasync) psycopg2.OperationalError: FATAL: the database system is in recovery mode

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last): File "manage.py", line 30, in execute_from_command_line(sys.argv) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/core/management/init.py", line 381, in execute_from_command_line utility.execute() File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/core/management/init.py", line 375, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/core/management/base.py", line 316, in run_from_argv self.execute(*args, **cmd_options) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/core/management/base.py", line 353, in execute output = self.handle(*args, **options) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/core/management/base.py", line 83, in wrapped res = handle_func(*args, **kwargs) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 203, in handle fake_initial=fake_initial, File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration state = migration.apply(state, schema_editor) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 108, in exit self.atomic.exit(exc_type, exc_value, traceback) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/transaction.py", line 256, in exit connection.set_autocommit(True) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/base.py", line 394, in set_autocommit self.ensure_connection() File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection self.connect() File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/utils.py", line 89, in exit raise dj_exc_value.with_traceback(traceback) from exc_value File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection self.connect() File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/base/base.py", line 194, in connect self.connection = self.get_new_connection(conn_params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/django/db/backends/postgresql/base.py", line 178, in get_new_connection connection = Database.connect(**conn_params) File "/home/ace/.local/share/virtualenvs/website-10j77PrM/lib/python3.6/site-packages/psycopg2/init.py", line 130, in connect conn = _connect(dsn, connection_factory=connection_factory, **kwasync) django.db.utils.OperationalError: FATAL: the database system is in recovery `mode``

  • 10

    CSS as FileField in `Theme` model

    Hello,

    I have seen that the Theme model allow to "inject" raw css through its css attribute. However it is a TextField and it is not so easy to use in practice (for instance we need to inline the css code in the json fixture). I think it could be great to either turn this field into a FileField or to add a new FileField attribute like css_file. Of course I can help through a PR :)

  • 11

    Show active filters at the top of the sidebar with clear button

    On a list page with many filters shown and the dropdown option active, admin users have a hard time finding out which filters are currently active, in order to remove one for example if the current selection has no results. They would have to go through the list and determine if the value visible is the default or not, so they end up clearing all filters (it’s the only action displayed) and re-building their selection.

    #174 improves the visibility and #175 fixes a usability issue. This proposes a new theme option to also display current filters at the top of the sidebar, wich a link to remove each filter: ( x Age: 9+ ) ( x Group: 10-15 ) ( x Clear all filters ) (parens to represent a chip widget)

  • 12

    Used slugify template tag for tabs not working with non-ASCII alphanumeric characters

    Hello, Thank you for your amazing django package

    When used slugify template tag for tabs not working with non-ASCII alphanumeric characters

    https://github.com/fabiocaccamo/django-admin-interface/blob/8d82d80c19f76f409f75456bf974966f6d8295a2/admin_interface/templates/admin/change_form.html#L21

    instated you can used forloop counter

    used tab with loop of counter for fieldset

    <button type="button" id="tablink-tab{{  forloop.counter   }}" class="tabbed-changeform-tablink {{ forloop.counter0|default:'active' }}" onclick="AdminInterface.tabbedChangeForm.openTab(event, 'tab{{forloop.counter }}')">
                        {{ tab_name|capfirst }}
                    </button>
    

    Used** tab0 for fieldsets without tabs

    used itab with loop counter for inlines formset

    <button type="button" id="tablink-itab{{ forloop.counter }}" class="tabbed-changeform-tablink" onclick="AdminInterface.tabbedChangeForm.openTab(event, 'itab{{ forloop.counter }}')">
                        {{ tab_name|capfirst }}
                    </button>
    

    this is full patch code:

      <div id="tabbed-changeform-tabs" class="tabbed-changeform-tabs">
    
                {% if show_fieldsets_as_tabs %}
                    {% for fieldset in adminform %}
    
                    {% with fieldset.name|default_if_none:opts.verbose_name as tab_name %}
                    <button type="button" id="tablink-tab{{  forloop.counter   }}" class="tabbed-changeform-tablink {{ forloop.counter0|default:'active' }}" onclick="AdminInterface.tabbedChangeForm.openTab(event, 'tab{{forloop.counter }}')">
                        {{ tab_name|capfirst }}
                    </button>
                    {% endwith %}
    
                    {% endfor %}
                {% else %}
                    {% with opts.verbose_name as tab_name %}
                    <button type="button" id="tablink-tab0" class="tabbed-changeform-tablink active" onclick="AdminInterface.tabbedChangeForm.openTab(event, 'tab0')">
                        {{ tab_name|capfirst }}
                    </button>
                    {% endwith %}
                {% endif %}
    
                {% if show_inlines_as_tabs %}
                    {% for inline_admin_formset in inline_admin_formsets %}
                    {% with inline_admin_formset.opts.verbose_name_plural as tab_name %}
                    <button type="button" id="tablink-itab{{ forloop.counter }}" class="tabbed-changeform-tablink" onclick="AdminInterface.tabbedChangeForm.openTab(event, 'itab{{ forloop.counter }}')">
                        {{ tab_name|capfirst }}
                    </button>
                    {% endwith %}
                    {% endfor %}
                {% endif %}
    
                <span class="tabbed-changeform-tabs-remaining-space"></span>
    
            </div>
    
            {% if show_fieldsets_as_tabs %}
                {% for fieldset in adminform %}
                {% with fieldset.name|default_if_none:opts.verbose_name as tab_name %}
                <div id="tabcontent-tab{{ forloop.counter }}" class="tabbed-changeform-tabcontent {{ forloop.counter0|default:'active' }}">
                    {% include "admin/includes/headerless_fieldset.html" %}
                </div>
                {% endwith %}
                {% endfor %}
            {% else %}
                {% with opts.verbose_name as tab_name %}
                <div id="tabcontent-tab0" class="tabbed-changeform-tabcontent active">
                {% for fieldset in adminform %}
                    {% include "admin/includes/fieldset.html" %}
                {% endfor %}
                </div>
                {% endwith %}
            {% endif %}
    
            {% for inline_admin_formset in inline_admin_formsets  %}
            {% with inline_admin_formset.opts.verbose_name_plural as tab_name %}
            <div id="tabcontent-itab{{ forloop.counter }}" class="tabbed-changeform-tabcontent">
                {% get_admin_interface_inline_template inline_admin_formset.opts.template as inline_template %}
                {% include inline_template %}
            </div>
            {% endwith %}
            {% endfor %}
    
  • 13

    Dashboard feature

    When building django admin apps, it is usually nice to have a custom dashboard to display extra data.

    Take a look a django-unfold package and see how that is achieved, it'll be nice to have something similar.

  • 14

    Initial changes for Dark mode :

    Related to #129

    This PR lays the ground work for using a proper dark mode. This PR is meant to validate and allow two separate themes at the same time

    • [X] Adds a new param active_dark to designate a theme to be used for dark mode
    • [X] Splits outs Styles in base_site.html into separate file that is included
    • [X] Updates the new ThemeQueryset, model function and signals to handle for use_dark
    • [X] Add active dark checkbox for admin listview
    • [X] Tests

    TODO in a different PR :

    • Override Django's css variables with colors from the theme
  • 15

    Add new `css_generic_link_active_color` field to use on active tab (tabbed changeform).

    Yes, adding a css_generic_link_active_color would solve any doubt and would also be available for possible other future cases.

    Originally posted by @fabiocaccamo in https://github.com/fabiocaccamo/django-admin-interface/issues/231#issuecomment-1352912993

  • 16

    Custom Admin Page

    Hello !! I've recently discovered this project in my quest to reuse the admin page as much as possible for a minimal backoffice. I love that ability to theme and all the little features like dropdown for filters that make a big difference to UX.

    Requested feature Do you have any plans on adding support for a custom Admin Page?

    Feature context Currently, I am hitting a wall with the reusability of the admin. I'd like to make custom pages with a custom queryset in order to have custom pages for KPIs and charts, internal forms and tiny little backoffice features.

    A quick look at the code shows me that it needs to be an admin_view or tied to BaseModelAdmin. I'm currently working on trying to replicate it but it's a wip and I'm pretty lost haha

    What it brings to project This would be a major differentiator against the standard admin. Since, django admin comes loaded with default widgets and permissons, there is far less logic to be written if we need only a few custom pages for a backoffice.

    Other solutions : I've taken a look at django-admin-views but I'm not been able to get it working so far. (I've raised a bug report at the moment)

  • 17

    Sticky table header and columns (action checkbox column and first field column).

    It would be very useful having the possibility to set sticky table columns in the changelist (action checkbox column if actions are enabled + list_display_links columns), and also in the tabular inlines table.

    This feature would improve tables UX, especially when there is horizontal scroll.

    NOTE: should test also with RTL languages.