Django admin and MPTT #2

This is a follow up to the previous post on managing and visualizing trees using django. I’ve been using MPTT quite a bit now and it’s great – also, I looked deeper into the admin integration (basically, the issue of being able of manage trees from within the admin).

The major issue I had with the patch discussed in my previous post was the fact that it is mainly a javascript hack – everything is done in the browser – i.e. it looked wonderful but it didn’t really scale up. So if you had a lot of items in your tree (say thousands) the js-driven pagination (basically, hiding and showing things on demand) would crash – at least, it did that to me all the time!

The solution has been to reuse the admin management section from the FeinCMS project – this is a great CMS created by a bunch of django-ers in Switzerland – it relies heavvily on django’s admin so they had the same problem when having to provide a way for users to add structure to the pages in a website. With some help from google and Matthias (tx! he’s one of the guys behind FeinCMS) I got it all working.. here’s the main steps:

1. upgrade to django 1.1
This might not be necessary, cause everything is supposed to work also with the previous release – I tried it with django 1.0 too but I had to fix a couple of urls to make it work (Basically media files which were not loaded properly). So, if you want a hassle-free installation just upgrade to django 1.1 ! (which is great btw)

2. download and add feincms, mptt to you installed apps in settings.py
As simple as that.

INSTALLED_APPS = (
    ....
    'mptt',
    'feincms',
)

3. specify a url-path for feincms media in settings.py, and also a location (this may vary in your live server, if you want apache to serve these files directly).

FEINCMS_ADMIN_MEDIA = '/feincms_media/'
FEINCMS_ADMIN_MEDIA_LOCATION = '/My/local/path/to/feincms/media/'

4. add a url handler for feincms media files in urls.py. Again, these settings are ok on a development server, on production phase you might wanna do things differently :-)

from django.conf import settings
    urlpatterns = patterns('',
    .....
    (r'^feincms_media/(?P<path>.*)$', 'django.views.static.serve',
         {'document_root': settings.FEINCMS_ADMIN_MEDIA_LOCATION, 'show_indexes': True}),
)

5. register your hierarchical model with mptt, then remember to set the Meta option correctly.. this is needed for a correct display of the tree in the admin (obviously you need to run syncdb to create the table in the db!):

from django.db import models
import mptt

class TreeNode(models.Model):
   name = models.CharField(max_length=50, unique=True)
   parent = models.ForeignKey('self', null=True, blank=True, related_name='children')

   def __unicode__(self):
                return self.name

   class Meta:
          ordering = ['tree_id', 'lft']


mptt.register(TreeNode,)

6. create a model admin that inherits from feincms TreeEditor class:

from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django.conf import settings as django_settings
from feincms.admin import editor
from myproject.myapp.models import *

class TreeNodeAdmin(editor.TreeEditor):
    pass

admin.site.register(TreeNode, TreeNodeAdmin)

End! That should be it! Let me know if I forgot something..
Here’s a screenshot of the new tree-management admin page we created:

Picture 1

UPDATE 09/2009: how to add more actions to the tree bar.
Just override the _actions_column method on the TreeNodeAdmin class, as follows::

class TreeNodeAdmin(editor.TreeEditor):
        def _actions_column(self, page):
                actions = super(TreeNodeAdmin, self)._actions_column(page)
                actions.insert(0, u'<a href="add/?parent=%s" title="%s"><img
                       src="%simg/admin/icon_addlink.gif" alt="%s"></a>' %
                       (page.pk, _('Add child page'),
                       settings.ADMIN_MEDIA_PREFIX , _('Add child page')))
               actions.insert(0, u'<a href="%s" title="%s"><img
                       src="%simg/admin/selector-search.gif" alt="%s" /></a>' %
                       (page.get_absolute_url(), _('View on site'),
                       django_settings.ADMIN_MEDIA_PREFIX, _('View on site')))
                return actions

admin.site.register(TreeNode, TreeNodeAdmin

 

Share/Bookmark






31 Responses to “Django admin and MPTT #2”

Wow, great writeup! The fourth step should be done differently though — it is not recommended to use django.views.static.serve for production[1]. You should copy the FeinCMS media files somewhere inside your MEDIA_ROOT resp. MEDIA_URL and set FEINCMS_ADMIN_MEDIA accordingly.

[1]: http://docs.djangoproject.com/en/dev/howto/static-files/#the-big-fat-disclaimer

Matthias Kestenholz added these pithy words on Aug 18 09 at 10:58 am

yes that’s right!!! …I had the development server in mind :-)

magicrebirth added these pithy words on Aug 18 09 at 11:42 am

Thank you.
Very useful

laurent added these pithy words on Aug 25 09 at 7:52 am

The latest version of feincms will automatically set up ordering in the admin, so step 5 (setting Meta options) should also not be necessary. Also, the latest version makes it very easy to rip out the tree editor if that is the only component you are interested in.

Chris Mutel added these pithy words on Sep 03 09 at 8:00 pm

I have followed your instructions.
Everything works fine, except one thing: I have no plus symbol in the Actions column (which adds a new item as a child).

Can you help me with this?

Uszy Wieloryba added these pithy words on Sep 14 09 at 4:29 pm

I solved the problem by editing method _actions_column(self, page) from class TreeEditor in feincmsadmintree_editor.py which is responsible for generating the actions row for every node. Now I have the plus symbol there.

But I still do not know, why did I have to do it. By the way, I have also noticed, that the scissors icon looks a little bit different on you screenshot.

Uszy Wieloryba added these pithy words on Sep 15 09 at 12:44 am

What did you do exactly? I’m trying to figure out how to do this, but I need more clues. How to modify that function? Is there built in action handling adding new node as a child?

Jaro added these pithy words on Sep 23 09 at 2:57 pm

thanks for pointing this out! I forgot to mention that.. you can do it as you say, although a better solution is not to modify the feincms package source, but just to override the _actions_column method in your admin class. I updated the post with an example of this…

magicrebirth added these pithy words on Sep 28 09 at 12:22 pm

[…] in programming by magicrebirth on September 15, 2009 Here we are again with django and MPTT (already have other posts about it). After working with this for a bit I realized that things were breaking mysteriously, and only […]

Using Django-MPTT: lessons learned… « Parerga und Paralipomena added these pithy words on Sep 15 09 at 4:36 pm

Is it necessary to install feincms in INSTALLED_APPS? Is there a reason this wouldn’t work without it installed?

saturdayplace added these pithy words on Oct 08 09 at 6:48 pm

I guess not!
But the admin class [editor.TreeEditor] used to render the tree comes from FeinCMS so somehow you’ve got to import that. Actually it’d be nice to have that inside the MPTT app …

magicrebirth added these pithy words on Oct 12 09 at 4:26 pm

Just a little tweak to the ‘add child’ action to make it more generic (the parent field may not be called ‘parent’)

u’‘ % (getattr(self.model._meta,’parent_attr’,’parent’), cat.pk, ‘Add child category’, settings.ADMIN_MEDIA_PREFIX, ‘Add child category’)

Paul added these pithy words on Oct 20 09 at 11:49 am

Has anyone else found that the left/right values are not updated when you delete an item via the ‘delete selected’ action?

If you go into the item edit screen and click the delete link then the values are updated correctly…

Paul added these pithy words on Oct 20 09 at 11:55 am

[…] the instructions here, we borrow some code from the FeinCMS app to add tree control to the […]

Making admin bulk delete action work with django-mptt « Anentropic Blog added these pithy words on Oct 26 09 at 5:55 pm

If you don’t use the default ‘parent’ attribute name in your mptt model you need to do a small hack to Fein CMS:
http://anentropic.wordpress.com/2009/10/26/making-admin-bulk-delete-action-work-with-django-mptt/

anentropic added these pithy words on Oct 30 09 at 4:20 pm

the mptt.register in the models.py gives me a:

Exception Type: TemplateSyntaxError
Exception Value: Caught an exception while rendering: The model Element has already been registered.

im using django 1.1.1 and i copy/pasted the code here…
any suggestions?

andreas added these pithy words on Jan 26 10 at 3:37 pm

hi, hard to tell but I think you should check your code in admin.py .. looks like you’re registering your models more than once. Otherwise try to identify the exact place which is causing the error… it might also be some nuisance such as a missing parenthesis or similar..

magicrebirth added these pithy words on Feb 01 10 at 9:13 am

im still stuck on this error. i really dont understand, the model is not registered twice and it really doesnt work even by copy pasting the code above.
django is 1.1.1
mptt is 0.3-pre

my traceback: http://pastebin.com/4F2sfJ2f

any help is appreciated :)

andreas added these pithy words on Mar 09 10 at 9:45 am

ok i solved using this version of django-mptt
http://github.com/bfirsh/django-mptt

the trunk on googlecode wasnt working at all for me.

andreas added these pithy words on Mar 15 10 at 2:08 pm

Hi,
What versions of django, mptt and FeinCMS are you using?

I followed your steps but for some reason it’s only partially working.
The changelist items do not show up indented at all and I’ve got (None) where the item names should appear.
The cut and “paste” actions work fine though (at the data level).

My versions are:
Django – 1.2-beta-1 – active
FeinCMS – 1.0.4 – active development
django-mptt – 0.3-pre – active development

I’ve tried downgrading django to 1.1 but the result is the same.

Any ideas as of what might be wrong?

nicoechaniz added these pithy words on Feb 15 10 at 7:02 am

django 1.1
feincms 1.0.3
mptt 0.3pre

Mmm try fiddle a bit with FeinCMS maybe.. in theory what you need are just a few modelAdmin classes from there. I had planned to get rid of FeinCMS (as I don’t use it as a CMS) but never got down to doing it..
Also: if you don’t add the following (point 5) the tree won’t show up correcty:
class Meta:
ordering = [‘tree_id’, ‘lft’]

other stuff I can’t think about right now…

magicrebirth added these pithy words on Feb 15 10 at 8:51 am

thanks – that’s pretty useful to know!

magicrebirth added these pithy words on Feb 18 10 at 6:05 am

Sadly but it looks like feincms TreeEditor doesn’t work for national locales.
At least it fails for ‘ru’ with UnicodeDecodeError

Qrilka added these pithy words on Feb 17 10 at 10:47 pm

BTW in source code with red background you have GenericPossessionsAdmin instead of TreeNodeAdmin

Qrilka added these pithy words on Feb 17 10 at 11:20 pm

@ Qrilka: thanks ;-)

magicrebirth added these pithy words on Feb 18 10 at 6:04 am

i tryed it, but wasn’t able to use it. ‘coz was having an error

unsupported operation -: ‘unicode’ and ‘unicode’

in getattr(self, self._meta.left_attr) – 1) / 2
does anyone know how to fix it?

Vovk Donets added these pithy words on Mar 12 10 at 11:12 am

[…] Угу. Буквально пять минут назад нашёл описание как выдрать из feincms интерфейс для показа mptt-дерева: http://magicrebirth.wordpress.com/2009/08/18/django-admin-and-mptt-2/ […]

Отображение древовидных данных в админке. added these pithy words on Apr 15 10 at 8:18 pm

Heya,

This was really helpful, Can confirm it worked fine with with django 1.2.1 & feincms 1.1.2, however in step 4 the pattern name is missing, presumably sanitised & removed because it looks like a html tag

ms_media/(?P here .*)$’, ‘djang

sjh added these pithy words on Jul 02 10 at 9:34 am

thanks – you’re right the pattern variable disappeared! I fixed the code above..

mike added these pithy words on Jul 02 10 at 2:50 pm

Hey, thanks for this. Just wondering if there is a way of doing this without FeinCMS three years later?
Thanks

Jonas added these pithy words on Sep 03 12 at 1:17 pm