Thursday, June 29, 2017

How to combine change_list_template in ModelAdmin mixin


I would like to create a mixin to extend the ModelAdmin class that adds a description text to the view, overriding the default change_list_template.

[admin_extra.py]
class DescriptionAdminMixin(object)
change_list_template = "description_change_list.html"
...

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}
        extra_context.update({
            'description': self.description,
        })
        return super(DescriptionAdminMixin, self).changelist_view(request, extra_context=extra_context)

[description_change_list.html]
{% extends "admin/change_list.html" %}
{% block object-tools %}
{% block description %}
{% if description %}{{ description }}{% endif %}
{% endblock description %}
{{ block.super }}
{% endblock %}


This works fine if used on a ModelAdmin, but it fails if used on an already subclassed ModelAdmin that also defines change_list_template, as it gets overwritten.


Ex. adding django-import-export mixin:

class MyModelAdmin(DescriptionAdminMixin, ExportMixin, ModelAdmin): 
...

where ExportMixin is defined as:

class ExportMixin(ImportExportMixinBase):
...
    change_list_template = 'admin/import_export/change_list_export.html'
    ...

Is there a preferred way to combine both templates?


The solution I use for now is defining a parent_template in the context, and use that in the template to extend from it

[admin_extra.py]
class DescriptionAdminMixin(object)
    change_list_template = "description_change_list.
    ...
    def changelist_view(self, request, extra_context=None):
        # Define parent object template, or use the default admin change list template
        opts = self.model._meta
        app_label = opts.app_label
        parent_template_list = super(DescriptionAdminMixin, self).change_list_template or [
            'admin/%s/%s/change_list.html' % (app_label, opts.model_name),
            'admin/%s/change_list.html' % app_label,
            'admin/change_list.html'
            ]
        parent_template = SimpleTemplateResponse(None).resolve_template(parent_template_list)

        extra_context = extra_context or {}
        extra_context.update({
            'description': self.description,
            'parent_template': parent_template,
        })
        return super(DescriptionAdminMixin, self).changelist_view(request, extra_context=extra_context)

[description_change_list.html]
{% extends parent_template %}
{% block object-tools %}
{% block description %}
{% if description %}{{ description }}{% endif %}
{% endblock description %}
{{ block.super }}
{% endblock %}

Is there any better solution? Is there a way for the AdminObject to provide the default template, something like get_change_list_template() to avoid doing the template resolution? Or even better some built-in way of getting the template of the parent class?



--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/62cb6134-cae1-48a0-8938-41604553d07f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment