- Author:
- pawnhearts
- Posted:
- February 25, 2010
- Language:
- Python
- Version:
- 1.1
- Score:
- 0 (after 0 ratings)
to get code with all media files and setup.py: hg clone http://code.tabed.org/mptt_admin/ screenshot
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | `# coding: utf-8
# vim: ai ts=4 sts=4 et sw=4
#from django.utils.translation import ugettext_lazy as _
from django.contrib import admin
from django.conf.urls.defaults import *
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404
from django.conf import settings
from django.utils.encoding import force_unicode
from django.utils import simplejson
from django import template
from copy import deepcopy
class MpttAdmin(admin.ModelAdmin):
""" Base class for mptt model admins, usage:
class ExampleAdmin(MpttAdmin):
tree_title_field = 'name'
tree_display = ('name','slug','created|date') # you can use filters here
prepopulated_fields = {"slug": ("name",)}
class Meta:
model = Example
"""
def __init__(self,*args,**kargs):
super(MpttAdmin,self).__init__(*args,**kargs)
if not hasattr(self,'tree_display'):
self.tree_display = ()
if self.tree_display and not hasattr(self,'tree_title_field'):
self.tree_title_field = self.tree_display[0]
if not hasattr(self,'tree_title_field'):
title_field = ''#self.tree_display[0]
else:
title_field = '.'+self.tree_title_field
extra_fields = ' '.join('<span title="%s">{{ node.%s }}</span>' % (field,field) for field in self.tree_display if not hasattr(self,'tree_title_field') or field!=self.tree_title_field)
model = '%s.%s' % (self.Meta.model._meta.app_label, self.Meta.model._meta.object_name)
self._tree_tpl = template.Template("""{% load mptt_tags %}{% full_tree_for_model """+model+""" as nodes %}{% for node,structure in nodes|tree_info %}{% if structure.new_level %}{% if node.is_child_node %}<ul>{% endif %}<li id="n{{node.pk}}">{% else %}</li><li id="n{{node.pk}}">{% endif %}<ins> </ins><a href="{{node.pk}}/">{{ node"""+title_field+""" }}</a>"""+extra_fields+"""{% for level in structure.closed_levels %}</li>{% if node.is_child_node %}</ul>{% endif %}{% endfor %}{% endfor %}""")
self._changelist_tpl = template.Template("""{% extends "admin/change_list.html" %}
{% load mptt_tags %}
{% block extrahead %}
<script>var permissions={{permissions|safe}};</script>
<script src="{{ MEDIA_URL }}js/jstree_admin.js"></script>
{% endblock %}
{% block search %}{% endblock %}{% block date_hierarchy %}{% endblock %}
{% block result_list %}{% endblock %}{% block pagination %}{% endblock %}
{% block filters %}<div id="tree"><ul>{{tree}}</ul></div>{% endblock %}""")
#self.move_node = permission_required('%s.change_%s' % (self.model._meta.app_label,self.model._meta.object_name))(self.move_node)
#self.rename = permission_required('%s.change_%s' % (self.model._meta.app_label,self.model._meta.object_name))(self.rename)
#self.remove = permission_required('%s.delete_%s' % (self.model._meta.app_label,self.model._meta.object_name))(self.remove)
def changelist_view(self, request, extra_context=None):
model = '%s.%s' % (self.Meta.model._meta.app_label, self.Meta.model._meta.object_name)
opts = self.model._meta
app_label = opts.app_label
media = deepcopy(self.media)
media.add_js(['js/lib/jquery-1.3.2.min.js',
'js/lib/jquery.tree.min.js',
'js/lib/plugins/jquery.tree.contextmenu.js'])
module_name = force_unicode(opts.verbose_name_plural)
permissions = simplejson.dumps({
'renameable' : self.has_change_permission(request, None) and hasattr(self,'tree_title_field'),
'deletable' : self.has_delete_permission(request, None),
'creatable' : self.has_add_permission(request),
'draggable' : self.has_change_permission(request, None),
})
context = {
'module_name': module_name,
'title': module_name,
'is_popup': False,
'cl': {'opts':{'verbose_name_plural': module_name}},
'media': media,
'has_add_permission': self.has_add_permission(request),
'root_path': self.admin_site.root_path,
'app_label': app_label,
'tree':self._tree_tpl.render(template.Context()),
'permissions': permissions,
'MEDIA_URL': settings.MEDIA_URL,
}
context.update(extra_context or {})
context_instance = template.RequestContext(request, current_app=self.admin_site.name)
context_instance.update(context)
return HttpResponse(self._changelist_tpl.render(context_instance))
def get_urls(self):
urls = super(MpttAdmin, self).get_urls()
my_urls = patterns('',
(r'^tree/$', self.get_tree),
(r'^move_node/$', self.move_node),
(r'^rename/$', self.rename),
(r'^remove/$', self.remove),
)
return my_urls + urls
def get_tree(self,request):
return HttpResponse(self._tree_tpl.render(template.Context()))
def move_node(self,request):
if not self.has_change_permission(request, None):
raise PermissionDenied
node = get_object_or_404(self.Meta.model,pk=request.POST.get('node'))
target = get_object_or_404(self.Meta.model,pk=request.POST.get('target'))
position = request.POST.get('position')
if position not in ('left','right','last-child','first-child'):
return HttpResponseBadRequest('bad position')
self.Meta.model.tree.move_node(node,target,position)
return self.get_tree(request)
def rename(self,request):
if not self.has_change_permission(request, None):
raise PermissionDenied
node = get_object_or_404(self.Meta.model,pk=request.POST.get('node'))
setattr(node,self.tree_title_field, request.POST.get('name'))
print self.tree_title_field, request.POST.get('name')
node.save()
return self.get_tree(request)
def remove(self,request):
if not self.has_delete_permission(request, None):
raise PermissionDenied
node = get_object_or_404(self.Meta.model,pk=request.POST.get('node'))
node.delete()
return self.get_tree(request)`
jstree_admin.js:
`$(document).ready(function() {
if (!$('#tree').length)
return false;
$(function() {
window.jtree = $("#tree").tree({
plugins: {
contextmenu: {
items: {
remove: true,
create: {
label: "Create",
icon: "create",
visible: function(node, treeobj) {
if (node.length != 1)
return 0;
return treeobj.check("creatable", node);
},
action: function(node, treeobj) {
location.href = 'add/?parent=' + node.attr('id').replace('n','');
},
separator_after: true
},
rename: {
label: "Rename",
icon: "rename",
visible: function(node, treeobj) {
if (node.length != 1)
return false;
return treeobj.check("renameable", node);
},
action: function(node, treeobj) {
treeobj.rename(node);
}
},
edit: {
label: "Change",
icon: "rename",
visible: function(node, treeobj) {
if (node.length != 1)
return false;
return true;
},
action: function(node, treeobj) {
location.href = $(node).attr('id').replace('n','') + '/';
}
},
remove: {
label: "Remove",
icon: "remove",
visible: function(node, treeobj) {
if (node.length != 1)
return false;
return treeobj.check("deletable", node);
},
action: function(node, treeobj) {
treeobj.remove(node);
}
}
}
}
},
callback: {
beforemove: function(node, ref_node, TYPE, treeobj) {
if(treeobj._moving){
treeobj._moving=false;
return true;
}else treeobj._moving=true;
var position={'inside':'last-child','before':'left','after':'right'}[TYPE];
treeobj.settings.data.opts.url = 'move_node/';
treeobj.settings.data.opts.method='POST';
treeobj._params={node:node.id.replace('n',''),target:ref_node.id.replace('n',''),position:position};
treeobj.refresh();
return false;
},
ondblclk: function(node, treeobj) {
location.href = $(node).attr('id').replace('n','');
},
onload: function(treeobj) {
treeobj.open_all();
},
onrename: function(node, treeobj, RB) {
//treeobj.settings.data._node=node;
var new_name=$(node).children('a:first').text();//.replace(/^\s\s*/, '');
treeobj._params={node:node.id.replace('n',''),name:new_name};
treeobj.settings.data.opts.url = 'rename/';
treeobj.settings.data.opts.method = 'POST';
treeobj.refresh();
return false;
},
beforedelete: function(node, treeobj) {
treeobj._params={node:node.id.replace('n','')};
treeobj.settings.data.opts.url = 'remove/';
treeobj.settings.data.opts.method = 'POST';
treeobj.refresh();
return false;
},
onsearch : function (n,t) {
t.container.find('.search').removeClass('search');
n.addClass('search');
},
ondata: function(data, treeobj) {
if(typeof(treeobj._params)!='undefined'){
treeobj._params={};
treeobj.settings.data.opts.url='tree/';
treeobj.settings.data.opts.method='POST';}
return data;
},
beforedata: function(node, treeobj) {
return typeof(treeobj._params)!='undefined' && treeobj._params || {};
},
onchange : function (node) {
document.location.href = $(node).children("a:eq(0)").attr("href");
}
},
data: {
type: "html",async: false
},
"types": {
"default": permissions
}
});
});
$('#changelist').removeClass('module');
});`
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Seems not fully working anymore, or may some files are not right. Would be great to have more details about the required files etc.
#
Thx for good snippet!
In django-mptt 0.5.x you need to replace lines:
with:
#
Please login first before commenting.