From 2408809617db2f81d1554d9a712c2339bc63dbef Mon Sep 17 00:00:00 2001 From: Jose Soares Date: Mon, 5 Dec 2016 12:02:45 -0500 Subject: [PATCH] [-] Various updates - explicit admin urls - django 1.9 compatibility - get_formsets was removed - admin views needs extra args (args, kwargs) - more specific obj-data url --- genericadmin/admin.py | 70 ++++++++++++------- .../static/genericadmin/js/genericadmin.js | 67 +++++++++--------- 2 files changed, 79 insertions(+), 58 deletions(-) diff --git a/genericadmin/admin.py b/genericadmin/admin.py index e9f5fc4..3daf035 100644 --- a/genericadmin/admin.py +++ b/genericadmin/admin.py @@ -1,6 +1,7 @@ import json from functools import update_wrapper +from django.core.urlresolvers import reverse, NoReverseMatch from django.contrib import admin from django.conf.urls import url from django.conf import settings @@ -12,7 +13,7 @@ from django.contrib.contenttypes.models import ContentType try: - from django.utils.encoding import force_text + from django.utils.encoding import force_text except ImportError: from django.utils.encoding import force_unicode as force_text from django.utils.text import capfirst @@ -24,7 +25,7 @@ from django.contrib.admin.options import IS_POPUP_VAR from django.core.exceptions import ObjectDoesNotExist -JS_PATH = getattr(settings, 'GENERICADMIN_JS', 'genericadmin/js/') +JS_PATH = getattr(settings, 'GENERICADMIN_JS', 'genericadmin/js/') class BaseGenericModelAdmin(object): class Media: @@ -34,7 +35,7 @@ class Media: generic_fk_fields = [] content_type_blacklist = [] content_type_whitelist = [] - + def __init__(self, model, admin_site): try: media = list(self.Media.js) @@ -42,10 +43,10 @@ def __init__(self, model, admin_site): media = [] media.append(JS_PATH + 'genericadmin.js') self.Media.js = tuple(media) - + self.content_type_whitelist = [s.lower() for s in self.content_type_whitelist] - self.content_type_blacklist = [s.lower() for s in self.content_type_blacklist] - + self.content_type_blacklist = [s.lower() for s in self.content_type_blacklist] + super(BaseGenericModelAdmin, self).__init__(model, admin_site) def get_generic_field_list(self, request, prefix=''): @@ -53,7 +54,7 @@ def get_generic_field_list(self, request, prefix=''): exclude = [self.ct_field, self.ct_fk_field] else: exclude = [] - + field_list = [] if hasattr(self, 'generic_fk_fields') and self.generic_fk_fields: for fields in self.generic_fk_fields: @@ -62,19 +63,26 @@ def get_generic_field_list(self, request, prefix=''): fields['inline'] = prefix != '' fields['prefix'] = prefix field_list.append(fields) - else: + else: for field in self.model._meta.virtual_fields: if isinstance(field, GenericForeignKey) and \ field.ct_field not in exclude and field.fk_field not in exclude: field_list.append({ - 'ct_field': field.ct_field, + 'ct_field': field.ct_field, 'fk_field': field.fk_field, 'inline': prefix != '', 'prefix': prefix, }) - + if hasattr(self, 'inlines') and len(self.inlines) > 0: - for FormSet, inline in zip(self.get_formsets(request), self.get_inline_instances(request)): + try: + # Django < 1.9 + formsets = zip(self.get_formsets(request), self.get_inline_instances(request)) + except (AttributeError, ): + # Django >= 1.9 + formsets = self.get_formsets_with_inlines(request) + + for FormSet, inline in formsets: if hasattr(inline, 'get_generic_field_list'): prefix = FormSet.get_default_prefix() field_list = field_list + inline.get_generic_field_list(request, prefix) @@ -86,26 +94,36 @@ def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) return update_wrapper(wrapper, view) - + custom_urls = [ - url(r'^obj-data/$', wrap(self.generic_lookup), name='admin_genericadmin_obj_lookup'), - url(r'^genericadmin-init/$', wrap(self.genericadmin_js_init), name='admin_genericadmin_init'), + url(r'^(.*)genericadmin-obj-data/', wrap( + self.generic_lookup), name='admin_genericadmin_obj_lookup'), + url(r'^(.*)genericadmin-init/', wrap( + self.genericadmin_js_init), name='admin_genericadmin_init'), ] return custom_urls + super(BaseGenericModelAdmin, self).get_urls() - - def genericadmin_js_init(self, request): + + def genericadmin_js_init(self, request, *args, **kwargs): if request.method == 'GET': obj_dict = {} for c in ContentType.objects.all(): val = force_text('%s/%s' % (c.app_label, c.model)) params = self.content_type_lookups.get('%s.%s' % (c.app_label, c.model), {}) params = url_params_from_lookup_dict(params) + + try: + # Reverse the admin changelist url + url = reverse('admin:%s_%s_changelist' % ( + c.app_label, c.model)) + except (NoReverseMatch, ): + continue + if self.content_type_whitelist: if val in self.content_type_whitelist: - obj_dict[c.id] = (val, params) + obj_dict[c.id] = (val, url, params) elif val not in self.content_type_blacklist: - obj_dict[c.id] = (val, params) - + obj_dict[c.id] = (val, url, params) + data = { 'url_array': obj_dict, 'fields': self.get_generic_field_list(request), @@ -114,15 +132,15 @@ def genericadmin_js_init(self, request): resp = json.dumps(data, ensure_ascii=False) return HttpResponse(resp, content_type='application/json') return HttpResponseNotAllowed(['GET']) - - def generic_lookup(self, request): + + def generic_lookup(self, request, *args, **kwargs): if request.method != 'GET': return HttpResponseNotAllowed(['GET']) - + if 'content_type' in request.GET and 'object_id' in request.GET: content_type_id = request.GET['content_type'] object_id = request.GET['object_id'] - + obj_dict = { 'content_type_id': content_type_id, 'object_id': object_id, @@ -136,12 +154,12 @@ def generic_lookup(self, request): obj_dict["object_text"] = capfirst(force_text(obj)) except ObjectDoesNotExist: raise Http404 - + resp = json.dumps(obj_dict, ensure_ascii=False) else: resp = '' return HttpResponse(resp, content_type='application/json') - + class GenericAdminModelAdmin(BaseGenericModelAdmin, admin.ModelAdmin): @@ -149,7 +167,7 @@ class GenericAdminModelAdmin(BaseGenericModelAdmin, admin.ModelAdmin): class GenericTabularInline(BaseGenericModelAdmin, GenericTabularInline): - """Model admin for generic tabular inlines. """ + """Model admin for generic tabular inlines. """ class GenericStackedInline(BaseGenericModelAdmin, GenericStackedInline): diff --git a/genericadmin/static/genericadmin/js/genericadmin.js b/genericadmin/static/genericadmin/js/genericadmin.js index 529dbb9..c26744e 100755 --- a/genericadmin/static/genericadmin/js/genericadmin.js +++ b/genericadmin/static/genericadmin/js/genericadmin.js @@ -12,10 +12,10 @@ var GenericAdmin = { url_array: null, fields: null, - obj_url: "../obj-data/", + obj_url: "../genericadmin-obj-data/", admin_media_url: window.__admin_media_prefix__, popup: '_popup', - + prepareSelect: function(select) { var that = this, opt_keys = [], @@ -30,7 +30,7 @@ if (this.value) { if (that.url_array[this.value]) { key = that.url_array[this.value][0].split('/')[0]; - + opt = $(this).clone(); opt.text(that.capFirst(opt.text())); if ($.inArray(key, opt_keys) < 0) { @@ -47,7 +47,7 @@ } }); select.empty().append(no_value); - + opt_keys = opt_keys.sort(); $.each(opt_keys, function(index, key) { @@ -61,8 +61,9 @@ return select; }, + getLookupUrlParams: function(cID) { - var q = this.url_array[cID][1] || {}, + var q = this.url_array[cID][2] || {}, str = []; for(var p in q) { str.push(encodeURIComponent(p) + "=" + encodeURIComponent(q[p])); @@ -71,11 +72,13 @@ url = x ? ("?" + x) : ""; return url; }, - - getLookupUrl: function(cID) { - return '../../../' + this.url_array[cID][0] + '/' + this.getLookupUrlParams(cID); + + getLookupUrl: function(cID, with_params) { + var url = this.url_array[cID][1]; + if(with_params){url = url + this.getLookupUrlParams(cID);} + return url; }, - + getFkId: function() { if (this.fields.inline === false) { return 'id_' + this.fields.fk_field; @@ -83,7 +86,7 @@ return ['id_', this.fields.prefix, '-', this.fields.number, '-', this.fields.fk_field].join(''); } }, - + getCtId: function() { if (this.fields.inline === false) { return 'id_' + this.fields.ct_field; @@ -91,24 +94,24 @@ return ['id_', this.fields.prefix, '-', this.fields.number, '-', this.fields.ct_field].join(''); } }, - + capFirst: function(string) { return string.charAt(0).toUpperCase() + string.slice(1); }, - + hideLookupLink: function() { var this_id = this.getFkId(); $('#lookup_' + this_id).unbind().remove(); $('#lookup_text_' + this_id + ' a').remove(); $('#lookup_text_' + this_id + ' span').remove(); }, - + showLookupLink: function() { var that = this, - url = this.getLookupUrl(this.cID), + url = this.getLookupUrl(this.cID, true), id = 'lookup_' + this.getFkId(), link = ' '; - + link = link + ''; // insert link html after input element @@ -116,7 +119,7 @@ return id; }, - + pollInputChange: function(window) { var that = this, interval_id = setInterval(function() { @@ -128,11 +131,11 @@ }, 150); }, - + popRelatedObjectLookup: function(link) { var name = id_to_windowname(this.getFkId()), url_parts = [], - href, + href, win; if (link.href.search(/\?/) >= 0) { @@ -156,14 +159,14 @@ win.focus(); return false; }, - + updateObjectData: function() { var that = this; return function() { var value = that.object_input.val(); - - if (!value) { - return + + if (!value) { + return } //var this_id = that.getFkId(); $('#lookup_text_' + that.getFkId() + ' span').text('loading...'); @@ -176,7 +179,7 @@ }, success: function(item) { if (item && item.content_type_text && item.object_text) { - var url = that.getLookupUrl(that.cID); + var url = that.getLookupUrl(that.cID, false); $('#lookup_text_' + that.getFkId() + ' a') .text(item.content_type_text + ': ' + item.object_text) .attr('href', url + item.object_id); @@ -208,10 +211,10 @@ this.url_array = url_array; this.fields = fields; this.popup = popup_var || this.popup; - + // store the base element this.object_input = $("#" + this.getFkId()); - + // find the select we need to change this.object_select = this.prepareSelect($("#" + this.getCtId())); @@ -245,22 +248,22 @@ this.updateObjectData()(); } }; - + var InlineAdmin = { sub_admins: null, url_array: null, fields: null, popup: '_popup', - + install: function(fields, url_array, popup_var) { var inline_count = $('#id_' + fields.prefix + '-TOTAL_FORMS').val(), admin; - + this.url_array = url_array; this.fields = fields; this.sub_admins = []; this.popup = popup_var || this.popup; - + for (var j = 0; j < inline_count; j++) { f = $.extend({}, this.fields); f.number = j; @@ -279,7 +282,7 @@ added_fields.number = ($('#id_' + that.fields.prefix + '-TOTAL_FORMS').val() - 1); admin.install(added_fields, that.url_array, that.popup); that.sub_admins.push(admin); - + $('#' + that.fields.prefix + '-' + added_fields.number + ' .inline-deletelink').click( that.removeHandler(that) ); @@ -290,7 +293,7 @@ var parent_id, deleted_num, sub_admin; - + e.preventDefault(); parent_id = $(e.currentTarget).parents('.dynamic-' + that.fields.prefix).first().attr('id'); deleted_num = parseInt(parent_id.charAt(parent_id.length - 1), 10); @@ -315,7 +318,7 @@ ct_fields = data.fields, popup_var = data.popup_var, fields; - + for (var i = 0; i < ct_fields.length; i++) { fields = ct_fields[i]; if (fields.inline === false) {