from django.conf import settings from django.contrib.admin.options import ModelAdmin from django.utils.translation import gettext_lazy as _ from .settings import USE_JQUERY_UI, JQUERY_UI_CSS, JQUERY_UI_JS class TabbedModelAdmin(ModelAdmin): tabs = None formatted_tabs = {} # Needs a specific template to display the tabs change_form_template = 'tabbed_admin/change_form.html' def get_fieldsets(self, request, obj=None): """ Overwrites BaseModelAdmin fieldsets to add fieldsets passed by the tabs. If the tabs attribute is not set, use the default ModelAdmin method. """ tabs_fieldsets = self.get_formatted_tabs(request, obj)['fieldsets'] if self.tabs is not None: self.fieldsets = () self.fieldsets = self.add_tabbed_item(tabs_fieldsets, self.fieldsets) return super(TabbedModelAdmin, self).get_fieldsets(request, obj) def get_inline_instances(self, request, obj=None): """ Overwrites BaseModelAdmin fieldsets to add fieldsets passed by the tabs. If the tabs attribute is not set, use the default ModelAdmin method. """ if self.tabs is not None: self.inlines = () tabs_inlines = self.get_formatted_tabs(request, obj)['inlines'] self.inlines = self.add_tabbed_item(tabs_inlines, self.inlines) try: # django >=1.7 return super(TabbedModelAdmin, self)\ .get_inline_instances(request, obj) except TypeError: return super(TabbedModelAdmin, self).get_inline_instances(request) def add_tabbed_item(self, items_to_add, collection): """ Adds tabbed items (inlines or fieldsets) to their corresponding attribute. """ if items_to_add: for item in items_to_add: if item not in collection: if type(collection) == tuple: collection = collection + (item, ) elif type(collection) == list: collection.append(item) return collection def get_tabs(self, request, obj=None): """ Returns the tabs attribute. """ return self.tabs def get_formatted_tabs(self, request, obj=None): """ Returns the formated tabs attribute. """ if self.tabs: self.parse_fieldsets_inlines_from_tabs(request, obj) return self.formatted_tabs def parse_fieldsets_inlines_from_tabs(self, request, obj=None): """ Parses the self.tabs attribute. Checks its integrity and populates self._tabs_fieldsets and self._tabs_inlines attributes. """ tabs_fieldsets = () tabs_inlines = () self.formatted_tabs['fields'] = [] for tab in self.get_tabs(request, obj): # Checks that each tab if formated with 2 arguments, verbose name # of the tab and the tab configuration. if type(tab) not in [tuple, list]: raise TypeError( _(u'Each tab entry must be either a list or a tuple')) if len(tab) != 2: raise ValueError( _(u'Each tabs entry must contain 2 arguments: a verbose name and the tab setup.')) if type(tab[1]) not in [tuple, list]: raise TypeError( _(u'A tab definition must be either a list or a tuple')) # So far all went well, lets parse the tab configuration, we go # through each item. If its a tuple or a list we consider its a # fieldset, otherwise its a tuple. formatted_tab = {'name': tab[0], 'entries': []} for tab_entry in tab[1]: formatted_tab_entry = {} if type(tab_entry) in [tuple, list]: tabs_fieldsets = tabs_fieldsets + (tab_entry, ) formatted_tab_entry = {'type': 'fieldset', 'name': tab_entry[0], 'config': tab_entry[1]} else: tabs_inlines = tabs_inlines + (tab_entry, ) formatted_tab_entry = {'type': 'inline', 'name': tab_entry.__name__} formatted_tab['entries'].append(formatted_tab_entry) self.formatted_tabs['fields'].append(formatted_tab) self.formatted_tabs['fieldsets'] = tabs_fieldsets self.formatted_tabs['inlines'] = tabs_inlines def add_view(self, request, form_url='', extra_context=None): """ Overwrites add_view to insert the tabs config for the template. """ if extra_context is None: extra_context = {} extra_context.update({'tabs': self.get_formatted_tabs(request)}) return super(TabbedModelAdmin, self)\ .add_view(request, form_url=form_url, extra_context=extra_context) def change_view(self, request, object_id, form_url='', extra_context=None): """ Overwrites change_view to insert the tabs config for the template. """ try: # django 1.4 change_view = super(TabbedModelAdmin, self)\ .change_view(request, object_id, form_url=form_url, extra_context=extra_context) except TypeError: # django 1.3 change_view = super(TabbedModelAdmin, self)\ .change_view(request, object_id, extra_context=extra_context) if hasattr(change_view, 'context_data'): change_view.context_data.update( {'tabs': self.get_formatted_tabs(request, change_view.context_data.get('original'))} ) return change_view class Media: """ Extends media class to add custom jquery ui if TABBED_ADMIN_USE_JQUERY_UI is set to True. """ if 'grappelli' in settings.INSTALLED_APPS: css = {'all': ("tabbed_admin/css/tabbed_grappelli_admin.css", )} if USE_JQUERY_UI: css = { 'all': (JQUERY_UI_CSS, 'tabbed_admin/css/tabbed_admin.css', )} js = (JQUERY_UI_JS,)