Admin cosmetics
This commit is contained in:
parent
c731a73889
commit
ccbda512bf
|
@ -62,15 +62,15 @@ def wrap_admin_view(modeladmin, view):
|
|||
def set_default_filter(queryarg, request, value):
|
||||
""" set default filters for changelist_view """
|
||||
if queryarg not in request.GET:
|
||||
q = request.GET.copy()
|
||||
request_copy = request.GET.copy()
|
||||
if callable(value):
|
||||
value = value(request)
|
||||
q[queryarg] = value
|
||||
request.GET = q
|
||||
request_copy[queryarg] = value
|
||||
request.GET = request_copy
|
||||
request.META['QUERY_STRING'] = request.GET.urlencode()
|
||||
|
||||
|
||||
def link(*args, **kwargs):
|
||||
def admin_link(*args, **kwargs):
|
||||
""" utility function for creating admin links """
|
||||
field = args[0] if args else ''
|
||||
order = kwargs.pop('order', field)
|
||||
|
@ -88,7 +88,7 @@ def link(*args, **kwargs):
|
|||
extra = 'onclick="return showAddAnotherPopup(this);"'
|
||||
return '<a href="%s" %s>%s</a>' % (url, extra, obj)
|
||||
display_link.allow_tags = True
|
||||
display_link.short_description = _(field)
|
||||
display_link.short_description = _(field.replace('_', ' '))
|
||||
display_link.admin_order_field = order
|
||||
return display_link
|
||||
|
||||
|
|
|
@ -94,6 +94,8 @@ class LinkHeaderRouter(DefaultRouter):
|
|||
for _prefix, viewset, __ in self.registry:
|
||||
if _prefix == prefix_or_model or viewset.model == prefix_or_model:
|
||||
return viewset
|
||||
msg = "%s does not have a regiestered viewset" % prefix_or_model
|
||||
raise KeyError(msg)
|
||||
|
||||
def insert(self, prefix_or_model, name, field, **kwargs):
|
||||
""" Dynamically add new fields to an existing serializer """
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.utils.safestring import mark_safe
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import wrap_admin_view, link
|
||||
from orchestra.admin.utils import wrap_admin_view, admin_link
|
||||
from orchestra.core import services
|
||||
|
||||
from .filters import HasMainUserListFilter
|
||||
|
@ -42,7 +42,7 @@ class AccountAdmin(ExtendedModelAdmin):
|
|||
add_form = AccountCreationForm
|
||||
form = AccountChangeForm
|
||||
|
||||
user_link = link('user', order='user__username')
|
||||
user_link = admin_link('user', order='user__username')
|
||||
|
||||
def name(self, account):
|
||||
return account.name
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.utils.safestring import mark_safe
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import link
|
||||
from orchestra.admin.utils import admin_link
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||
|
||||
from .forms import (DatabaseUserChangeForm, DatabaseUserCreationForm,
|
||||
|
@ -21,7 +21,7 @@ class UserInline(admin.TabularInline):
|
|||
readonly_fields = ('user_link',)
|
||||
extra = 0
|
||||
|
||||
user_link = link('user')
|
||||
user_link = admin_link('user')
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Make value input widget bigger """
|
||||
|
@ -38,7 +38,7 @@ class PermissionInline(AccountAdminMixin, admin.TabularInline):
|
|||
extra = 0
|
||||
filter_by_account_fields = ['database']
|
||||
|
||||
database_link = link('database', popup=True)
|
||||
database_link = admin_link('database', popup=True)
|
||||
|
||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||
""" Make value input widget bigger """
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.template.response import TemplateResponse
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ChangeListDefaultFilter, ExtendedModelAdmin
|
||||
from orchestra.admin.utils import wrap_admin_view, link
|
||||
from orchestra.admin.utils import wrap_admin_view, admin_link
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
from orchestra.utils import apps
|
||||
|
||||
|
@ -41,7 +41,7 @@ class DomainInline(admin.TabularInline):
|
|||
extra = 0
|
||||
verbose_name_plural = _("Subdomains")
|
||||
|
||||
domain_link = link()
|
||||
domain_link = admin_link()
|
||||
domain_link.short_description = _("Name")
|
||||
|
||||
def has_add_permission(self, *args, **kwargs):
|
||||
|
|
|
@ -12,7 +12,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from markdown import markdown
|
||||
|
||||
from orchestra.admin import ChangeListDefaultFilter, ExtendedModelAdmin#, ChangeViewActions
|
||||
from orchestra.admin.utils import (link, colored, wrap_admin_view, display_timesince)
|
||||
from orchestra.admin.utils import (admin_link, colored, wrap_admin_view,
|
||||
display_timesince)
|
||||
from orchestra.apps.contacts import settings as contacts_settings
|
||||
|
||||
from .actions import (reject_tickets, resolve_tickets, take_tickets, close_tickets,
|
||||
|
@ -107,8 +108,8 @@ class TicketInline(admin.TabularInline):
|
|||
extra = 0
|
||||
max_num = 0
|
||||
|
||||
creator_link = link('creator')
|
||||
owner_link = link('owner')
|
||||
creator_link = admin_link('creator')
|
||||
owner_link = admin_link('owner')
|
||||
|
||||
def ticket_id(self, instance):
|
||||
return '<b>%s</b>' % link()(self, instance)
|
||||
|
@ -198,9 +199,9 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeView
|
|||
'issues/js/ticket-admin.js',
|
||||
)
|
||||
|
||||
display_creator = link('creator')
|
||||
display_queue = link('queue')
|
||||
display_owner = link('owner')
|
||||
display_creator = admin_link('creator')
|
||||
display_queue = admin_link('queue')
|
||||
display_owner = admin_link('owner')
|
||||
|
||||
def display_summary(self, ticket):
|
||||
context = {
|
||||
|
@ -212,7 +213,7 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin): #TODO ChangeView
|
|||
if msg:
|
||||
context.update({
|
||||
'updated': display_timesince(msg.created_on),
|
||||
'updater': link('author')(self, msg) if msg.author else msg.author_name,
|
||||
'updater': admin_link('author')(self, msg) if msg.author else msg.author_name,
|
||||
})
|
||||
context['updated'] = '. Updated by %(updater)s about %(updated)s' % context
|
||||
return '<h4>Added by %(creator)s about %(created)s%(updated)s</h4>' % context
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.contrib.admin import SimpleListFilter
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .models import Ticket
|
||||
|
||||
|
@ -10,13 +11,19 @@ class MyTicketsListFilter(SimpleListFilter):
|
|||
|
||||
def lookups(self, request, model_admin):
|
||||
return (
|
||||
('True', 'My Tickets'),
|
||||
('False', 'All'),
|
||||
('True', _("My Tickets")),
|
||||
('False', _("All")),
|
||||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value() == 'True':
|
||||
return queryset.involved_by(request.user)
|
||||
|
||||
def choices(self, cl):
|
||||
""" Remove default All """
|
||||
choices = iter(super(MyTicketsListFilter, self).choices(cl))
|
||||
choices.next()
|
||||
return choices
|
||||
|
||||
|
||||
class TicketStateListFilter(SimpleListFilter):
|
||||
|
@ -25,14 +32,14 @@ class TicketStateListFilter(SimpleListFilter):
|
|||
|
||||
def lookups(self, request, model_admin):
|
||||
return (
|
||||
('OPEN', "Open"),
|
||||
(Ticket.NEW, "New"),
|
||||
(Ticket.IN_PROGRESS, "In Progress"),
|
||||
(Ticket.RESOLVED, "Resolved"),
|
||||
(Ticket.FEEDBACK, "Feedback"),
|
||||
(Ticket.REJECTED, "Rejected"),
|
||||
(Ticket.CLOSED, "Closed"),
|
||||
('False', 'All'),
|
||||
('OPEN', _("Open")),
|
||||
(Ticket.NEW, _("New")),
|
||||
(Ticket.IN_PROGRESS, _("In Progress")),
|
||||
(Ticket.RESOLVED, _("Resolved")),
|
||||
(Ticket.FEEDBACK, _("Feedback")),
|
||||
(Ticket.REJECTED, _("Rejected")),
|
||||
(Ticket.CLOSED, _("Closed")),
|
||||
('False', _("All")),
|
||||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
|
@ -41,3 +48,10 @@ class TicketStateListFilter(SimpleListFilter):
|
|||
elif self.value() == 'False':
|
||||
return queryset
|
||||
return queryset.filter(state=self.value())
|
||||
|
||||
def choices(self, cl):
|
||||
""" Remove default All """
|
||||
choices = iter(super(TicketStateListFilter, self).choices(cl))
|
||||
choices.next()
|
||||
return choices
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ from django.contrib.auth.admin import UserAdmin
|
|||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import link
|
||||
from orchestra.admin.utils import admin_link
|
||||
from orchestra.apps.accounts.admin import SelectAccountAdminMixin
|
||||
|
||||
from .forms import ListCreationForm, ListChangeForm
|
||||
|
@ -47,7 +47,7 @@ class ListAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
add_form = ListCreationForm
|
||||
filter_by_account_fields = ['address_domain']
|
||||
|
||||
address_domain_link = link('address_domain', order='address_domain__name')
|
||||
address_domain_link = admin_link('address_domain', order='address_domain__name')
|
||||
|
||||
def get_urls(self):
|
||||
useradmin = UserAdmin(List, self.admin_site)
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from djcelery.humanize import naturaldate
|
||||
|
||||
from orchestra.admin.html import monospace_format
|
||||
from orchestra.admin.utils import link
|
||||
from orchestra.admin.utils import admin_link
|
||||
|
||||
from .models import Server, Route, BackendLog, BackendOperation
|
||||
|
||||
|
@ -60,7 +60,7 @@ class BackendOperationInline(admin.TabularInline):
|
|||
|
||||
def instance_link(self, operation):
|
||||
try:
|
||||
return link('instance')(self, operation)
|
||||
return admin_link('instance')(self, operation)
|
||||
except:
|
||||
return _("deleted {0} {1}").format(
|
||||
escape(operation.content_type), escape(operation.object_id)
|
||||
|
@ -88,11 +88,7 @@ class BackendLogAdmin(admin.ModelAdmin):
|
|||
]
|
||||
readonly_fields = fields
|
||||
|
||||
def server_link(self, log):
|
||||
url = reverse('admin:orchestration_server_change', args=(log.server.pk,))
|
||||
return '<a href="%s">%s</a>' % (url, log.server.name)
|
||||
server_link.short_description = _("server")
|
||||
server_link.allow_tags = True
|
||||
server_link = admin_link('server')
|
||||
|
||||
def display_state(self, log):
|
||||
color = STATE_COLORS.get(log.state, 'grey')
|
||||
|
|
|
@ -1,18 +1,29 @@
|
|||
from django import forms
|
||||
from django.db import models
|
||||
from django.contrib import admin
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ChangeListDefaultFilter
|
||||
from orchestra.admin.filters import UsedContentTypeFilter
|
||||
from orchestra.admin.utils import admin_link
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||
from orchestra.core import services
|
||||
|
||||
from .filters import ActiveOrderListFilter
|
||||
from .models import Service, Order, MetricStorage
|
||||
|
||||
|
||||
class ServiceAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'description', 'content_type', 'handler_type', 'num_orders', 'is_active'
|
||||
)
|
||||
list_filter = ('is_active', 'handler_type', UsedContentTypeFilter)
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'classes': ('wide',),
|
||||
'fields': ('description', 'content_type', 'match', 'handler', 'is_active')
|
||||
'fields': ('description', 'content_type', 'match', 'handler_type',
|
||||
'is_active')
|
||||
}),
|
||||
(_("Billing options"), {
|
||||
'classes': ('wide',),
|
||||
|
@ -36,12 +47,32 @@ class ServiceAdmin(admin.ModelAdmin):
|
|||
if db_field.name in ['match', 'metric']:
|
||||
kwargs['widget'] = forms.TextInput(attrs={'size':'160'})
|
||||
return super(ServiceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
|
||||
|
||||
def num_orders(self, service):
|
||||
num = service.orders.count()
|
||||
url = reverse('admin:orders_order_changelist')
|
||||
url += '?service=%i' % service.pk
|
||||
return '<a href="%s">%d</a>' % (url, num)
|
||||
num_orders.short_description = _("Orders")
|
||||
num_orders.admin_order_field = 'orders__count'
|
||||
num_orders.allow_tags = True
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(ServiceAdmin, self).get_queryset(request)
|
||||
qs = qs.annotate(models.Count('orders'))
|
||||
return qs
|
||||
|
||||
|
||||
class OrderAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
list_display = ('id', 'service', 'account_link', 'cancelled_on')
|
||||
list_filter = ('service',)
|
||||
|
||||
class OrderAdmin(AccountAdminMixin, ChangeListDefaultFilter, admin.ModelAdmin):
|
||||
list_display = (
|
||||
'id', 'service', 'account_link', 'content_object_link', 'cancelled_on'
|
||||
)
|
||||
list_filter = (ActiveOrderListFilter, 'service',)
|
||||
default_changelist_filters = (
|
||||
('is_active', 'True'),
|
||||
)
|
||||
|
||||
content_object_link = admin_link('content_object')
|
||||
|
||||
class MetricStorageAdmin(admin.ModelAdmin):
|
||||
list_display = ('order', 'value', 'created_on', 'updated_on')
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
from django.contrib.admin import SimpleListFilter
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class ActiveOrderListFilter(SimpleListFilter):
|
||||
""" Filter tickets by created_by according to request.user """
|
||||
title = 'Orders'
|
||||
parameter_name = 'is_active'
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
return (
|
||||
('True', _("Active")),
|
||||
('False', _("Inactive")),
|
||||
('None', _("All")),
|
||||
)
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value() == 'True':
|
||||
return queryset.active()
|
||||
elif self.value() == 'False':
|
||||
return queryset.inactive()
|
||||
return queryset
|
||||
|
||||
def choices(self, cl):
|
||||
""" Remove default All """
|
||||
choices = iter(super(ActiveOrderListFilter, self).choices(cl))
|
||||
choices.next()
|
||||
return choices
|
|
@ -12,13 +12,19 @@ class ServiceHandler(plugins.Plugin):
|
|||
def __init__(self, service):
|
||||
self.service = service
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.service, attr)
|
||||
|
||||
@classmethod
|
||||
def get_plugin_choices(cls):
|
||||
choices = super(ServiceHandler, cls).get_plugin_choices()
|
||||
return [('', _("Default"))] + choices
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.service, attr)
|
||||
def get_content_type(self):
|
||||
if not self.model:
|
||||
return self.content_type
|
||||
app_label, model = self.model.split('.')
|
||||
return ContentType.objects.get_by_natural_key(app_label, model.lower())
|
||||
|
||||
def matches(self, instance):
|
||||
safe_locals = {
|
||||
|
@ -27,13 +33,8 @@ class ServiceHandler(plugins.Plugin):
|
|||
return eval(self.match, safe_locals)
|
||||
|
||||
def get_metric(self, instance):
|
||||
safe_locals = {
|
||||
instance._meta.model_name: instance
|
||||
}
|
||||
return eval(self.metric, safe_locals)
|
||||
|
||||
def get_content_type(self):
|
||||
if not self.model:
|
||||
return self.content_type
|
||||
app_label, model = self.model.split('.')
|
||||
return ContentType.objects.get_by_natural_key(app_label, model.lower())
|
||||
if self.metric:
|
||||
safe_locals = {
|
||||
instance._meta.model_name: instance
|
||||
}
|
||||
return eval(self.metric, safe_locals)
|
||||
|
|
|
@ -31,7 +31,7 @@ def search_for_related(origin, max_depth=2):
|
|||
if hasattr(node, 'account') or isinstance(node, Account):
|
||||
return node
|
||||
for related in related_iterator(node):
|
||||
if related not in models:
|
||||
if related and related not in models:
|
||||
new_models = list(models)
|
||||
new_models.append(related)
|
||||
queue.append(new_models)
|
||||
|
|
|
@ -45,8 +45,10 @@ class Service(models.Model):
|
|||
description = models.CharField(_("description"), max_length=256, unique=True)
|
||||
content_type = models.ForeignKey(ContentType, verbose_name=_("content type"))
|
||||
match = models.CharField(_("match"), max_length=256, blank=True)
|
||||
handler = models.CharField(_("handler"), max_length=256, blank=True,
|
||||
help_text=_("Handler used to process this Service."),
|
||||
handler_type = models.CharField(_("handler"), max_length=256, blank=True,
|
||||
help_text=_("Handler used for processing this Service. A handler "
|
||||
"enables customized behaviour far beyond what options "
|
||||
"here allow to."),
|
||||
choices=ServiceHandler.get_plugin_choices())
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
# Billing
|
||||
|
@ -172,14 +174,16 @@ class Service(models.Model):
|
|||
cache.set(ct, services)
|
||||
return services
|
||||
|
||||
# FIXME some times caching is nasty, do we really have to? make get_plugin more efficient?
|
||||
@cached_property
|
||||
def proxy(self):
|
||||
if self.handler:
|
||||
return ServiceHandler.get_plugin(self.handler)(self)
|
||||
def handler(self):
|
||||
""" Accessor of this service handler instance """
|
||||
if self.handler_type:
|
||||
return ServiceHandler.get_plugin(self.handler_type)(self)
|
||||
return ServiceHandler(self)
|
||||
|
||||
def clean(self):
|
||||
content_type = self.proxy.get_content_type()
|
||||
content_type = self.handler.get_content_type()
|
||||
if self.content_type != content_type:
|
||||
msg =_("Content type must be equal to '%s'." % str(content_type))
|
||||
raise ValidationError(msg)
|
||||
|
@ -191,22 +195,30 @@ class Service(models.Model):
|
|||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
self.proxy.matches(obj)
|
||||
except Exception as e:
|
||||
raise ValidationError(_(str(e)))
|
||||
for attr in ['matches', 'get_metric']:
|
||||
try:
|
||||
getattr(self.handler, attr)(obj)
|
||||
except Exception as exception:
|
||||
name = type(exception).__name__
|
||||
message = exception.message
|
||||
msg = "{0} {1}: {2}".format(attr, name, message)
|
||||
raise ValidationError(msg)
|
||||
|
||||
|
||||
class OrderQuerySet(models.QuerySet):
|
||||
def by_object(self, obj, *args, **kwargs):
|
||||
def by_object(self, obj, **kwargs):
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
return self.filter(object_id=obj.pk, content_type=ct)
|
||||
return self.filter(object_id=obj.pk, content_type=ct, **kwargs)
|
||||
|
||||
def active(self, *args, **kwargs):
|
||||
def active(self, **kwargs):
|
||||
""" return active orders """
|
||||
return self.filter(
|
||||
Q(cancelled_on__isnull=True) | Q(cancelled_on__gt=timezone.now())
|
||||
).filter(*args, **kwargs)
|
||||
).filter(**kwargs)
|
||||
|
||||
def inactive(self, **kwargs):
|
||||
""" return inactive orders """
|
||||
return self.filter(cancelled_on__lt=timezone.now(), **kwargs)
|
||||
|
||||
|
||||
class Order(models.Model):
|
||||
|
@ -234,10 +246,12 @@ class Order(models.Model):
|
|||
|
||||
def update(self):
|
||||
instance = self.content_object
|
||||
if self.service.metric:
|
||||
metric = self.service.get_metric(instance)
|
||||
MetricStorage.store(self, metric)
|
||||
description = "{}: {}".format(self.service.description, str(instance))
|
||||
handler = self.service.handler
|
||||
if handler.metric:
|
||||
metric = handler.get_metric(instance)
|
||||
if metric is not None:
|
||||
MetricStorage.store(self, metric)
|
||||
description = "{}: {}".format(handler.description, str(instance))
|
||||
if self.description != description:
|
||||
self.description = description
|
||||
self.save()
|
||||
|
@ -246,7 +260,7 @@ class Order(models.Model):
|
|||
def update_orders(cls, instance):
|
||||
for service in Service.get_services(instance):
|
||||
orders = Order.objects.by_object(instance, service=service).active()
|
||||
if service.matches(instance):
|
||||
if service.handler.matches(instance):
|
||||
if not orders:
|
||||
account_id = getattr(instance, 'account_id', instance.pk)
|
||||
order = cls.objects.create(content_object=instance,
|
||||
|
@ -289,23 +303,20 @@ class MetricStorage(models.Model):
|
|||
|
||||
@receiver(pre_delete, dispatch_uid="orders.cancel_orders")
|
||||
def cancel_orders(sender, **kwargs):
|
||||
if (not sender in [MetricStorage, LogEntry, Order, Service] and
|
||||
not Service in sender.__mro__):
|
||||
instance = kwargs['instance']
|
||||
for order in Order.objects.by_object(instance).active():
|
||||
order.cancel()
|
||||
if sender not in [MetricStorage, LogEntry, Order, Service]:
|
||||
instance = kwargs['instance']
|
||||
for order in Order.objects.by_object(instance).active():
|
||||
order.cancel()
|
||||
|
||||
|
||||
@receiver(post_save, dispatch_uid="orders.update_orders")
|
||||
@receiver(post_delete, dispatch_uid="orders.update_orders")
|
||||
def update_orders(sender, **kwargs):
|
||||
if (not sender in [MetricStorage, LogEntry, Order, Service] and
|
||||
not Service in sender.__mro__):
|
||||
instance = kwargs['instance']
|
||||
print kwargs
|
||||
if instance.pk:
|
||||
# post_save
|
||||
Order.update_orders(instance)
|
||||
related = search_for_related(instance)
|
||||
if related:
|
||||
Order.update_orders(related)
|
||||
if sender not in [MetricStorage, LogEntry, Order, Service]:
|
||||
instance = kwargs['instance']
|
||||
if instance.pk:
|
||||
# post_save
|
||||
Order.update_orders(instance)
|
||||
related = search_for_related(instance)
|
||||
if related:
|
||||
Order.update_orders(related)
|
||||
|
|
|
@ -7,7 +7,7 @@ from djcelery.humanize import naturaldate
|
|||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.filters import UsedContentTypeFilter
|
||||
from orchestra.admin.utils import insertattr, get_modeladmin, link
|
||||
from orchestra.admin.utils import insertattr, get_modeladmin, admin_link
|
||||
from orchestra.core import services
|
||||
from orchestra.utils import running_syncdb
|
||||
|
||||
|
@ -71,10 +71,7 @@ class ResourceDataAdmin(admin.ModelAdmin):
|
|||
list_filter = ('resource',)
|
||||
readonly_fields = ('content_object_link',)
|
||||
|
||||
def content_object_link(self, data):
|
||||
return link('content_object')(self, data)
|
||||
content_object_link.allow_tags = True
|
||||
content_object_link.short_description = _("Content object")
|
||||
content_object_link = admin_link('content_object')
|
||||
|
||||
|
||||
class MonitorDataAdmin(admin.ModelAdmin):
|
||||
|
@ -82,10 +79,7 @@ class MonitorDataAdmin(admin.ModelAdmin):
|
|||
list_filter = ('monitor',)
|
||||
readonly_fields = ('content_object_link',)
|
||||
|
||||
def content_object_link(self, data):
|
||||
return link('content_object')(self, data)
|
||||
content_object_link.allow_tags = True
|
||||
content_object_link.short_description = _("Content object")
|
||||
content_object_link = admin_link('content_object')
|
||||
|
||||
|
||||
admin.site.register(Resource, ResourceAdmin)
|
||||
|
|
|
@ -164,7 +164,15 @@ def create_resource_relation():
|
|||
class ResourceHandler(object):
|
||||
""" account.resources.web """
|
||||
def __getattr__(self, attr):
|
||||
return self.obj.resource_set.get(resource__name=attr)
|
||||
""" get or create ResourceData """
|
||||
try:
|
||||
return self.obj.resource_set.get(resource__name=attr)
|
||||
except ResourceData.DoesNotExist:
|
||||
model = self.obj._meta.model_name
|
||||
resource = Resource.objects.get(content_type__model=model,
|
||||
name=attr, is_active=True)
|
||||
return ResourceData.objects.create(content_object=self.obj,
|
||||
resource=resource)
|
||||
|
||||
def __get__(self, obj, cls):
|
||||
self.obj = obj
|
||||
|
|
|
@ -27,7 +27,10 @@ if not running_syncdb():
|
|||
# TODO why this is even loaded during syncdb?
|
||||
for resources in Resource.group_by_content_type():
|
||||
model = resources[0].content_type.model_class()
|
||||
router.insert(model, 'resources', ResourceSerializer, required=False, many=True)
|
||||
try:
|
||||
router.insert(model, 'resources', ResourceSerializer, required=False, many=True)
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
def validate_resources(self, attrs, source, _resources=resources):
|
||||
""" Creates missing resources """
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.utils.safestring import mark_safe
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import insertattr, link
|
||||
from orchestra.admin.utils import insertattr, admin_link
|
||||
from orchestra.apps.accounts.admin import SelectAccountAdminMixin
|
||||
from orchestra.apps.domains.forms import DomainIterator
|
||||
from orchestra.apps.users.roles.admin import RoleAdmin
|
||||
|
@ -79,7 +79,7 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
|||
filter_by_account_fields = ['domain']
|
||||
filter_horizontal = ['mailboxes']
|
||||
|
||||
domain_link = link('domain', order='domain__name')
|
||||
domain_link = admin_link('domain', order='domain__name')
|
||||
|
||||
def email_link(self, address):
|
||||
link = self.domain_link(address)
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.safestring import mark_safe
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orchestra.admin import ExtendedModelAdmin
|
||||
from orchestra.admin.utils import link
|
||||
from orchestra.admin.utils import admin_link
|
||||
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||
from orchestra.apps.accounts.widgets import account_related_field_widget_factory
|
||||
|
||||
|
@ -35,7 +35,7 @@ class ContentInline(AccountAdminMixin, admin.TabularInline):
|
|||
readonly_fields = ('webapp_link', 'webapp_type')
|
||||
filter_by_account_fields = ['webapp']
|
||||
|
||||
webapp_link = link('webapp', popup=True)
|
||||
webapp_link = admin_link('webapp', popup=True)
|
||||
webapp_link.short_description = _("Web App")
|
||||
|
||||
def webapp_type(self, content):
|
||||
|
|
Loading…
Reference in New Issue