186 lines
5.9 KiB
Python
186 lines
5.9 KiB
Python
|
import datetime
|
||
|
import importlib
|
||
|
import inspect
|
||
|
from functools import wraps
|
||
|
|
||
|
from django.conf import settings
|
||
|
from django.contrib import admin
|
||
|
from django.core.exceptions import ObjectDoesNotExist
|
||
|
from django.urls import reverse, NoReverseMatch
|
||
|
from django.db import models
|
||
|
from django.shortcuts import redirect
|
||
|
from django.utils import timezone
|
||
|
from django.utils.html import escape, format_html
|
||
|
from django.utils.safestring import mark_safe
|
||
|
|
||
|
from orchestra.models.utils import get_field_value
|
||
|
from orchestra.utils import humanize
|
||
|
|
||
|
from .decorators import admin_field
|
||
|
from .html import monospace_format, code_format
|
||
|
|
||
|
|
||
|
def get_modeladmin(model, import_module=True):
|
||
|
""" returns the modeladmin registred for model """
|
||
|
for k,v in admin.site._registry.items():
|
||
|
if k is model:
|
||
|
return v
|
||
|
if import_module:
|
||
|
# Sometimes the admin module is not yet imported
|
||
|
app_label = model._meta.app_label
|
||
|
for app in settings.INSTALLED_APPS:
|
||
|
if app.endswith(app_label):
|
||
|
app_label = app
|
||
|
importlib.import_module('%s.%s' % (app_label, 'admin'))
|
||
|
return get_modeladmin(model, import_module=False)
|
||
|
|
||
|
|
||
|
def insertattr(model, name, value):
|
||
|
""" Inserts attribute to a modeladmin """
|
||
|
modeladmin = None
|
||
|
if issubclass(model, models.Model):
|
||
|
modeladmin = get_modeladmin(model)
|
||
|
modeladmin_class = type(modeladmin)
|
||
|
elif not inspect.isclass(model):
|
||
|
modeladmin = model
|
||
|
modeladmin_class = type(modeladmin)
|
||
|
else:
|
||
|
modeladmin_class = model
|
||
|
# Avoid inlines defined on parent class be shared between subclasses
|
||
|
# Seems that if we use tuples they are lost in some conditions like changing
|
||
|
# the tuple in modeladmin.__init__
|
||
|
if not getattr(modeladmin_class, name):
|
||
|
setattr(modeladmin_class, name, [])
|
||
|
setattr(modeladmin_class, name, list(getattr(modeladmin_class, name))+[value])
|
||
|
if modeladmin:
|
||
|
# make sure class and object share the same attribute, to avoid wierd bugs
|
||
|
setattr(modeladmin, name, getattr(modeladmin_class, name))
|
||
|
|
||
|
|
||
|
def wrap_admin_view(modeladmin, view):
|
||
|
""" Add admin authentication to view """
|
||
|
@wraps(view)
|
||
|
def wrapper(*args, **kwargs):
|
||
|
return modeladmin.admin_site.admin_view(view)(*args, **kwargs)
|
||
|
return wrapper
|
||
|
|
||
|
|
||
|
def set_url_query(request, key, value):
|
||
|
""" set default filters for changelist_view """
|
||
|
if key not in request.GET:
|
||
|
request_copy = request.GET.copy()
|
||
|
if callable(value):
|
||
|
value = value(request)
|
||
|
request_copy[key] = value
|
||
|
request.GET = request_copy
|
||
|
request.META['QUERY_STRING'] = request.GET.urlencode()
|
||
|
|
||
|
|
||
|
def action_to_view(action, modeladmin):
|
||
|
""" Converts modeladmin action to view function """
|
||
|
@wraps(action)
|
||
|
def action_view(request, object_id=1, modeladmin=modeladmin, action=action):
|
||
|
queryset = modeladmin.model.objects.filter(pk=object_id)
|
||
|
response = action(modeladmin, request, queryset)
|
||
|
if not response:
|
||
|
opts = modeladmin.model._meta
|
||
|
url = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
|
||
|
return redirect(url, object_id)
|
||
|
return response
|
||
|
return action_view
|
||
|
|
||
|
|
||
|
def change_url(obj):
|
||
|
if obj is not None:
|
||
|
cls = type(obj)
|
||
|
opts = obj._meta
|
||
|
if cls is models.DEFERRED:
|
||
|
opts = cls.__base__._meta
|
||
|
view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
|
||
|
return reverse(view_name, args=(obj.pk,))
|
||
|
raise NoReverseMatch
|
||
|
|
||
|
|
||
|
@admin_field
|
||
|
def admin_link(*args, **kwargs):
|
||
|
instance = args[-1]
|
||
|
if kwargs['field'] in ('id', 'pk', '__str__'):
|
||
|
obj = instance
|
||
|
else:
|
||
|
try:
|
||
|
obj = get_field_value(instance, kwargs['field'])
|
||
|
except ObjectDoesNotExist:
|
||
|
return '---'
|
||
|
if not getattr(obj, 'pk', None):
|
||
|
return '---'
|
||
|
display_ = kwargs.get('display')
|
||
|
if display_:
|
||
|
display_ = getattr(obj, display_, display_)
|
||
|
else:
|
||
|
display_ = obj
|
||
|
try:
|
||
|
url = change_url(obj)
|
||
|
except NoReverseMatch:
|
||
|
# Does not has admin
|
||
|
return str(display_)
|
||
|
extra = ''
|
||
|
if kwargs['popup']:
|
||
|
extra = mark_safe('onclick="return showAddAnotherPopup(this);"')
|
||
|
title = "Change %s" % obj._meta.verbose_name
|
||
|
return format_html('<a href="{}" title="{}" {}>{}</a>', url, title, extra, display_)
|
||
|
|
||
|
|
||
|
@admin_field
|
||
|
def admin_colored(*args, **kwargs):
|
||
|
instance = args[-1]
|
||
|
field = kwargs['field']
|
||
|
value = escape(get_field_value(instance, field))
|
||
|
color = kwargs.get('colors', {}).get(value, 'black')
|
||
|
value = getattr(instance, 'get_%s_display' % field)().upper()
|
||
|
colored_value = '<span style="color: %s;">%s</span>' % (color, value)
|
||
|
if kwargs.get('bold', True):
|
||
|
colored_value = '<b>%s</b>' % colored_value
|
||
|
return mark_safe(colored_value)
|
||
|
|
||
|
|
||
|
@admin_field
|
||
|
def admin_date(*args, **kwargs):
|
||
|
instance = args[-1]
|
||
|
date = get_field_value(instance, kwargs['field'])
|
||
|
if not date:
|
||
|
return kwargs.get('default', '')
|
||
|
if isinstance(date, datetime.datetime):
|
||
|
natural = humanize.naturaldatetime(date)
|
||
|
else:
|
||
|
natural = humanize.naturaldate(date)
|
||
|
if hasattr(date, 'hour'):
|
||
|
date = timezone.localtime(date)
|
||
|
date = date.strftime("%Y-%m-%d %H:%M:%S %Z")
|
||
|
else:
|
||
|
date = date.strftime("%Y-%m-%d")
|
||
|
return format_html('<span title="{0}">{1}</span>', date, natural)
|
||
|
|
||
|
|
||
|
def get_object_from_url(modeladmin, request):
|
||
|
try:
|
||
|
object_id = int(request.path.split('/')[-3])
|
||
|
except ValueError:
|
||
|
return None
|
||
|
else:
|
||
|
return modeladmin.model.objects.get(pk=object_id)
|
||
|
|
||
|
|
||
|
def display_mono(field):
|
||
|
def display(self, log):
|
||
|
content = getattr(log, field)
|
||
|
return monospace_format(escape(content))
|
||
|
display.short_description = field
|
||
|
return display
|
||
|
|
||
|
|
||
|
def display_code(field):
|
||
|
def display(self, log):
|
||
|
return code_format(getattr(log, field))
|
||
|
display.short_description = field
|
||
|
return display
|