django-fluent / django-fluent-contents

A widget engine to display various content on Django pages
http://django-fluent.org/
Apache License 2.0
149 stars 39 forks source link

mptt tree support for content items #45

Open Kurdakov opened 9 years ago

Kurdakov commented 9 years ago

The task I'm working on naturally leads me to desire to have nested content items.

It is not difficult to change base class for class ContentItemMetaClass(PolymorphicMPTTModelBase) and class ContentItem(with_metaclass(ContentItemMetaClass, CachedModelMixin, PolymorphicMPTTModel))

but then there is a problem to set relationship between page's contentitems in admin

also, MPTTModel adds it's own 'parent' field so there is either need to completely replace ContentItem placeholder parent field or to combine this field with mpttmodel parent field so that mptt parent field is used to track tree relations of ContentItems for output for real world page and placeholder parent field is used to keep admin page presentation of ContentItem blocks )

after combining placeholder field mptt parent field also appears in ContentItemForm in admin page, but apparently without additional efforts is non-funtional such that mptt works as usual linear container for ContainerItems

And I have a question to the author, if he considers viable addition of tree relationships to ContentItems and how he would approach setting root node for the page and setting specific relations between ContenItems via setting parents for ContenItems using 'mptt parent' drop down which appears in admin blocks ( maybe providing queryset to dropdown which consists of all objects in given placeholder )

As a first attempt I tried to add children to 'root' tree content Items via form ModelMultipleChoiceField by adding to derived Form from ContentItemForm with lines like localchildren = forms.ModelMultipleChoiceField(widget=FilteredSelectMultiple("Children", is_stacked=False),queryset= ...)

but failed to find a way to pass to Form required queryset which could consist of ContentItems in current placeholder and which could allow to build trees manually from selected data

(edit: one afterthought here is that the solution would be easier if there was way to connect model and form directly in content plugin code )

But still seems setting mptt parent to ContentItem via autogenerated ContentItemForm field might provide a relatively easy way to build a tree of ContentItems -

the question is - how better to approach this task.

mrmachine commented 9 years ago

Can you explain a bit more about the types of content items and how they would be nested? I was also looking for a way to add pages which have their own tree of sub-content nodes, but not necessarily content items.

The sub-content nodes are more likely to be sub-pages, but I don't want to manage all the sub-pages from the main page tree change list along with all other pages. I want to work with just the tree of sub-pages for a given page.

I know that django-fluent-pages already provides a separate page tree for each Site object, so I was wondering if it would be possible to create a regular change list for a particular page type, without showing a page tree. Any page that is created from there would be created as a root node in the page tree. Then from the page edit form, I would like to display the sub-page tree in a sidebar.

I assume it might be possible to implement this via filtering on the parent field in a similar way that django-fluent-pages filters on Site?

Kurdakov commented 9 years ago

"Can you explain a bit more about the types of content items and how they would be nested?"

I think of famo.us pages - there are transform ( modifier ) nodes which can contain surface subnodes ( and again transform/modifier subnodes ). Transform modifiers in famo.us can move html subnodes, rotate them etc. so transform is just a 'pivot' placement point - and following nodes can be positioned relative to higher transform

so I plan to have 'transform node' ContentItem and various specialised famo.us surfaces wrapped as ContentItems ( in famo.us surfaces are in fact plain divs which can be filled with any valid html, but which can be freely placed/moved in any position on the page - that is where power of assembling trees can be very useful).

to output those ContentItems to pages would be relatively easy - there will be just call to famo.us add ( in plain famo.us ) in placeholder ( just almost the same way items are iterated for output in placeholder ) or call to output open 'braket' then output html for inner ContentItems, then call stack with closing brackets backward providing closing brackets to html output.

edit June 5,2015: one approach might be to have two/multiple admin views for page(s) - one which is like current, the other view is tailored to bringing sub blocks into tree. That might be not only for famo.us surfaces, but for relative positioning of divs/html elements as well

vdboor commented 9 years ago

Hi! sorry for not getting into this discussion before! This seems like a good thing to add, through I'm not sure about the details:

But please, go ahead on this idea!

Note, making backward incompatible changes would validate a 2.0 release with many other changes. Some of my idea's include: convert all bundled plugins to separate packages, have frontend editing support (via a different package!), and optionally let the backend look more like a preview, where you can select the item to change.


FYI, workarounds and design patterns that I typically use are:

class Slideshow(BaseSlideshowModel):
    STYLE_CHOICES = (
        # Commonly usable everywhere:
        ('default', pgettext_lazy('admin-title', u"Default")),
        ('default-no-bullets', pgettext_lazy('admin-title', u"Default - no bullets")),
        ('compact', pgettext_lazy('admin-title', u"Compact - no margin")),
    )

    style = models.CharField(_("Style"), max_length=50, choices=STYLE_CHOICES)

@plugin_pool.register
class SlideshowPlugin(ContentPlugin):
    model = SlideshowItem
    category = _("Media")
    render_template = "includes/slideshow/{style}.html"
    cache_output_per_language = True

    def get_render_template(self, request, instance, **kwargs):
        return [
            self.render_template.format(style=instance.slideshow.style),
            self.render_template.format(style='default'),
        ]

Note how this allows users to select the "theme" or "style" of an item, while the designer still has full control over the layout.

Kurdakov commented 9 years ago

Thanks for reply, I will try to get deeper into provided information later

Kurdakov commented 9 years ago

also - to share thoughts: to ease heavy admin page I thought of using
multiple views for page admins using proxy models like mentioned here http://stackoverflow.com/questions/2223375/multiple-modeladmins-views-for-same-model-in-django-admin

maybe this approach might be used in django-fluent besides tree of page elements

another way to ease admin page is to have a checkbox to 'collapse' all items on the page ( so all plugin objects look like entries on the bottom of the page ( like 'publication settings').

Having this feature, the user can concentrate his attention on editing just one item object

vdboor commented 8 years ago

FYI, I'll be working on this feature in the coming weeks - as modern web design requires it!

(first work is now in feature/container-items (https://github.com/edoburu/django-fluent-contents/tree/feature/container-items) @ abfa2bbc4dc44b3936d305ffba675a73558312ca)

Kurdakov commented 8 years ago

Great to hear, one of my idea (which I did not implement so far ) was to use https://github.com/mbraak/django-mptt-admin but use not just tree but your polymorphic tree so that links lead to polymorphic admin pages

rather currently I use polymorphic inlines to build top level nodes ( say rows ) then those rows have polymorphic links to sub nodes , which in turn could have polymorphic inlines with subnodes. database heavy approach though

vdboor commented 8 years ago

@Kurdakov: having a global "structure" view would be nice to have, though it's not my first focus.

The backend support seams rather complete, but I'm still struggling with time to improve the admin-javascript interface. If you could pick some parts of this up, I'd be delighted!

Kurdakov commented 8 years ago

@vdboor good news. as for help have some crunch-time here and seems it's for long. don't know when I have spare time any time soon. sorry

Kurdakov commented 8 years ago

@vdboor still I'm open to help, just - can we speak in skype or google hangouts? there are a lot of details which we might resolve and then I could help?

vdboor commented 7 years ago

@Kurdakov I completely missed this mention. If you're still interested, please send me your email address and I'll invite you to the slack channel (https://django-fluent.slack.com/signup)