A cool, modern and responsive django admin application based on bootstrap 5

Related tags

django-baton
Overview

django-baton

Version Build status License Downloads

A cool, modern and responsive django admin application based on bootstrap 5

Documentation: readthedocs


Live Demo

Now you can try django-baton using the new shining live demo! Login with user demo and password demo

https://django-baton-demo.herokuapp.com/


Screenshot

Table of contents

Features

Supports Django >= 2.1. For older versions of Django, please use [email protected]

This application was written with one concept in mind: overwrite as few django templates as possible. Everything is styled through CSS and when required, JS is used.

  • Based on Bootstrap 5 and FontAwesome Free 5
  • Fully responsive
  • Custom and flexible sidebar menu
  • Configurable search field
  • Text input filters and dropdown list filters facilities
  • Form tabs out of the box
  • Easy way to include templates in the change form and change list pages
  • Easy way to add attributes to change list table rows/cells
  • Collapsable stacked inline entries
  • Lazy loading of uploaded images
  • Optional display of changelist filters in a modal
  • Optional use of changelist filters as a form (combine some filters at once and perform the search action)
  • Optional index page filled with google analytics widgets
  • Customization available for recompiling the js app provided
  • IT translations provided

The following packages are required to manage the Google Analytics index:

  • google-auth
  • google-auth-httplib2
  • google-api-python-client
  • requests

Baton is based on the following frontend technologies:

  • Bootstrap 5
  • FontAwesome 5 (solid and brands)

Flexbox is used to accomplish responsiveness. jQuery is used for DOM manipulations.

All JS, fonts and CSS are compiled, and produce a single JS file which is included in the base_site template.

A custom menu is provided, the menu is rendered through JS, and data is fetched in JSON format through an AJAX request.

Installation

Install the last stable release

$ pip install django-baton

ℹ️ In order to use the Google Analytics index, install baton along the optional dependencies with $ pip install django-baton[analytics]

or clone the repo inside your project

$ git clone https://github.com/otto-torino/django-baton.git

Add baton and baton.autodiscover to your INSTALLED_APPS:

INSTALLED_APPS = (
    # ...
    'baton',
    'django.contrib.admin',
    # ... (place baton.autodiscover at the very end)
    'baton.autodiscover',
)

Replace django.contrib.admin in your project urls, and add baton urls:

# from django.contrib import admin
from baton.autodiscover import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('baton/', include('baton.urls')),

]

If you get a "No crypto library available" when using the Google Analytics index, install this package:

$ pip install PyOpenSSL

Why two installed apps?

Well, first baton has to be placed before the django.contrib.admin app, because it overrides 3 templates and resets all CSS. The baton.autodiscover entry is needed as the last installed app in order to register all applications for the admin. I decided to create a custom AdminSite class, to allow the customization of some variables the Django way (site_header, index_title, ...). I think it's a good approach to customize these vars instead of overwriting the orignal templates. The problem is that when creating a custom AdminSite, you have to register all the apps manualy. I didn't like that so I wrote this autodiscover module which automatically registers all the apps registered with the Django's default AdminSite. For this to work, all the apps must be already registered so this app should be the last in INSTALLED_APPS.

Configuration

The configuration dictionary must be defined inside your settings:

Otto srl', # noqa 'POWERED_BY': 'Otto srl', 'CONFIRM_UNSAVED_CHANGES': True, 'SHOW_MULTIPART_UPLOADING': True, 'ENABLE_IMAGES_PREVIEW': True, 'CHANGELIST_FILTERS_IN_MODAL': True, 'CHANGELIST_FILTERS_ALWAYS_OPEN': False, 'CHANGELIST_FILTERS_FORM': True, 'MENU_ALWAYS_COLLAPSED': False, 'MENU_TITLE': 'Menu', 'MESSAGES_TOASTS': False, 'GRAVATAR_DEFAULT_IMG': 'retro', 'LOGIN_SPLASH': '/static/core/img/login-splash.png', 'SEARCH_FIELD': { 'label': 'Search contents...', 'url': '/search/', }, 'MENU': ( { 'type': 'title', 'label': 'main', 'apps': ('auth', ) }, { 'type': 'app', 'name': 'auth', 'label': 'Authentication', 'icon': 'fa fa-lock', 'models': ( { 'name': 'user', 'label': 'Users' }, { 'name': 'group', 'label': 'Groups' }, ) }, { 'type': 'title', 'label': 'Contents', 'apps': ('flatpages', ) }, { 'type': 'model', 'label': 'Pages', 'name': 'flatpage', 'app': 'flatpages' }, { 'type': 'free', 'label': 'Custom Link', 'url': 'http://www.google.it', 'perms': ('flatpages.add_flatpage', 'auth.change_user') }, { 'type': 'free', 'label': 'My parent voice', 'default_open': True, 'children': [ { 'type': 'model', 'label': 'A Model', 'name': 'mymodelname', 'app': 'myapp' }, { 'type': 'free', 'label': 'Another custom link', 'url': 'http://www.google.it' }, ] }, ), 'ANALYTICS': { 'CREDENTIALS': os.path.join(BASE_DIR, 'credentials.json'), 'VIEW_ID': '12345678', } } ">
BATON = {
    'SITE_HEADER': 'Baton',
    'SITE_TITLE': 'Baton',
    'INDEX_TITLE': 'Site administration',
    'SUPPORT_HREF': 'https://github.com/otto-torino/django-baton/issues',
    'COPYRIGHT': 'copyright © 2020 Otto srl', # noqa
    'POWERED_BY': 'Otto srl',
    'CONFIRM_UNSAVED_CHANGES': True,
    'SHOW_MULTIPART_UPLOADING': True,
    'ENABLE_IMAGES_PREVIEW': True,
    'CHANGELIST_FILTERS_IN_MODAL': True,
    'CHANGELIST_FILTERS_ALWAYS_OPEN': False,
    'CHANGELIST_FILTERS_FORM': True,
    'MENU_ALWAYS_COLLAPSED': False,
    'MENU_TITLE': 'Menu',
    'MESSAGES_TOASTS': False,
    'GRAVATAR_DEFAULT_IMG': 'retro',
    'LOGIN_SPLASH': '/static/core/img/login-splash.png',
    'SEARCH_FIELD': {
        'label': 'Search contents...',
        'url': '/search/',
    },
    'MENU': (
        { 'type': 'title', 'label': 'main', 'apps': ('auth', ) },
        {
            'type': 'app',
            'name': 'auth',
            'label': 'Authentication',
            'icon': 'fa fa-lock',
            'models': (
                {
                    'name': 'user',
                    'label': 'Users'
                },
                {
                    'name': 'group',
                    'label': 'Groups'
                },
            )
        },
        { 'type': 'title', 'label': 'Contents', 'apps': ('flatpages', ) },
        { 'type': 'model', 'label': 'Pages', 'name': 'flatpage', 'app': 'flatpages' },
        { 'type': 'free', 'label': 'Custom Link', 'url': 'http://www.google.it', 'perms': ('flatpages.add_flatpage', 'auth.change_user') },
        { 'type': 'free', 'label': 'My parent voice', 'default_open': True, 'children': [
            { 'type': 'model', 'label': 'A Model', 'name': 'mymodelname', 'app': 'myapp' },
            { 'type': 'free', 'label': 'Another custom link', 'url': 'http://www.google.it' },
        ] },
    ),
    'ANALYTICS': {
        'CREDENTIALS': os.path.join(BASE_DIR, 'credentials.json'),
        'VIEW_ID': '12345678',
    }
}
  • SITE_HEADER, COPYRIGHT and POWERED_BY are marked as safe, so you can include img tags and links.
  • SUPPORT_HREF is the URL of the support link. For instance, you can use mailto:[email protected].
  • CONFIRM_UNSAVED_CHANGES: if set to True a confirmation modal appears when leaving a change form or add form with unsaved changes. The check of a dirty form relies on the jQuery serialize method, so it's not 100% safe. Disabled inputs, particular widgets (ckeditor) can not be detected. Default value is True.
  • SHOW_MULTIPART_UPLOADING: if set to True an overlay with a spinner appears when submitting a multipart/form-data form.
  • ENABLE_IMAGES_PREVIEW: if set to True a preview is displayed above all input file fields which contain images. You can control how the preview is displayed by overriding the class .baton-image-preview. By default, previews have 100px height and with a box shadow (on "hover").
  • CHANGELIST_FILTERS_IN_MODAL: if set to True the changelist filters are opened in a centered modal above the document, useful when you set many filters. By default, its value is False and the changelist filters appears from the right side of the changelist table.
  • CHANGELIST_FILTERS_ALWAYS_OPEN: if set to True the changelist filters are opened by default. By default, its value is False and the changelist filters can be expanded clicking a toggler button. This option is considered only if CHANGELIST_FILTERS_IN_MODAL is False.
  • CHANGELIST_FILTERS_FORM: if set to True the changelist filters are treated as in a form, you can set many of them and then press a filter button. With such option all standard filters are displayed as dropdowns.
  • COLLAPSABLE_USER_AREA: if set to True the sidebar user area is collapsed and can be expanded to show links.
  • MENU_ALWAYS_COLLAPSED: if set to True the menu is hidden at page load, and the navbar toggler is always visible, just click it to show the sidebar menu.
  • MENU_TITLE: the menu title shown in the sidebar. If an empty string, the menu title is hidden and takes no space on larger screens, the default menu voice will still be visible in the mobile menu.
  • MESSAGES_TOASTS: you can decide to show all or specific level admin messages in toasts. Set it to True to show all message in toasts. set it to ['warning', 'error'] to show only warning and error messages in toasts.
  • GRAVATAR_DEFAULT_IMG: the default gravatar image displayed if the user email is not associated to any gravatar image. Possible values: 404, mp, identicon, monsterid, wavatar, retro, robohash, blank (see http://en.gravatar.com/site/implement/images/).
  • LOGIN_SPLASH: an image used as body background in the login page. The image is centered and covers the whole viewport.

MENU, SEARCH_FIELD and ANALYTICS configurations in detail:

MENU

Currently four kind of voices are supported: title, app, model and free.

Title and free voices can have children, which follow the following rules:

  • children voices' children are ignored (do not place an app voice as a child)

Voices with children (title, app, free) can specify a default_open key to expand the submenu by default.

If you don't define a MENU key in the configuration dictionary, the default MENU is shown.

Title

Like MAIN and CONTENTS in the screenshot, it represents a menu section. You should set a label and optionally apps or perms key, used for visualization purposes.

If the title voice should act as a section title for a group of apps, you'd want to specify these apps, because if the user can't operate over them, then the voice is not shown. You can also define some perms (OR condition), like this:

{ 'type': 'title', 'label': 'main', 'perms': ('auth.add_user', ) },

Free voices can have children and so you can specify the default_open key.

App

You must specify the type and name keys. Optionally, an icon key (you can use FontAwesome classes which are included by default), a default_open key and a models key. If you don't define the models key, the default app models are listed under your app.

Model

You must specify the type, name and app keys. Optionally, an icon key.

Free

You can specify free voices. You must define a url and if you want some visibility permissions (OR clause). Free voices can have children and so you can specify the default_open key. Free voices also accept a re property, which specifies a regular expression used to decide whether to highlight the voice or not (the regular expression is evaluated against the document location pathname).

{
    'type': 'free',
    'label': 'Categories',
    'url': '/admin/news/category/',
    're': '^/admin/news/category/(\d*)?'
}

SEARCH FIELD

With Baton you can optionally configure a search field in the sidebar above the menu.

Search field

With this functionality, you can configure a sidebar input search field with autocomplete functionality that can let you surf easily and quickly to any page you desire.

'SEARCH_FIELD': {
    'label': 'Label shown as placeholder',
    'url': '/api/path/',
},

The autocomplete field will call a custom api at every keyup event. Such api receives the text param in the querystring and should return a json response including the search results in the form:

{
    length: 2,
    data: [
        { label: 'My result #1', icon: 'fa fa-edit', url: '/admin/myapp/mymodel/1/change' },
        // ...
    ]
}

In order to activate this functionality you should add the BATON configuration:

You should provide the results length and the data as an array of objects which must contain the label and url keys. The icon key is optional and is treated as css class given to an i element.

Let's see an example:

@staff_member_required
def admin_search(request):
    text = request.GET.get('text', None)
    res = []
    news = News.objects.all()
    if text:
        news = news.filter(title__icontains=text)
    for n in news:
        res.append({
            'label': str(n) + ' edit',
            'url': '/admin/news/news/%d/change' % n.id,
            'icon': 'fa fa-edit',
        })
    if text.lower() in 'Lucio Dalla Wikipedia'.lower():
        res.append({
            'label': 'Lucio Dalla Wikipedia',
            'url': 'https://www.google.com',
            'icon': 'fab fa-wikipedia-w'
        })
    return JsonResponse({
        'length': len(res),
        'data': res
    })

You can move between the results using the keyboard up and down arrows, and you can browse to the voice url pressing Enter.

ANALYTICS

ℹ️ In order to use the Google Analytics index, install baton along the optional dependencies with $ pip install django-baton[analytics]

You can create a cool index page displaying some statistics widgets using the Google Analytics API just by defining the ANALYTICS setting.

It requires two keys:

  • CREDENTIALS: it is the path to the credentials json file
  • VIEW_ID: ID of the view from which to display data

You can add contents before and after the analytics dashboard by extending the baton/analytics.html template and filling the baton_before_analytics and baton_after_analytics blocks.

How to generate a credentials json file

Follow the steps in the Google Identity Platform documentation to create a service account from the Google Developer Console.

Once the service account is created, you can click the Generate New JSON Key button to create and download the key and add it to your project.

Add the service account as a user in Google Analytics. The service account you created in the previous step has an email address that you can add to any of the Google Analytics views you'd like to request the data from. It's generally best to only grant the service account read-only access.

Page Detection

Baton triggers some of its functionalities basing upon the current page. For example, it will trigger the tab functionality only when the current page is an add form or change form page.

Baton understands which page is currently displayed performing some basic regular expressions against the location pathname. There may be cases in which you'd like to serve such contents at different and custom urls, in such cases you need a way to tell Baton which kind of page is tied to that url.

For this reason you can inject your custom hook, a javascript function which should return the page type and that receives as first argument the Baton's default function to use as fallback, i.e.


<script>
    (function ($, undefined) {
        $(document).ready(function () {
            Baton.detectPageHook = fn => /newschange/.test(location.pathname) ? 'change_form' : fn()
            Baton.init(JSON.parse(document.getElementById('baton-config').textContent));
        })
    })(jQuery, undefined)
script>

In this case we tell Baton that when the location pathname includes the string newschange, then the page should be considered a change_form, otherwise we let Baton guess the page type.

So, in order to hook into the Baton page detection system, just define a Baton.detectPageHook function which receives the default function as first argument and should return the page type.

The available page types are the following: dashboard, admindocs, login, logout, passowrd_change, password_change_success, add_form, change_form, changelist, filer, default.

Signals

Baton provides a dispatcher that can be used to register function that will be called when some events occurr. Currently, Baton emits four types of events:

  • onNavbarReady: dispatched when the navbar is fully rendered
  • onMenuReady: dispatched when the menu is fully rendered (probably the last event fired, since the menu contents are retrieved async)
  • onTabsReady: dispatched when the changeform tabs are fully rendered
  • onMenuError: dispatched if the request sent to retrieve menu contents fails
  • onReady: dispatched when Baton JS has finished its sync job

To use these, just override the baton admin/base_site.html template and register your listeners before calling Baton.init, i.e.


<script>

    (function ($, undefined) {
        // init listeners
        Baton.Dispatcher.register('onReady', function () { console.log('BATON IS READY') })
        Baton.Dispatcher.register('onMenuReady', function () { console.log('BATON MENU IS READY') })
        Baton.Dispatcher.register('onNavbarReady', function () { console.log('BATON NAVBAR IS READY') })
        // end listeners
        $(document).ready(function () {
            Baton.init(JSON.parse(document.getElementById('baton-config').textContent));
        })
    })(jQuery, undefined)
script>

Js Utilities

Baton comes with a number of exported js modules you can use to enhance your admin application.

Dispatcher

Baton Dispatcher singleton module lets you subscribe to event and dispatch them, making use of the Mediator pattern.

Example:

// register a callback tied to the event
Baton.Dispatcher.register('myAppLoaded', function (evtName, s) { console.log('COOL ' + s) })

// emit the event
Baton.Dispatcher.emit('myAppLoaded', 'STUFF!')

Modal

Baton Modal class lets you insert some content on a bootstrap modal without dealing with all the markup.

Modal

Usage:

// modal configuration:
//
// let config = {
//     title: 'My modal title',
//     subtitle: 'My subtitle', // optional
//     content: '

my html content

', // alternative to url
// url: '/my/url', // url used to perform an ajax request, the response is put inside the modal body. Alternative to content. // hideFooter: false, // optional // showBackBtn: false, // show a back button near the close icon, optional // backBtnCb: function () {}, // back button click callback (useful to have a multi step modal), optional // actionBtnLabel: 'save', // action button label, default 'save', optional // actionBtnCb: null, // action button callback, optional // onUrlLoaded: function () {}, // callback called when the ajax request has completed, optional // size: 'lg', // modal size: sm, md, lg, xl, optional // onClose: function () {} // callback called when the modal is closed, optional // } // // constructs a new modal instance // let myModal = new Baton.Modal(config) let myModal = new Baton.Modal({ title: 'My modal title', content: '

my html content

'
, size: 'lg' }) myModal.open(); myModal.close(); myModal.update({ title: 'Step 2', content: '

cool

'
}) myModal.toggle();

Js Translations

There are some circustamces in which Baton will print to screen some js message. Baton detects the user locale and will localize such messages, but it comes with just en and it translations provided.

Baton retrieves the current user locale from the lang attribute of the html tag.

However you can provide or add your own translations by attaching an object to the Baton namespace:

// these are the default translations, you can just edit the one you need, or add some locales. Baton engione will always
// pick up your custom translation first, if it find them.
// you can define the object before Baton.init in the base_site template
Baton.translations = {
  unsavedChangesAlert: 'You have some unsaved changes.',
  uploading: 'Uploading...',
  filter: 'Filter',
  close: 'Close',
  save: 'Save',
  search: 'Search',
  cannotCopyToClipboardMessage: 'Cannot copy to clipboard, please do it manually: Ctrl+C, Enter',
  retrieveDataError: 'There was an error retrieving the data'
}

Baton.init(JSON.parse(document.getElementById('baton-config').textContent));

If Baton can't find the translations for the user locale, it will default to en. Keep in mind that Baton will use en translations for all en-xx locales, but of course you can specify your custom translations!

List Filters

List Filters

Input Text Filters

Taken from this medium article

Baton defines a custom InputFilter class that you can use to create text input filters and use them as any other list_filters, for example:

# your app admin

from baton.admin import InputFilter

class IdFilter(InputFilter):
    parameter_name = 'id'
    title = 'id'
 
    def queryset(self, request, queryset):
        if self.value() is not None:
            search_term = self.value()
            return queryset.filter(
                id=search_term
            )


class MyModelAdmin(admin.ModelAdmin):
    list_filters = (
        'my_field',
        IdFilter,
        'my_other_field',
    )

Dropdown Filters

Taken from the github app django-admin-list-filter-dropdown

Baton provides a dropdown form of the following list filters:

Django admin filter name Baton name
SimpleListFilter SimpleDropdownFilter
AllValuesFieldListFilter DropdownFilter
ChoicesFieldListFilter ChoicesDropdownFilter
RelatedFieldListFilter RelatedDropdownFilter
RelatedOnlyFieldListFilter RelatedOnlyDropdownFilter

The dropdown is visible only if the filter contains at least three options, otherwise the default template is used.

Usage:

from baton.admin import DropdownFilter, RelatedDropdownFilter, ChoicesDropdownFilter

class MyModelAdmin(admin.ModelAdmin):
    # ...
    list_filter = (
        # for ordinary fields
        ('a_charfield', DropdownFilter),
        # for choice fields
        ('a_choicefield', ChoiceDropdownFilter),
        # for related fields
        ('a_foreignkey_field', RelatedDropdownFilter),
    )

Changelist Includes

In order for this feature to work, the user browser must support html template tags.

Baton lets you include templates directly inside the change list page, in any position you desire. It's as simple as specifying the template path and the position of the template:

@admin.register(News)
class NewsAdmin(admin.ModelAdmin):
    #...
    baton_cl_includes = [
        ('news/admin_include_top.html', 'top', ),
        ('news/admin_include_below.html', 'below', )
    ]

In this case, Baton will place the content of the admin_include_top.html template at the top of the changelist section (above the search field), and the content of the admin_include_below.html below the changelist form.

Baton changelist includes

You can specify the following positions:

Position Description
top the template is placed inside the changelist form, at the top
bottom the template is placed inside the changelist form, at the bottom
above the template is placed above the changelist form
below the template is placed below the changelist form

And, of course, you can access the all the changelist view context variables inside your template.

Changelist Filters Includes

In order for this feature to work, the user browser must support html template tags.

Baton lets you include templates directly inside the change list filter container, at the top or the bottom. It's as simple as specifying the template path and the position of the template:

@admin.register(News)
class NewsAdmin(admin.ModelAdmin):
    #...
    baton_cl_filters_includes = [
        ('news/admin_filters_include_top.html', 'top', ),
        ('news/admin_filters_include_bottom.html', 'bottom', )
    ]

Baton changelist filters includes

You can specify the following positions:

Position Description
top the template is placed inside the changelist filter container, at the top
bottom the template is placed inside the changelist filter container, at the bottom

And, of course, you can access the all the changelist view context variables inside your template.

Changelist Row Attributes

In order for this feature to work, the user browser must support html template tags.

With Baton you can add every kind of html attribute (including css classes) to any element in the changelist table (cell, rows, ...)

Baton changelist row attributes

It's a bit tricky, let's see how:

  1. Add a baton_cl_rows_attributes function to your ModelAdmin class, which takes request and cl (changelist view) as parameters.
  2. Return a json dictionary where the keys are used to match an element and the values specifies the attributes and other rules to select the element.

Better to see an example:

%s' % (instance.id, str(instance.category))) get_category.short_description = 'category' def baton_cl_rows_attributes(self, request, cl): data = {} for news in cl.queryset.filter(category__id=2): data[news.id] = { 'class': 'table-info', } data[news.id] = { 'class': 'table-success', 'data-lol': 'lol', 'title': 'A fantasctic tooltip!', 'selector': '.span-category-id-%d' % 1, 'getParent': 'td', } return json.dumps(data) ">
class NewsModelAdmin(admin.ModelAdmin):
    # ...

    def get_category(self, instance):
        return mark_safe('%s' % (instance.id, str(instance.category)))
    get_category.short_description = 'category'

    def baton_cl_rows_attributes(self, request, cl):
        data = {}
        for news in cl.queryset.filter(category__id=2):
            data[news.id] = {
                'class': 'table-info',
            }
        data[news.id] = {
            'class': 'table-success',
            'data-lol': 'lol',
            'title': 'A fantasctic tooltip!',
            'selector': '.span-category-id-%d' % 1,
            'getParent': 'td',
        }
        return json.dumps(data)

In such case we're returning a dictionary with possibly many keys (each key is an id of a news instance).

The first kind of dictionary elements will add a table-info class to the tr (rows) containing the news respecting the rule category__id=2

The second kind of element instead uses some more options to customize the element selection: you can specify a css selector, and you can specify if Baton should then take one of its parents, and in such case you can give a parent selector also. In the example provided Baton will add the class table-success, data-attribute and the title attribute to the cell which contains the element .span-category-id-1.

So these are the rules:

  • the default selector is #result_list tr input[name=_selected_action][value=' + key + '], meaning that it can work only if the model is editable (you have the checkox inputs for selecting a row), and selects the row of the instance identified by key. If you use a custom selector the dictionary key is unuseful.
  • the default getParent is tr. You can change it at you will, or set it to False, in such case the element to which apply the given attributes will be the one specified by selector.
  • Every other key different from selector and getParent will be considered an attribute and added to the element.

Form tabs

Tabs

How much I loved django-suit form tabs? Too much. So, this was a feature I couldn't live without.

There are three types of tabs:

  • fieldset tab: a tab containing a fieldset
  • inline tab: a tab containing an inline
  • group tab: a tab which can contain fieldsets and inlines in the order you specify

Tabs' titles are retrieved automatically. For fieldset and inline tabs, it's the fieldset's title and the inline related verbose name plural. For group tabs the first title is taken (either of an inline or fieldset section).

Using group tabs you can mix inlines with fields just by splitting fields into fieldsets and arranging them in your preferred order.

Let's see how to define tabs in your admin forms (everything is done through js, no templatetags or templates overriden):

class AttributeInline(admin.StackedInline):
    model = Attribute
    extra = 1

class FeatureInline(admin.StackedInline):
    model = Feature
    extra = 1

class ItemAdmin(admin.ModelAdmin):
    list_display = ('label', 'description', 'main_feature', )
    inlines = [AttributeInline, FeatureInline, ]

    fieldsets = (
        ('Main', {
            'fields': ('label', ),
            'classes': ('order-0', 'baton-tabs-init', 'baton-tab-inline-attribute', 'baton-tab-fs-content', 'baton-tab-group-fs-tech--inline-feature', ),
            'description': 'This is a description text'

        }),
        ('Content', {
            'fields': ('text', ),
            'classes': ('tab-fs-content', ),
            'description': 'This is another description text'

        }),
        ('Tech', {
            'fields': ('main_feature', ),
            'classes': ('tab-fs-tech', ),
            'description': 'This is another description text'

        }),
    )

As you can see these are the rules:

  • Inline classes remain the same, no action needed
  • On the first fieldset, define a baton-tabs-init class which enables tabs
  • On the first fieldset, you can add an order-[NUMBER] class, which will be used to determined in which position to place the first fieldset. The order starts from 0, and if omitted, the first fieldset has order 0. If you assign for example the class order-2 to the first fieldset, then the first fieldset will be the third tab, while all other tabs will respect the order of declaration.
  • For every inline you want to put in a separate tab, add a class baton-tab-inline-MODELNAME or baton-tab-inline-RELATEDNAME if you've specified a related name in the model foreign key field
  • For every fieldset you want to put in a separate tab, add a class baton-tab-fs-CUSTOMNAME, and add a class tab-fs-CUSTOMNAME on the fieldset
  • For every group you want to put in a separate tab, add a class baton-tab-group-ITEMS, where items can be inlines (inline-RELATEDNAME) and/or fieldsets (fs-CUSTOMNAME) separated by a double hypen --. Also add a class tab-fs-CUSTOMNAME on the fieldset items.
  • Tabs order respects the defined classes order
  • Fieldsets without a specified tab will be added to the main tab. If you want the fieldset to instead display outside of any tabs, add a class tab-fs-none to the fieldset. The fieldset will then always be visible regardless of the current tab.

Other features:

  • When a field has an error, the first tab containing errors is opened automatically
  • You can open a tab on page load just by adding an hash to the url, i.e. #inline-feature, #fs-content, #group-fs-tech--inline-feature

Form Includes

In order for this feature to work, the user browser must support html template tags.

Baton lets you include templates directly inside the change form page, in any position you desire. It's as simple as specifying the template path, the field name used as anchor and the position of the template:

@admin.register(News)
class NewsAdmin(admin.ModelAdmin):
    #...
    baton_form_includes = [
        ('news/admin_datetime_include.html', 'datetime', 'top', ),
        ('news/admin_content_include.html', 'content', 'above', )
    ]

In this case, Baton will place the content of the admin_datetime_include.html template at the top of the datetime field row, and the content of the admin_content_include.html above the content field row.

Baton form includes

You can specify the following positions:

Position Description
top the template is placed inside the form row, at the top
bottom the template is placed inside the form row, at the bottom
above the template is placed above the form row
below the template is placed below the form row
right the template is placed inline at the input field right side

And, of course, you can access the {{ original }} object variable inside your template.

It works seamlessly with the tab facility, if you include content related to a field inside one tab, then the content will be placed in the same tab.

Collapsable stacked inlines entries

Screenshot

Baton lets you collapse single stacked inline entries, just add a collapse-entry class to the inline, with or without the entire collapse class:

class VideosInline(admin.StackedInline):
    model = Video
    extra = 1
    classes = ('collapse-entry', )  # or ('collapse', 'collapse-entry', )

And if you want the first entry to be initially expanded, add also the expand-first class:

class VideosInline(admin.StackedInline):
    model = Video
    extra = 1
    classes = ('collapse-entry', 'expand-first', )

Customization

It's easy to heavily customize the appeareance of baton. All the stuff is compiled from a modern JS app which resides in baton/static/baton/app.

Customization

You just need to change the SASS variables values (and you can also overwrite Bootstrap variables), re-compile, get the compiled JS file, place it in the static folder of your main app, and place your main app (ROOTAPP) before baton in the INSTALLED_APPS.

So:

$ git clone https://github.com/otto-torino/django-baton.git
$ cd django-baton/baton/static/baton/app/
$ npm install
$ vim src/styles/_variables.scss
$ npm run compile
$ cp dist/baton.min.js ROOTAPP/static/baton/app/dist/

If you want to test your live changes, just start the webpack dev server:

$ cd django-baton/baton/static/baton/app/
$ npm run dev

And inside the base_site.html template, make these changes:

comment the compiled src and uncomment the webpack served src --> ">


Now while you make your changes to the JS app (CSS included), webpack will update the bundle automatically, so just refresh the page and you'll see your changes.

Tests

Starting from the release 1.7.1, django baton is provided with a set of unit and e2e tests. Testing baton is not so easy, because it almost do all the stuff with css rules and by manipulating the DOM. So the e2e tests are performed using selenium and inspecting the test application inside a real browser. In order to have them run properly, you need to have the test application running on localhost:8000.

Development

Start the test app (login admin:admin):

$ cd testapp
$ python3 -m venv .virtualenv
$ cd app
$ pip install -r requirements.txt
$ python manage.py runserver

Switch the baton js path in base_site.html

comment the compiled src and uncomment the webpack served src --> ">


Start the js app in watch mode

$ cd baton/static/baton/app
$ npm install
$ npm run dev

Now you'll see live all your changes in the testapp.

Commands

Install invoke and sphinx_rtd_theme

$ pip install invoke sphinx_rtd_theme

Now you can generate the documentation in order to check it. Inside the root dir:

$ invoke docs

Contributing

Read CONTRIBUTING.md

Screenshots

Screenshot

Screenshot

Screenshot

Screenshot

Screenshot

Screenshot

Screenshot

Screenshot

Screenshot

Screenshot

Issues
  • loss of tab context

    loss of tab context

    Hi @abidibo,

    I noticed that since I upgraded to v2, the tabs in change forms are not mapped to distinct urls. An unfortunate consequence is that when one is editing an object in a given tab, hitting 'save and continue' will lose the currently open tab.

    Is there a way to avoid losing this tab context when saving?

    Thanks!

    enhancement add to next release fixed in develop 
    opened by etanter 22
  • Integration with django-import-export

    Integration with django-import-export

    It seems like django-import-export is not displayed correctly due to mismatch with the CSS classes where import-export uses django's default. Any idea on how to fix this?

    add to next release fixed in develop third party integration 
    opened by Abe-2 17
  • submit_line buttons do not arrange nice when shrinking width / viewing on phone

    submit_line buttons do not arrange nice when shrinking width / viewing on phone

    Hi,

    The submit_line buttons in change forms display nicely when there is space: Screen Shot 2020-06-25 at 10 16 32 AM

    However, when shrinking space (or viewing on a phone), the buttons arrange weirdly: Screen Shot 2020-06-25 at 10 16 16 AM and this despite the fact that there is enough horizontal space to accommodate them in one line.

    how can I get these buttons to layout properly (as do tabs for instance)?

    Thanks!

    opened by etanter 15
  • Form includes with right option issue

    Form includes with right option issue

    Form includes with right adjustment doubles the included text.

    form_includes-with-riight-option

    django 2.2 baton 2.1.3

    invalid 
    opened by AliPolat 14
  • admin base.css is still loading messing up the baton design

    admin base.css is still loading messing up the baton design

    hey guys,

    I installed the module and with in admin dashboard its still loading the admin/css/base.css which messed up the dashboard design ( making fonts white etc ? )

    Any hints what causing this?

    more info needed under review 
    opened by shashitechno 14
  • how to ensure proper highlighting of selected voice in menu?

    how to ensure proper highlighting of selected voice in menu?

    I have a customized menu with the following:

    {'label': 'Home', 'type': 'free', 'icon': 'fa fa-home', 'url': 'home/'},
    {'label': 'Información', 'type': 'free', 'icon': 'fa fa-address-card', 'url': 'pg/professor/' + str(prof_id) + "/"},
    

    when I click on Home, the voice is highlighted as expected: Screen Shot 2020-11-17 at 12 35 21 PM

    but when I click on Información, the voice isn't highlighted: Screen Shot 2020-11-17 at 12 35 53 PM Note that this one points to the change_form of a particular model instance, while the one above is a regular view.

    Also, another entry in the menu points to a changelist:

     {'label': 'Etudiantes', 'type': 'free', 'icon': 'fa fa-user', 'url': 'pg/student/'},
    

    the voice is highlighted properly, but when navigating to one of the elements of the list, the highlighting disappears.

    Do you have an idea what's going on and how I could make sure that the voices are properly highlighted?

    (in case it matters, this is a custom menu that I set using the GetAppListJsonView.get_menu hook)

    Thanks!

    add to next release fixed in develop 
    opened by etanter 12
  • Put each inline to seperate tab

    Put each inline to seperate tab

    Hi @abidibo

    @admin.register(AModel)
    class AuthorAdmin(admin.ModelAdmin, DynamicArrayMixin):
        list_display = ('name',)
        inlines = [BAdmin, QGenericForeignKeyInline, ]
    
    

    I am using the above code in admin.py. AModelconsists of 23 fields. I want to have separate tab for each of the inlines classes. I tried following your documentation but I need to explicitly mention all fields in the fieldset values.

    I am also using GenericForiegnKey named QGenericForeignKeyInline but this is not coming in separate tab even I am attaching a class to it. It seems it only works in ForeignKey.

    opened by nitishxp 11
  • User drop-down  menu items problem

    User drop-down menu items problem

    Hello,

    User Dropdown menu items stays behind the admin panel in my case. How can I fix this ? the menu items under "Ytsejam" are not shown in the image. Screenshot from 2019-04-19 13-10-03

    Thanks for your app , it looks promising.

    opened by teethgrinder 11
  • beginning GUI issues

    beginning GUI issues

    Hi, I'm trying to evaluate migrating from django-suit to django-baton, for an app running on Django 1.11. I like the minimalist philosophy and the general design, cool stuff!

    After applying the basic install instructions, and removing all django-suits files around, everything seems fairly functional except that:

    • the menu does not show up at all (it blinks on page load then disappears and I can't find a way to get it back (also in the blink it appears to be empty, despite my config)
    • the horizontal banner (with support, copyright, etc.) shows up on the bottom of the page when first loaded, but it does not move as I scoll down the page, so it obfuscates the middle of the info.

    See snapshot attached where both issues can be appreciated. Screen Shot 2019-04-26 at 10 44 00 AM

    Any help is greatly appreciated!

    Thanks

    Éric

    opened by etanter 10
  • toggling collapsed inline

    toggling collapsed inline

    Hi, currently the toggle for collapsed inline has two main "zones": one is the blue eye icon, and the other is the whole header. The whole header is very practical as a way to toggle inlines, but there are currently two issues:

    • first, there is no visual cue that the header is in fact clickable (some change in color on hover would help suggesting that it can be clicked)
    • second, the inline label itself is, surprisingly, not clickable.

    Finally, it might be clearer to put the blue eye on the left, instead of just beside the Delete checkbox (it's a bit dangerous to have these guys too close). In fact, if the whole header is clickable, and with a visual cue, then the blue eye might not even be needed!

    opened by etanter 10
  • Custom URL in settings.

    Custom URL in settings.

    Hi, I thinks that more than a bug it is a feature.

    I use case is the following.

    I write custom url for some specific usage like payment and therefore I overwrite some methods in the admin.

    I define the following

    def get_urls(self): urls = super().get_urls() my_urls = [ path('my_url/int:value/', self.admin_site.admin_view(self.create_sale_process), name='my_url'), ] return my_urls + urls

    the way I can access this url in application is reverse(admin:my_url).

    right now I didnt find any way to pass an dynamic url into settings the problem with getting the full URL static in settings is that it cannot be reused.

    Any help will be highly appreciated.

    opened by MathiasKowoll 1
  • Bump django from 3.1.2 to 3.1.13 in /testapp/app

    Bump django from 3.1.2 to 3.1.13 in /testapp/app

    Bumps django from 3.1.2 to 3.1.13.

    Commits
    • 43873b9 [3.1.x] Bumped version for 3.1.13 release.
    • 0bd57a8 [3.1.x] Fixed CVE-2021-35042 -- Prevented SQL injection in QuerySet.order_by().
    • 8dc1cc0 [3.1.x] Added stub release notes for 3.1.13.
    • 1471ec4 [3.1.x] Fixed docs header underlines in security archive.
    • 6022181 [3.1.x] Added CVE-2021-33203 and CVE-2021-33571 to security archive.
    • 064c0c5 [3.1.x] Post-release version bump.
    • 625d3c1 [3.1.x] Bumped version for 3.1.12 release.
    • 203d4ab [3.1.x] Fixed CVE-2021-33571 -- Prevented leading zeros in IPv4 addresses.
    • 20c67a0 [3.1.x] Fixed CVE-2021-33203 -- Fixed potential path-traversal via admindocs'...
    • aa8781c [3.1.x] Confirmed release date for Django 3.1.12, and 2.2.24.
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies python 
    opened by dependabot[bot] 0
  • Bump url-parse from 1.5.1 to 1.5.3 in /baton/static/baton/app

    Bump url-parse from 1.5.1 to 1.5.3 in /baton/static/baton/app

    Bumps url-parse from 1.5.1 to 1.5.3.

    Commits
    • ad44493 [dist] 1.5.3
    • c798461 [fix] Fix host parsing for file URLs (#210)
    • 201034b [dist] 1.5.2
    • 2d9ac2c [fix] Sanitize only special URLs (#209)
    • fb128af [fix] Use 'null' as origin for non special URLs
    • fed6d9e [fix] Add a leading slash only if the URL is special
    • 94872e7 [fix] Do not incorrectly set the slashes property to true
    • 81ab967 [fix] Ignore slashes after the protocol for special URLs
    • ee22050 [ci] Use GitHub Actions
    • d2979b5 [fix] Special case the file: protocol (#204)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies javascript 
    opened by dependabot[bot] 0
  • Bump sqlparse from 0.4.1 to 0.4.2 in /testapp/app

    Bump sqlparse from 0.4.1 to 0.4.2 in /testapp/app

    Bumps sqlparse from 0.4.1 to 0.4.2.

    Changelog

    Sourced from sqlparse's changelog.

    Release 0.4.2 (Sep 10, 2021)

    Notable Changes

    Enhancements

    • Add ELSIF as keyword (issue584).
    • Add CONFLICT and ON_ERROR_STOP keywords (pr595, by j-martin).

    Bug Fixes

    • Fix parsing of backticks (issue588).
    • Fix parsing of scientific number (issue399).
    Commits
    • b1f76f6 Update changelog.
    • 3eec44e Update Changelog and bump version.
    • 8238a9e Optimize regular expression for identifying line breaks in comments.
    • e660467 Fix parsing of scientific numbers (fixes #399).
    • 23d2993 Update authors and changelog.
    • acc2810 keyword, add ON_ERROR_STOP
    • 282bcf1 keyword, add CONFLICT to postgres keywords
    • 63885dd Add ELSIF as keyword (fixes #584).
    • e575ae2 Fix parsing of backticks (fixes #588).
    • fe39072 Switch back to development mode.
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies python 
    opened by dependabot[bot] 0
  • Bump pillow from 8.0.0 to 8.3.2 in /testapp/app

    Bump pillow from 8.0.0 to 8.3.2 in /testapp/app

    Bumps pillow from 8.0.0 to 8.3.2.

    Release notes

    Sourced from pillow's releases.

    8.3.2

    https://pillow.readthedocs.io/en/stable/releasenotes/8.3.2.html

    Security

    • CVE-2021-23437 Raise ValueError if color specifier is too long [hugovk, radarhere]

    • Fix 6-byte OOB read in FliDecode [wiredfool]

    Python 3.10 wheels

    • Add support for Python 3.10 #5569, #5570 [hugovk, radarhere]

    Fixed regressions

    • Ensure TIFF RowsPerStrip is multiple of 8 for JPEG compression #5588 [kmilos, radarhere]

    • Updates for ImagePalette channel order #5599 [radarhere]

    • Hide FriBiDi shim symbols to avoid conflict with real FriBiDi library #5651 [nulano]

    8.3.1

    https://pillow.readthedocs.io/en/stable/releasenotes/8.3.1.html

    Changes

    8.3.0

    https://pillow.readthedocs.io/en/stable/releasenotes/8.3.0.html

    Changes

    ... (truncated)

    Changelog

    Sourced from pillow's changelog.

    8.3.2 (2021-09-02)

    • CVE-2021-23437 Raise ValueError if color specifier is too long [hugovk, radarhere]

    • Fix 6-byte OOB read in FliDecode [wiredfool]

    • Add support for Python 3.10 #5569, #5570 [hugovk, radarhere]

    • Ensure TIFF RowsPerStrip is multiple of 8 for JPEG compression #5588 [kmilos, radarhere]

    • Updates for ImagePalette channel order #5599 [radarhere]

    • Hide FriBiDi shim symbols to avoid conflict with real FriBiDi library #5651 [nulano]

    8.3.1 (2021-07-06)

    • Catch OSError when checking if fp is sys.stdout #5585 [radarhere]

    • Handle removing orientation from alternate types of EXIF data #5584 [radarhere]

    • Make Image.array take optional dtype argument #5572 [t-vi, radarhere]

    8.3.0 (2021-07-01)

    • Use snprintf instead of sprintf. CVE-2021-34552 #5567 [radarhere]

    • Limit TIFF strip size when saving with LibTIFF #5514 [kmilos]

    • Allow ICNS save on all operating systems #4526 [baletu, radarhere, newpanjing, hugovk]

    • De-zigzag JPEG's DQT when loading; deprecate convert_dict_qtables #4989 [gofr, radarhere]

    • Replaced xml.etree.ElementTree #5565 [radarhere]

    ... (truncated)

    Commits
    • 8013f13 8.3.2 version bump
    • 23c7ca8 Update CHANGES.rst
    • 8450366 Update release notes
    • a0afe89 Update test case
    • 9e08eb8 Raise ValueError if color specifier is too long
    • bd5cf7d FLI tests for Oss-fuzz crash.
    • 94a0cf1 Fix 6-byte OOB read in FliDecode
    • cece64f Add 8.3.2 (2021-09-02) [CI skip]
    • e422386 Add release notes for Pillow 8.3.2
    • 08dcbb8 Pillow 8.3.2 supports Python 3.10 [ci skip]
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies python 
    opened by dependabot[bot] 0
  • Bump tar from 6.1.0 to 6.1.11 in /baton/static/baton/app

    Bump tar from 6.1.0 to 6.1.11 in /baton/static/baton/app

    Bumps tar from 6.1.0 to 6.1.11.

    Commits
    • e573aee 6.1.11
    • edb8e9a fix: perf regression on hot string munging path
    • a9d9b05 chore(test): Avoid spurious failures packing node_modules/.cache
    • 24b8bda fix(test): use posix path for testing path reservations
    • e5a223c fix(test): make unpack test pass on case-sensitive fs
    • 188badd 6.1.10
    • 23312ce drop dirCache for symlink on all platforms
    • 4f1f4a2 6.1.9
    • 875a37e fix: prevent path escape using drive-relative paths
    • b6162c7 fix: reserve paths properly for unicode, windows
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies javascript 
    opened by dependabot[bot] 0
  • Bump pygments from 2.7.3 to 2.7.4 in /testapp/app

    Bump pygments from 2.7.3 to 2.7.4 in /testapp/app

    Bumps pygments from 2.7.3 to 2.7.4.

    Release notes

    Sourced from pygments's releases.

    2.7.4

    • Updated lexers:

      • Apache configurations: Improve handling of malformed tags (#1656)

      • CSS: Add support for variables (#1633, #1666)

      • Crystal (#1650, #1670)

      • Coq (#1648)

      • Fortran: Add missing keywords (#1635, #1665)

      • Ini (#1624)

      • JavaScript and variants (#1647 -- missing regex flags, #1651)

      • Markdown (#1623, #1617)

      • Shell

        • Lex trailing whitespace as part of the prompt (#1645)
        • Add missing in keyword (#1652)
      • SQL - Fix keywords (#1668)

      • Typescript: Fix incorrect punctuation handling (#1510, #1511)

    • Fix infinite loop in SML lexer (#1625)

    • Fix backtracking string regexes in JavaScript/TypeScript, Modula2 and many other lexers (#1637)

    • Limit recursion with nesting Ruby heredocs (#1638)

    • Fix a few inefficient regexes for guessing lexers

    • Fix the raw token lexer handling of Unicode (#1616)

    • Revert a private API change in the HTML formatter (#1655) -- please note that private APIs remain subject to change!

    • Fix several exponential/cubic-complexity regexes found by Ben Caller/Doyensec (#1675)

    • Fix incorrect MATLAB example (#1582)

    Thanks to Google's OSS-Fuzz project for finding many of these bugs.

    Changelog

    Sourced from pygments's changelog.

    Version 2.7.4

    (released January 12, 2021)

    • Updated lexers:

      • Apache configurations: Improve handling of malformed tags (#1656)

      • CSS: Add support for variables (#1633, #1666)

      • Crystal (#1650, #1670)

      • Coq (#1648)

      • Fortran: Add missing keywords (#1635, #1665)

      • Ini (#1624)

      • JavaScript and variants (#1647 -- missing regex flags, #1651)

      • Markdown (#1623, #1617)

      • Shell

        • Lex trailing whitespace as part of the prompt (#1645)
        • Add missing in keyword (#1652)
      • SQL - Fix keywords (#1668)

      • Typescript: Fix incorrect punctuation handling (#1510, #1511)

    • Fix infinite loop in SML lexer (#1625)

    • Fix backtracking string regexes in JavaScript/TypeScript, Modula2 and many other lexers (#1637)

    • Limit recursion with nesting Ruby heredocs (#1638)

    • Fix a few inefficient regexes for guessing lexers

    • Fix the raw token lexer handling of Unicode (#1616)

    • Revert a private API change in the HTML formatter (#1655) -- please note that private APIs remain subject to change!

    • Fix several exponential/cubic-complexity regexes found by Ben Caller/Doyensec (#1675)

    • Fix incorrect MATLAB example (#1582)

    Thanks to Google's OSS-Fuzz project for finding many of these bugs.

    Commits
    • 4d555d0 Bump version to 2.7.4.
    • fc3b05d Update CHANGES.
    • ad21935 Revert "Added dracula theme style (#1636)"
    • e411506 Prepare for 2.7.4 release.
    • 275e34d doc: remove Perl 6 ref
    • 2e7e8c4 Fix several exponential/cubic complexity regexes found by Ben Caller/Doyensec
    • eb39c43 xquery: fix pop from empty stack
    • 2738778 fix coding style in test_analyzer_lexer
    • 02e0f09 Added 'ERROR STOP' to fortran.py keywords. (#1665)
    • c83fe48 support added for css variables (#1633)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies python 
    opened by dependabot[bot] 0
  • Bump jinja2 from 2.11.2 to 2.11.3 in /testapp/app

    Bump jinja2 from 2.11.2 to 2.11.3 in /testapp/app

    Bumps jinja2 from 2.11.2 to 2.11.3.

    Release notes

    Sourced from jinja2's releases.

    2.11.3

    This contains a fix for a speed issue with the urlize filter. urlize is likely to be called on untrusted user input. For certain inputs some of the regular expressions used to parse the text could take a very long time due to backtracking. As part of the fix, the email matching became slightly stricter. The various speedups apply to urlize in general, not just the specific input cases.

    Changelog

    Sourced from jinja2's changelog.

    Version 2.11.3

    Released 2021-01-31

    • Improve the speed of the urlize filter by reducing regex backtracking. Email matching requires a word character at the start of the domain part, and only word characters in the TLD. :pr:1343
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies python 
    opened by dependabot[bot] 0
  • Allowing user-specified configuration values

    Allowing user-specified configuration values

    I was working with a personal fork of django-baton and I wanted to turn off Gravatar support. It's easy enough to just remove the JavaScript, but that would be harder to maintain long term than making Gravatar support optional and getting that contributed back upstream. I have a rough working copy that would allow for:

    BATON = {
        "GRAVATAR": False,
    }
    

    In doing this, though, I came across the need to modify baton.templatetags.baton_tags.baton_config to add the change. I have an idea for a better way to do this.


    What do y'all think about adding a baton.config.get_all_config_as_json that does something like this:

    def get_all_config_as_json():
        json_config = {}
        all_known_keys = set(list(settings.BATON.keys()) + list(default_config.keys()))
        for key in all_known_keys:
            json_key = convert_to_camel_case(key)
            json_config[json_key] = get_config(key)
        return json_config
    

    This would simplify baton_config as all it would need to do is:

    conf = {
        "api": {
            "app_list": reverse('baton-app-list-json'),
            "gravatar": reverse('baton-gravatar-json'),
        },
        **get_all_config_as_json()
    }
    

    Happy to open up a PR if this is something y'all would be interested in.

    under review 
    opened by tswicegood 3
  • Multiple choice list filter

    Multiple choice list filter

    Hi everybody,

    it would be nice to integrate the multiple choice list filter class (https://github.com/ctxis/django-admin-multiple-choice-list-filter) to the baton list filter class set.

    Thank You.

    enhancement 
    opened by AliPolat 1
Releases(2.2.3)
Owner
Otto srl
Otto srl
django's default admin interface made customizable. popup windows replaced by modals. :mage: :zap:

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

Fabio Caccamo 947 Oct 22, 2021
Responsive Theme for Django Admin With Sidebar Menu

Responsive Django Admin If you're looking for a version compatible with Django 1.8 just install 0.3.7.1. Features Responsive Sidebar Menu Easy install

Douglas Miranda 812 Sep 29, 2021
Extends the Django Admin to include a extensible dashboard and navigation menu

django-admin-tools django-admin-tools is a collection of extensions/tools for the default django administration interface, it includes: a full feature

Django Admin Tools 638 Oct 11, 2021
A Django app for easily adding object tools in the Django admin

Django Object Actions If you've ever tried making admin object tools you may have thought, "why can't this be as easy as making Django Admin Actions?"

Chris Chang 406 Oct 15, 2021
WordPress look and feel for Django administration panel

Django WP Admin WordPress look and feel for Django administration panel. Features WordPress look and feel New styles for selector, calendar and timepi

Maciej Marczewski 259 Sep 13, 2021
Modern responsive template for the Django admin interface with improved functionality. We are proud to announce completely new Jet. Please check out Live Demo

Django JET Modern template for Django admin interface with improved functionality Attention! NEW JET We are proud to announce completely new Jet. Plea

Geex Arts 3.2k Oct 18, 2021
Material design for django administration

Django Material Administration Quick start pip install django-material-admin Add material.admin and material.admin.default to your INSTALLED_APPS sett

Anton 222 Oct 18, 2021
An improved django-admin-tools dashboard for Django projects

django-fluent-dashboard The fluent_dashboard module offers a custom admin dashboard, built on top of django-admin-tools (docs). The django-admin-tools

django-fluent 295 Sep 9, 2021
An administration website for Django

yawd-admin, a django administration website yawd-admin now has a live demo at http://yawd-admin.yawd.eu/. Use demo / demo as username & passowrd. yawd

Pantelis Petridis 139 Jul 27, 2021
Django Semantic UI admin theme

Django Semantic UI admin theme A completely free (MIT) Semantic UI admin theme for Django. Actually, this is my 3rd admin theme for Django. The first

Alex 33 Oct 18, 2021
Legacy django jet rebooted , supports only Django 3

Django JET Reboot Rebooting the original project : django-jet. Django Jet is modern template for Django admin interface with improved functionality. W

null 41 Oct 9, 2021
📱 An extension for Django admin that makes interface mobile-friendly. Merged into Django 2.0

Django Flat Responsive django-flat-responsive is included as part of Django from version 2.0! ?? Use this app if your project is powered by an older D

elky 248 Jul 28, 2021
Django Smuggler is a pluggable application for Django Web Framework that helps you to import/export fixtures via the automatically-generated administration interface.

Django Smuggler Django Smuggler is a pluggable application for Django Web Framework to easily dump/load fixtures via the automatically-generated admin

semente 359 Sep 28, 2021
fastapi-admin is a fast admin dashboard based on FastAPI and TortoiseORM with tabler ui, inspired by Django admin.

fastapi-admin is a fast admin dashboard based on FastAPI and TortoiseORM with tabler ui, inspired by Django admin.

fastapi-admin 912 Oct 14, 2021
Jazzy theme for Django

Django jazzmin (Jazzy Admin) Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy Installation pip inst

David Farrington 813 Oct 23, 2021
Jet Bridge (Universal) for Jet Admin – API-based Admin Panel Framework for your application

Jet Bridge for Jet Admin – Admin panel framework for your application Description About Jet Admin: https://about.jetadmin.io Live Demo: https://app.je

Jet Admin 1k Oct 14, 2021
A Django admin theme using Twitter Bootstrap. It doesn't need any kind of modification on your side, just add it to the installed apps.

django-admin-bootstrapped A Django admin theme using Bootstrap. It doesn't need any kind of modification on your side, just add it to the installed ap

null 1.6k Oct 14, 2021
A Django admin theme using Twitter Bootstrap. It doesn't need any kind of modification on your side, just add it to the installed apps.

django-admin-bootstrapped A Django admin theme using Bootstrap. It doesn't need any kind of modification on your side, just add it to the installed ap

null 1.6k Oct 14, 2021
Visually distinguish environments in Django Admin

django-admin-env-notice Visually distinguish environments in Django Admin. Based on great advice from post: 5 ways to make Django Admin safer by hakib

Yuri Shikanov 228 Oct 15, 2021