Using MPTTModelAdmin as an inline?

1,021 views
Skip to first unread message

Ben Spatafora

unread,
Aug 7, 2013, 7:41:22 PM8/7/13
to django-...@googlegroups.com
Right now my admin setup looks something like this:

class CommentInline(admin.TabularInline):

    model = Comment

    form = CommentForm


class PostingAdmin(admin.ModelAdmin):

    inlines = [CommentInline]

    form = PostingForm


Is there any way to have CommentInline use MPTTModelAdmin?


(Also, 0.6 is out! Woo!)

Jan Schrewe

unread,
Aug 7, 2013, 8:53:33 PM8/7/13
to django-...@googlegroups.com
First, it's been a very long while since I've last used MPTT. 

That said if you look at https://github.com/django-mptt/django-mptt/blob/master/mptt/admin.py#L25-L49 the MPTTModelAdmin really only overrides the function formfield_for_foreignkey (changelists aren't all that relevant for inline formsets). It should actually be pretty easy to provide a MixIn that works with inlines and standard admins. Either in your own project or as a patch to MPTT.

If you have a lot of comments in your inline you might get unhappy though. Every __init__() of the MPTTAdminForm (from which your form probably needs to inherit) does change the queryset for the parent field if the instance attribute is set. Which involves running at least one query for every form in the formset. So if you have a lot of forms you might have to come up with something smarter.


--
You received this message because you are subscribed to the Google Groups "django-mptt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-mptt-d...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ben Spatafora

unread,
Aug 9, 2013, 10:10:40 AM8/9/13
to django-...@googlegroups.com
I don't have enough experience to know how to do that, but thank you for the response!

Jan Schrewe

unread,
Aug 9, 2013, 10:40:08 AM8/9/13
to django-...@googlegroups.com
I don't really have enough time to actually test this, so not exactly sure if it's gonna work. Basically what you want is a class that only does one small thing (that's what gets a called a mixin later) and then let the class that does what you actually want by inheriting from either several mixins or from a complex base class and your mixin.

So here you'd have the following mixin:

class MPTTModelMixin(object):
    form = MPTTAdminForm

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        from mptt.models import MPTTModel, TreeForeignKey
        if issubclass(db_field.rel.to, MPTTModel) \
                and not isinstance(db_field, TreeForeignKey) \
                and not db_field.name in self.raw_id_fields:
            defaults = dict(form_class=TreeNodeChoiceField, queryset=db_field.rel.to.objects.all(), required=False)
            defaults.update(kwargs)
            kwargs = defaults
        return super(MPTTModelAdmin, self).formfield_for_foreignkey(db_field,
                                                                    request,
                                                                    **kwargs)

So there's your mixin. Now for the admin classes:

class MPTTModelAdmin(MPTTModelMixin, ModelAdmin): # I think this is the right order, but maybe you need to swap them
    """
A basic admin class that displays tree items according to their position in the tree.
No extra editing functionality beyond what Django admin normally offers.
"""

    if IS_GRAPPELLI_INSTALLED:
        change_list_template = 'admin/grappelli_mptt_change_list.html'
    else:
        change_list_template = 'admin/mptt_change_list.html'

def get_changelist(self, request, **kwargs):
        """
Returns the ChangeList class for use on the changelist page.
"""
        return MPTTChangeList

class MPTTInlineModelAdmin(MPTTModelMixin, admin.TabularInline):
pass

And that should be all there is to it. Now you can use MPTTInlineModelAdmin instead of the normal MPTTModelAdmin for your inline case. Your comment form should be based on MPTTAdminForm but it should be in any case.

Hope this helps.

Jan Schrewe

unread,
Aug 9, 2013, 10:44:42 AM8/9/13
to django-...@googlegroups.com
Oh. My personal joy the super call is wrong up there:

return super(MPTTModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

must be

return super(MPTTModelMixin, self).formfield_for_foreignkey(db_field, request, **kwargs)

Ben Spatafora

unread,
Aug 9, 2013, 5:47:38 PM8/9/13
to django-...@googlegroups.com
Wow, thanks so much for taking the time to put that together. I gave it a try, but unfortunately I wasn't able to get it to work. (This very well may be due to my not really knowing what I'm doing.)

Having the comments appear under their parents in the admin would be nice, but is not essential, so I'm going to focus on getting everything working on the user-facing side. Again, though, thank you for the help!

Jan Schrewe

unread,
Aug 9, 2013, 6:44:32 PM8/9/13
to django-...@googlegroups.com
Okay, so after my curiosity got the better of me I tried it out. And while I have no idea how it is supposed to look rendered or what the points field does, I do have a working inline admin using your (slightly adapted) models from your other posts.


And I did fork MPTT to try it out. I am a bit hesitant to make a pull request just now, because I can't really say if it does what it's supposed to do or if some functionality is missing. (I can add and edit comments. Deleting seems to be more problematic.)  You can find my repo here: https://github.com/jschrewe/django-mptt and if that works for you I'd make a pull request for Craig.

HTH

Jan

Ben Spatafora

unread,
Aug 13, 2013, 11:09:03 AM8/13/13
to django-...@googlegroups.com
I tried to emulate what you did using my basic models, your admin file, and your branch of mptt, but unfortunately I'm getting the same result. I should have specified last time that my issue wasn't that the admin functionality broke using your code, but that it didn't seem to implement the part of the mptt admin functionality I'm looking for; namely, indenting comments to clarify their relationships and position in the tree (I realize now that I didn't indicate that this is what I was hoping to achieve; sorry about that).

I've attached an image of what the admin page for a posting looks like for me, with comments displayed linearly despite having a parent-child relationship. Please let me know if things displayed differently (i.e., with levels indicated by indent) for you.

One possibility is that I'm misunderstanding the documentation for mptt's admin functionality—I'd assumed what I'm talking about is what is meant by "All it does is...indent the nodes in the tree to make a pretty tree list view", under MPTTModelAdmin, but perhaps that refers only to the representation of the tree in the Parent field dropdown.

Anyway, I appreciate your having looked into this.

Jan Schrewe

unread,
Aug 13, 2013, 12:15:01 PM8/13/13
to django-...@googlegroups.com
Nope, indentation isn't there. And while I think that could be implemented, doing so would be a PITA. I think MPTT uses the changelist to display anything in tree form. Trouble is that an inline admin uses standard formsets to display and edit the inline elements together with some pretty complex templates.

If you want to give it a shot, I would suggest you start with building a formset that uses MPTTs already available methods to iterate over the tree and adds some sort of attribute on the generated form. Then hack the admin template to use the newly added attribute on the form to add a css class that holds level information (and add a new css file, to get some visual effect). Methods to look at are _construct_form, get_queryset and ordered_forms (though I'm not sure if the admin actually uses that).

In general I think this is one of those looks easy on paper things, that really suck to actually write. Sorry.

Craig de Stigter

unread,
Aug 13, 2013, 7:07:52 PM8/13/13
to django-...@googlegroups.com
I've been following this but haven't had a lot of time to reply.

Yeah, that would be a useful feature. Unfortunately hacking the django admin to do this kind of thing is a bit of a nightmare. The admin site has never been very modular or extendable.

It could be done but like Jan I'm guessing it'd require quite a bit of hackery to get it to work. From past experience I'd assume multiple templates and even templatetags would need overriding, and need to be kept up to date with upstream Django as it evolves.

To look at tackling this, I'd like to know a bit more about where Django's admin is heading. There have been lots of talk of making it better, but I don't know how far along the various proposals are. Perhaps someone reading this knows more?

Cheers
Craig
Reply all
Reply to author
Forward
0 new messages