You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
9.3 KiB
216 lines
9.3 KiB
# -*- coding: utf-8 -*-
|
|
|
|
import six
|
|
from django import get_version
|
|
from django.conf import settings
|
|
from django.contrib import admin
|
|
from django.contrib.admin.utils import model_format_dict
|
|
from django.db.models.fields import BLANK_CHOICE_DASH
|
|
from django.utils.timezone import template_localtime
|
|
from django_excel_response import ExcelResponse
|
|
from django_six import gettext_lazy as _
|
|
|
|
|
|
if not hasattr(settings, 'DJANGO_ADMIN_DISABLE_DELETE_SELECTED') or settings.DJANGO_ADMIN_DISABLE_DELETE_SELECTED:
|
|
# Django 2.x will raise error as below.
|
|
# TODO: Solution
|
|
#
|
|
# File "/Users/hqm/Envs/py37/lib/python3.7/site-packages/django_admin/__init__.py", line 3, in <module>
|
|
# from django_admin.djadmin import DeleteModelAdmin, ReadonlyModelAdmin, Readonly2ModelAdmin, ExportExcelModelAdmin, AdvancedExportExcelModelAdmin, ReadOnlyModelAdmin, ChangeOnlyModelAdmin, DeleteonlyModelAdmin, DeleteOnlyModelAdmin, AddOnlyModelAdmin, AdvancedActionsModelAdmin, SpecifiedQuantityQuerySetModelAdmin
|
|
# File "/Users/hqm/Envs/py37/lib/python3.7/site-packages/django_admin/djadmin.py", line 15, in <module>
|
|
# admin.site.disable_action('delete_selected')
|
|
# File "/Users/hqm/Envs/py37/lib/python3.7/site-packages/django/utils/functional.py", line 256, in inner
|
|
# self._setup()
|
|
# File "/Users/hqm/Envs/py37/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 530, in _setup
|
|
# AdminSiteClass = import_string(apps.get_app_config('admin').default_site)
|
|
# File "/Users/hqm/Envs/py37/lib/python3.7/site-packages/django/apps/registry.py", line 153, in get_app_config
|
|
# self.check_apps_ready()
|
|
# File "/Users/hqm/Envs/py37/lib/python3.7/site-packages/django/apps/registry.py", line 135, in check_apps_ready
|
|
# raise AppRegistryNotReady("Apps aren't loaded yet.")
|
|
# django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
|
|
if get_version()[0] == 1:
|
|
admin.site.disable_action('delete_selected')
|
|
|
|
|
|
class AdvancedActionsModelAdmin(object):
|
|
def get_action_choices(self, request, default_choices=BLANK_CHOICE_DASH):
|
|
"""
|
|
Return a list of choices for use in a form object. Each choice is a tuple (name, description).
|
|
"""
|
|
actions_exclude = self.actions_exclude if hasattr(self, 'actions_exclude') else []
|
|
choices = [] + default_choices
|
|
for func, name, description in six.itervalues(self.get_actions(request)):
|
|
if name in actions_exclude:
|
|
continue
|
|
choice = (name, description % model_format_dict(self.opts))
|
|
choices.append(choice)
|
|
return choices
|
|
|
|
|
|
class DeleteModelAdmin(object):
|
|
actions = ['override_delete_selected']
|
|
|
|
def override_delete_selected(modeladmin, request, queryset):
|
|
for query in queryset:
|
|
modeladmin.delete_model(request, query)
|
|
|
|
override_delete_selected.short_description = _(u'Delete selected %(verbose_name_plural)s')
|
|
|
|
|
|
class ExportExcelModelAdmin(object):
|
|
actions = ['export_excel']
|
|
|
|
def export_excel(modeladmin, request, queryset):
|
|
force_csv = (hasattr(settings, 'DJANGO_EXCEL_RESPONSE') and settings.DJANGO_EXCEL_RESPONSE) or (hasattr(modeladmin, 'force_csv') and modeladmin.force_csv)
|
|
return ExcelResponse(queryset, output_name=modeladmin.model._meta.verbose_name_plural, force_csv=force_csv)
|
|
|
|
export_excel.short_description = _(u'Export selected %(verbose_name_plural)s as Excel')
|
|
|
|
|
|
class AdvancedExportExcelModelAdmin(object):
|
|
actions = ['advanced_export_excel']
|
|
|
|
def excel_item(modeladmin, query, field):
|
|
foo_field = 'get_{0}_display'.format(field)
|
|
return str(getattr(query, foo_field)() if hasattr(query, foo_field) else template_localtime(getattr(query, field)))
|
|
|
|
def excel_data(modeladmin, request, query, model_fields, has_extra_excel_fields):
|
|
excel_item = [modeladmin.excel_item(query, field) for field in model_fields]
|
|
return excel_item + list(modeladmin.add_extra_excel_fields(request, query)) if has_extra_excel_fields else excel_item
|
|
|
|
def advanced_export_excel(modeladmin, request, queryset):
|
|
has_excel_headers = hasattr(modeladmin, 'excel_headers')
|
|
has_excel_headers_mapping = hasattr(modeladmin, 'excel_headers_mapping')
|
|
has_excel_fields = hasattr(modeladmin, 'excel_fields')
|
|
has_excel_fields_exclude = hasattr(modeladmin, 'excel_fields_exclude')
|
|
has_extra_excel_fields = hasattr(modeladmin, 'extra_excel_fields') # Add by call add_extra_excel_fields
|
|
|
|
model_fields = list(modeladmin.excel_fields) if has_excel_fields else [f.name for f in modeladmin.model._meta.fields]
|
|
if has_excel_fields_exclude:
|
|
model_fields = [field for field in model_fields if field not in set(modeladmin.excel_fields_exclude)]
|
|
|
|
excel_headers = modeladmin.excel_headers if has_excel_headers else (model_fields + list(modeladmin.extra_excel_fields) if has_extra_excel_fields else model_fields)
|
|
excel_headers = [(modeladmin.excel_headers_mapping.get(header) or header) for header in excel_headers] if has_excel_headers_mapping else excel_headers
|
|
|
|
excel_data = [excel_headers]
|
|
excel_data += [modeladmin.excel_data(request, query, model_fields, has_extra_excel_fields) for query in queryset]
|
|
|
|
force_csv = (hasattr(settings, 'DJANGO_EXCEL_RESPONSE') and settings.DJANGO_EXCEL_RESPONSE) or (hasattr(modeladmin, 'force_csv') and modeladmin.force_csv)
|
|
|
|
return ExcelResponse(excel_data, output_name=modeladmin.model._meta.verbose_name_plural, force_csv=force_csv)
|
|
|
|
advanced_export_excel.short_description = _(u'Advanced Export selected %(verbose_name_plural)s as Excel')
|
|
|
|
|
|
class ReadonlyModelAdmin(object):
|
|
""" Readonly for Update. """
|
|
def get_readonly_fields(self, request, obj=None):
|
|
if not hasattr(self, 'readonly_fields_exclude'):
|
|
self.readonly_fields_exclude = ()
|
|
if obj: # editing an existing object
|
|
return tuple(set(self.readonly_fields) | set(f.name for f in self.model._meta.fields) - set(self.readonly_fields_exclude))
|
|
return tuple(set(self.readonly_fields) - set(self.readonly_fields_exclude))
|
|
|
|
|
|
class Readonly2ModelAdmin(object):
|
|
""" Readonly for Add/Update. """
|
|
def get_readonly_fields(self, request, obj=None):
|
|
if not hasattr(self, 'readonly_fields_exclude'):
|
|
self.readonly_fields_exclude = ()
|
|
return tuple(set(self.readonly_fields) | set(f.name for f in self.model._meta.fields) - set(self.readonly_fields_exclude))
|
|
|
|
|
|
class ReadOnlyModelAdmin(ReadonlyModelAdmin):
|
|
""" Disables all editing capabilities. """
|
|
change_form_template = 'admin/readonly_form.html'
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(ReadOnlyModelAdmin, self).__init__(*args, **kwargs)
|
|
|
|
def get_actions(self, request):
|
|
actions = super(ReadOnlyModelAdmin, self).get_actions(request)
|
|
if 'delete_selected' in actions:
|
|
del actions['delete_selected']
|
|
return actions
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
pass
|
|
|
|
def delete_model(self, request, obj):
|
|
pass
|
|
|
|
def save_related(self, request, form, formsets, change):
|
|
pass
|
|
|
|
|
|
class ChangeOnlyModelAdmin(object):
|
|
""" Disables add/delete capabilities. """
|
|
def get_actions(self, request):
|
|
actions = super(ChangeOnlyModelAdmin, self).get_actions(request)
|
|
if 'delete_selected' in actions:
|
|
del actions['delete_selected']
|
|
return actions
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
def delete_model(self, request, obj):
|
|
pass
|
|
|
|
|
|
class DeleteonlyModelAdmin(object):
|
|
""" Disables add/change capabilities. """
|
|
change_form_template = 'admin/deleteonly_form.html'
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
|
|
class DeleteOnlyModelAdmin(ReadonlyModelAdmin, DeleteonlyModelAdmin):
|
|
""" Disables add/change capabilities, fields readonly. """
|
|
|
|
|
|
class AddOnlyModelAdmin(ReadonlyModelAdmin):
|
|
""" Disables delete/change capabilities, fields readonly.. """
|
|
change_form_template = 'admin/addonly_form.html'
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(AddOnlyModelAdmin, self).__init__(*args, **kwargs)
|
|
|
|
def get_actions(self, request):
|
|
actions = super(AddOnlyModelAdmin, self).get_actions(request)
|
|
if 'delete_selected' in actions:
|
|
del actions['delete_selected']
|
|
return actions
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
def delete_model(self, request, obj):
|
|
pass
|
|
|
|
|
|
class SpecifiedQuantityQuerySetModelAdmin(object):
|
|
""" Can Only Exist Specified Quantity QuerySet """
|
|
def save_model(self, request, obj, form, change):
|
|
# Change or Add
|
|
if change:
|
|
obj.save()
|
|
# Assign ``specified_quantity_queryset`` as 1 when ``specified_quantity_queryset`` not exists
|
|
if not hasattr(self, 'specified_quantity_queryset'):
|
|
self.specified_quantity_queryset = 1
|
|
# Assert whether ``specified_quantity_queryset`` is ``int`` or not
|
|
assert isinstance(self.specified_quantity_queryset, int)
|
|
if self.model.objects.count() >= self.specified_quantity_queryset:
|
|
return
|
|
obj.save()
|