Add spreadsheet export functionality to ModelAdmin

pull/5888/head
jacobtoppm 2020-03-09 17:54:26 +00:00
rodzic 877675bafb
commit 8e88f3535c
4 zmienionych plików z 48 dodań i 10 usunięć
wagtail
admin/views
contrib/modeladmin
templates/modeladmin

Wyświetl plik

@ -1,4 +1,6 @@
import csv
import datetime
from xlsxwriter.workbook import Workbook
from collections import OrderedDict
@ -51,7 +53,10 @@ class SpreadsheetExportMixin:
def write_xlsx_row(self, worksheet, row_dict, row_number):
for col_number, (field, value) in enumerate(row_dict.items()):
preprocess_function = self.custom_xlsx_field_preprocess.get(field, force_str)
if not isinstance(value, (datetime.date, datetime.time)):
preprocess_function = self.custom_xlsx_field_preprocess.get(field, force_str)
else:
preprocess_function = self.custom_xlsx_field_preprocess.get(field)
processed_value = preprocess_function(value) if preprocess_function else value
worksheet.write(row_number, col_number, processed_value)
@ -143,7 +148,6 @@ class LockedPagesView(ReportView):
title = _('Locked Pages')
header_icon = 'locked'
export_heading_overrides = {'latest_revision_created_at': _("Updated"), 'status_string': _("Status"), 'content_type.model_class._meta.verbose_name.title': _("Type")}
custom_xlsx_field_preprocess = {'latest_revision_created_at': None, 'locked_at': None}
list_export = ['title', 'latest_revision_created_at', 'status_string', 'content_type.model_class._meta.verbose_name.title', 'locked_at', 'locked_by']
def get_queryset(self):

Wyświetl plik

@ -74,6 +74,7 @@ class ModelAdmin(WagtailRegisterable):
menu_order = None
list_display = ('__str__',)
list_display_add_buttons = None
list_export = ()
inspect_view_fields = []
inspect_view_fields_exclude = []
inspect_view_enabled = False
@ -202,6 +203,13 @@ class ModelAdmin(WagtailRegisterable):
return self.list_display_add_buttons or self.get_list_display(
request)[0]
def get_list_export(self, request):
"""
Return a sequence containing the fields/method output to be displayed
in spreadsheet exports.
"""
return self.list_export
def get_empty_value_display(self, field_name=None):
"""
Return the empty_value_display value defined on ModelAdmin

Wyświetl plik

@ -24,13 +24,13 @@
{% block search %}{% search_form %}{% endblock %}
</div>
{% block header_extra %}
{% if user_can_create %}
<div class="right">
<div class="addbutton">
<div class="right">
{% if user_can_create %}
<span class="addbutton">
{% include 'modeladmin/includes/button.html' with button=view.button_helper.add_button %}
</div>
</div>
{% endif %}
</span>
{% endif %}
</div>
{% endblock %}
</div>
</header>
@ -86,6 +86,13 @@
</nav>
{% endblock %}
{% if view.list_export %}
<div class="nice-padding col9">
<a href="?export=base&{{ request.GET.urlencode }}" class="button bicolor icon icon-download">{% trans 'Download all' %}</a>
<a href="?export=base&{{ request.GET.urlencode }}" class="button bicolor icon icon-download">{% trans 'Download filtered' %}</a>
</div>
{% endif %}
{% endblock %}
</div>
</div>

Wyświetl plik

@ -24,6 +24,7 @@ from django.views.generic import TemplateView
from django.views.generic.edit import FormView
from wagtail.admin import messages
from wagtail.admin.views.reports import SpreadsheetExportMixin
from .forms import ParentChooserForm
@ -212,14 +213,15 @@ class InstanceSpecificView(WMABaseView):
return super().get_context_data(**context)
class IndexView(WMABaseView):
class IndexView(SpreadsheetExportMixin, WMABaseView):
ORDER_VAR = 'o'
ORDER_TYPE_VAR = 'ot'
PAGE_VAR = 'p'
SEARCH_VAR = 'q'
ERROR_FLAG = 'e'
IGNORED_PARAMS = (ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR)
EXPORT_VAR = 'export'
IGNORED_PARAMS = (ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, EXPORT_VAR)
# sortable_by is required by the django.contrib.admin.templatetags.admin_list.result_headers
# template tag as of Django 2.1 - see https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.sortable_by
@ -231,12 +233,14 @@ class IndexView(WMABaseView):
if not self.permission_helper.user_can_list(request.user):
raise PermissionDenied
self.list_export = self.model_admin.get_list_export(request)
self.list_display = self.model_admin.get_list_display(request)
self.list_filter = self.model_admin.get_list_filter(request)
self.search_fields = self.model_admin.get_search_fields(request)
self.items_per_page = self.model_admin.list_per_page
self.select_related = self.model_admin.list_select_related
self.search_handler = self.model_admin.get_search_handler(request, self.search_fields)
self.export = (request.GET.get(self.EXPORT_VAR))
# Get search parameters from the query string.
try:
@ -249,12 +253,27 @@ class IndexView(WMABaseView):
del self.params[self.PAGE_VAR]
if self.ERROR_FLAG in self.params:
del self.params[self.ERROR_FLAG]
if self.EXPORT_VAR in self.params:
del self.params[self.EXPORT_VAR]
self.query = request.GET.get(self.SEARCH_VAR, '')
if self.export == 'base':
return self.as_spreadsheet(self.get_base_queryset(request=request))
self.queryset = self.get_queryset(request)
if self.export == 'current':
return self.as_spreadsheet(self.queryset)
return super().dispatch(request, *args, **kwargs)
def get_heading(self, queryset, field):
heading_override = self.export_heading_overrides.get(field)
if heading_override:
return force_str(heading_override)
return force_str(label_for_field(field, model=self.model))
@property
def media(self):
return forms.Media(