2014-05-08 16:59:35 +00:00
|
|
|
from django import forms
|
2014-08-19 18:59:23 +00:00
|
|
|
from django.conf.urls import patterns, url
|
2014-05-08 16:59:35 +00:00
|
|
|
from django.contrib import admin
|
2014-09-03 22:01:44 +00:00
|
|
|
from django.contrib.admin.utils import unquote
|
2014-05-08 16:59:35 +00:00
|
|
|
from django.forms.models import BaseInlineFormSet
|
2014-09-26 19:21:09 +00:00
|
|
|
from django.shortcuts import render, redirect
|
2014-09-28 12:28:57 +00:00
|
|
|
from django.utils.text import camel_case_to_spaces
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2014-09-26 19:21:09 +00:00
|
|
|
from .utils import set_url_query, action_to_view, wrap_admin_view
|
2014-05-08 16:59:35 +00:00
|
|
|
|
2014-08-19 18:59:23 +00:00
|
|
|
|
|
|
|
class ChangeListDefaultFilter(object):
|
|
|
|
"""
|
|
|
|
Enables support for default filtering on admin change list pages
|
|
|
|
Your model admin class should define an default_changelist_filters attribute
|
|
|
|
default_changelist_filters = (('my_nodes', 'True'),)
|
|
|
|
"""
|
|
|
|
default_changelist_filters = ()
|
|
|
|
|
|
|
|
def changelist_view(self, request, extra_context=None):
|
|
|
|
""" Default filter as 'my_nodes=True' """
|
|
|
|
defaults = []
|
|
|
|
for key, value in self.default_changelist_filters:
|
|
|
|
set_url_query(request, key, value)
|
|
|
|
defaults.append(key)
|
|
|
|
# hack response cl context in order to hook default filter awaearness
|
|
|
|
# into search_form.html template
|
|
|
|
response = super(ChangeListDefaultFilter, self).changelist_view(request,
|
|
|
|
extra_context=extra_context)
|
|
|
|
if hasattr(response, 'context_data') and 'cl' in response.context_data:
|
|
|
|
response.context_data['cl'].default_changelist_filters = defaults
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
class AtLeastOneRequiredInlineFormSet(BaseInlineFormSet):
|
|
|
|
def clean(self):
|
|
|
|
"""Check that at least one service has been entered."""
|
|
|
|
super(AtLeastOneRequiredInlineFormSet, self).clean()
|
|
|
|
if any(self.errors):
|
|
|
|
return
|
|
|
|
if not any(cleaned_data and not cleaned_data.get('DELETE', False)
|
|
|
|
for cleaned_data in self.cleaned_data):
|
|
|
|
raise forms.ValidationError('At least one item required.')
|
|
|
|
|
|
|
|
|
|
|
|
class ChangeViewActionsMixin(object):
|
|
|
|
""" Makes actions visible on the admin change view page. """
|
|
|
|
|
|
|
|
change_view_actions = ()
|
|
|
|
change_form_template = 'orchestra/admin/change_form.html'
|
|
|
|
|
|
|
|
def get_urls(self):
|
|
|
|
"""Returns the additional urls for the change view links"""
|
|
|
|
urls = super(ChangeViewActionsMixin, self).get_urls()
|
|
|
|
admin_site = self.admin_site
|
|
|
|
opts = self.model._meta
|
|
|
|
new_urls = patterns('')
|
|
|
|
for action in self.get_change_view_actions():
|
|
|
|
new_urls += patterns('',
|
|
|
|
url('^(\d+)/%s/$' % action.url_name,
|
|
|
|
admin_site.admin_view(action),
|
|
|
|
name='%s_%s_%s' % (opts.app_label,
|
2014-09-03 22:01:44 +00:00
|
|
|
opts.model_name,
|
2014-08-19 18:59:23 +00:00
|
|
|
action.url_name)))
|
|
|
|
return new_urls + urls
|
|
|
|
|
2014-09-16 17:14:24 +00:00
|
|
|
def get_change_view_actions(self, obj=None):
|
|
|
|
""" allow customization on modelamdin """
|
2014-08-19 18:59:23 +00:00
|
|
|
views = []
|
|
|
|
for action in self.change_view_actions:
|
|
|
|
if isinstance(action, basestring):
|
|
|
|
action = getattr(self, action)
|
|
|
|
view = action_to_view(action, self)
|
|
|
|
view.url_name = getattr(action, 'url_name', action.__name__)
|
|
|
|
view.verbose_name = getattr(action, 'verbose_name',
|
|
|
|
view.url_name.capitalize().replace('_', ' '))
|
|
|
|
view.css_class = getattr(action, 'css_class', 'historylink')
|
|
|
|
view.description = getattr(action, 'description', '')
|
|
|
|
views.append(view)
|
|
|
|
return views
|
|
|
|
|
2014-09-03 22:01:44 +00:00
|
|
|
def change_view(self, request, object_id, **kwargs):
|
2014-08-19 18:59:23 +00:00
|
|
|
if not 'extra_context' in kwargs:
|
|
|
|
kwargs['extra_context'] = {}
|
2014-09-16 17:14:24 +00:00
|
|
|
obj = self.get_object(request, unquote(object_id))
|
2014-08-19 18:59:23 +00:00
|
|
|
kwargs['extra_context']['object_tools_items'] = [
|
2014-09-16 17:14:24 +00:00
|
|
|
action.__dict__ for action in self.get_change_view_actions(obj=obj)
|
2014-08-19 18:59:23 +00:00
|
|
|
]
|
2014-09-03 22:01:44 +00:00
|
|
|
return super(ChangeViewActionsMixin, self).change_view(request, object_id, **kwargs)
|
2014-08-19 18:59:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ChangeAddFieldsMixin(object):
|
|
|
|
""" Enables to specify different set of fields for change and add views """
|
2014-05-08 16:59:35 +00:00
|
|
|
add_fields = ()
|
|
|
|
add_fieldsets = ()
|
|
|
|
add_form = None
|
|
|
|
change_readonly_fields = ()
|
|
|
|
|
|
|
|
def get_readonly_fields(self, request, obj=None):
|
2014-08-19 18:59:23 +00:00
|
|
|
fields = super(ChangeAddFieldsMixin, self).get_readonly_fields(request, obj=obj)
|
2014-05-08 16:59:35 +00:00
|
|
|
if obj:
|
|
|
|
return fields + self.change_readonly_fields
|
|
|
|
return fields
|
|
|
|
|
|
|
|
def get_fieldsets(self, request, obj=None):
|
|
|
|
if not obj:
|
|
|
|
if self.add_fieldsets:
|
|
|
|
return self.add_fieldsets
|
|
|
|
elif self.add_fields:
|
|
|
|
return [(None, {'fields': self.add_fields})]
|
2014-08-19 18:59:23 +00:00
|
|
|
return super(ChangeAddFieldsMixin, self).get_fieldsets(request, obj=obj)
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
def get_inline_instances(self, request, obj=None):
|
|
|
|
""" add_inlines and inline.parent_object """
|
|
|
|
self.inlines = getattr(self, 'add_inlines', self.inlines)
|
|
|
|
if obj:
|
|
|
|
self.inlines = type(self).inlines
|
2014-08-19 18:59:23 +00:00
|
|
|
inlines = super(ChangeAddFieldsMixin, self).get_inline_instances(request, obj=obj)
|
2014-05-08 16:59:35 +00:00
|
|
|
for inline in inlines:
|
|
|
|
inline.parent_object = obj
|
|
|
|
return inlines
|
|
|
|
|
|
|
|
def get_form(self, request, obj=None, **kwargs):
|
|
|
|
""" Use special form during user creation """
|
|
|
|
defaults = {}
|
|
|
|
if obj is None and self.add_form:
|
|
|
|
defaults['form'] = self.add_form
|
|
|
|
defaults.update(kwargs)
|
2014-08-19 18:59:23 +00:00
|
|
|
return super(ChangeAddFieldsMixin, self).get_form(request, obj, **defaults)
|
2014-05-08 16:59:35 +00:00
|
|
|
|
|
|
|
|
2014-08-19 18:59:23 +00:00
|
|
|
class ExtendedModelAdmin(ChangeViewActionsMixin, ChangeAddFieldsMixin, admin.ModelAdmin):
|
|
|
|
pass
|
2014-09-26 19:21:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SelectPluginAdminMixin(object):
|
|
|
|
plugin = None
|
|
|
|
plugin_field = None
|
|
|
|
|
|
|
|
def get_form(self, request, obj=None, **kwargs):
|
|
|
|
if obj:
|
2014-09-26 21:24:23 +00:00
|
|
|
self.form = getattr(obj, '%s_class' % self.plugin_field)().get_form()
|
2014-09-26 19:21:09 +00:00
|
|
|
else:
|
|
|
|
self.form = self.plugin.get_plugin(self.plugin_value)().get_form()
|
|
|
|
return super(SelectPluginAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
|
|
|
|
|
|
|
def get_urls(self):
|
|
|
|
""" Hooks select account url """
|
|
|
|
urls = super(SelectPluginAdminMixin, self).get_urls()
|
|
|
|
opts = self.model._meta
|
|
|
|
info = opts.app_label, opts.model_name
|
|
|
|
select_urls = patterns("",
|
|
|
|
url("/select-plugin/$",
|
|
|
|
wrap_admin_view(self, self.select_plugin_view),
|
|
|
|
name='%s_%s_select_plugin' % info),
|
|
|
|
)
|
|
|
|
return select_urls + urls
|
|
|
|
|
|
|
|
def select_plugin_view(self, request):
|
|
|
|
opts = self.model._meta
|
|
|
|
context = {
|
|
|
|
'opts': opts,
|
|
|
|
'app_label': opts.app_label,
|
|
|
|
'field': self.plugin_field,
|
|
|
|
'field_name': opts.get_field_by_name(self.plugin_field)[0].verbose_name,
|
|
|
|
'plugins': self.plugin.get_plugin_choices(),
|
|
|
|
}
|
|
|
|
template = 'admin/orchestra/select_plugin.html'
|
|
|
|
return render(request, template, context)
|
|
|
|
|
|
|
|
def add_view(self, request, form_url='', extra_context=None):
|
|
|
|
""" Redirects to select account view if required """
|
|
|
|
if request.user.is_superuser:
|
|
|
|
plugin_value = request.GET.get(self.plugin_field)
|
|
|
|
if plugin_value or self.plugin.get_plugins() == 1:
|
|
|
|
self.plugin_value = plugin_value
|
|
|
|
if not plugin_value:
|
|
|
|
self.plugin_value = self.plugin.get_plugins()[0]
|
2014-09-28 12:28:57 +00:00
|
|
|
context = {
|
|
|
|
'title': _("Add new %s") % camel_case_to_spaces(self.plugin_value),
|
|
|
|
}
|
|
|
|
context.update(extra_context or {})
|
|
|
|
return super(SelectPluginAdminMixin, self).add_view(request, form_url=form_url,
|
|
|
|
extra_context=context)
|
2014-09-26 19:21:09 +00:00
|
|
|
return redirect('./select-plugin/?%s' % request.META['QUERY_STRING'])
|
|
|
|
|
2014-09-28 12:28:57 +00:00
|
|
|
def change_view(self, request, object_id, form_url='', extra_context=None):
|
|
|
|
obj = self.get_object(request, unquote(object_id))
|
|
|
|
plugin_value = getattr(obj, self.plugin_field)
|
|
|
|
context = {
|
|
|
|
'title': _("Change %s") % camel_case_to_spaces(plugin_value),
|
|
|
|
}
|
|
|
|
context.update(extra_context or {})
|
|
|
|
return super(SelectPluginAdminMixin, self).change_view(request, object_id,
|
|
|
|
form_url=form_url, extra_context=context)
|
|
|
|
|
2014-09-26 19:21:09 +00:00
|
|
|
def save_model(self, request, obj, form, change):
|
|
|
|
if not change:
|
|
|
|
setattr(obj, self.plugin_field, self.plugin_value)
|
|
|
|
obj.save()
|
|
|
|
|