import datetime
import inspect
from functools import wraps
from django.conf import settings
from django.contrib import admin
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db import models
from django.shortcuts import redirect
from django.utils import importlib
from django.utils.html import escape
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
def get_modeladmin(model, import_module=True):
""" returns the modeladmin registred for model """
for k,v in admin.site._registry.iteritems():
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 models.Model in model.__mro__:
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):
opts = obj._meta
view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
return reverse(view_name, args=(obj.pk,))
@admin_field
def admin_link(*args, **kwargs):
instance = args[-1]
if kwargs['field'] in ['id', 'pk', '__unicode__']:
obj = instance
else:
try:
obj = get_field_value(instance, kwargs['field'])
except ObjectDoesNotExist:
return '---'
if not getattr(obj, 'pk', None):
return '---'
url = change_url(obj)
extra = ''
if kwargs['popup']:
extra = 'onclick="return showAddAnotherPopup(this);"'
return '%s' % (url, extra, obj)
@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 = '%s' % (color, value)
if kwargs.get('bold', True):
colored_value = '%s' % colored_value
return mark_safe(colored_value)
@admin_field
def admin_date(*args, **kwargs):
instance = args[-1]
value = get_field_value(instance, kwargs['field'])
if not value:
return kwargs.get('default', '')
if isinstance(value, datetime.datetime):
natural = humanize.naturaldatetime(value)
else:
natural = humanize.naturaldate(value)
return '{1}'.format(
escape(str(value)), escape(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)