13 Sep 2024

feedDjango community aggregator: Community blog posts

django-content-editor now supports nested sections

django-content-editor now supports nested sections

django-content-editor (and it's ancestor FeinCMS) has been the Django admin extension for editing content consisting of reusable blocks since 2009. In the last years we have more and more often started automatically grouping related items, e.g. for rendering a sequence of images as a gallery. But, sometimes it's nice to give editors more control. This has been possible by using blocks which open a subsection and blocks which close a subsection for a long time, but it hasn't been friendly to content managers, especially when using nested sections.

The content editor now has first-class support for such nested sections. Here's a screenshot showing the nesting:

django-content-editor with sections

Finally it's possible to visually group blocks into sections, collapse those sections as once and drag and drop whole sections into their place instead of having to select the involved blocks individually.

The best part about it is that the content editor still supports all Django admin widgets, as long as those widgets have support for the Django administration interface's inline form events! Moving DOM nodes around breaks attached JavaScript behaviors, but we do not actually move DOM nodes around after the initialization - instead, we use Flexbox ordering to visually reorder blocks. It's a bit more work than using a ready-made sortable plugin, but - as mentioned - the prize is that we don't break any other Django admin extensions.

Simple patterns

I previously already reacted to a blog post by Lincoln Loop here in my post My reaction to the block-driven CMS blog post.

The latest blog post, Solving the Messy Middle: a Simple Block Pattern for Wagtail CMS was interesting as well. It dives into the configuration of a Wagtail stream field which allows composing content out of reusable blocks of content (sounds familiar!). The result is saved in a JSON blob in the database with all the advantages and disadvantages that entails.

Now, django-content-editor is a worthy competitor when you do not want to add another interface to your website besides the user-facing frontend and the Django administration interface.

The example from the Lincoln Loop blog post can be replicated quite closely with django-content-editor by using sections. I'm using the django-json-schema-editor package for the section plugin since it easily allows adding more fields if some section type needs it.

Here's an example model definition:

# Models
from content_editor.models import Region, create_plugin_base
from django_json_schema_editor.plugins import JSONPluginBase
from feincms3 import plugins

class Page(models.Model):
    # You have to define regions; each region gets a tab in the admin interface
    regions = [Region(key="content", title="Content")]

    # Additional fields for the page...

PagePlugin = create_plugin_base(Page)

class RichText(plugins.richtext.RichText, PagePlugin):
    pass

class Image(plugins.image.Image, PagePlugin):
    pass

class Section(JSONPluginBase, PagePlugin):
    pass

AccordionSection = Section.proxy(
    "accordion",
    schema={"type": "object", {"properties": {"title": {"type": "string"}}}},
)
CloseSection = Section.proxy(
    "close",
    schema={"type": "object", {"properties": {}}},
)

Here's the corresponding admin definition:

# Admin
from content_editor.admin import ContentEditor
from django_json_schema_editor.plugins import JSONPluginInline
from feincms3 import plugins

@admin.register(models.Page)
class PageAdmin(ContentEditor):
    inlines = [
        plugins.richtext.RichTextInline.create(models.RichText),
        plugins.image.ImageInline.create(models.Image),
        JSONPluginInline.create(models.AccordionSection, sections=1),
        JSONPluginInline.create(models.CloseSection, sections=-1),
    ]

The somewhat cryptic sections= argument says how many levels of sections the individual blocks open or close.

To render the content including accordions I'd probably use a feincms3 renderer. At the time of writing the renderer definition for sections is a bit tricky.

from feincms3.renderer import RegionRenderer, render_in_context, template_renderer

class PageRenderer(RegionRenderer):
    def handle(self, plugins, context):
        plugins = deque(plugins)
        yield from self._handle(plugins, context)

    def _handle(self, plugins, context, *, in_section=False):
        while plugins:
            if isinstance(plugins[0], models.Section):
                section = plugins.popleft()
                if section.type == "close":
                    if in_section:
                        return
                    # Ignore close section plugins when not inside section
                    continue

                if section.type == "accordion":
                    yield render_in_context("accordion.html", {
                        "title": accordion.data["title"],
                        "content": self._handle(plugins, context, in_section=True),
                    })

            else:
                yield self.render_plugin(plugin, context)

renderer = PageRenderer()
renderer.register(models.RichText, template_renderer("plugins/richtext.html"))
renderer.register(models.Image, template_renderer("plugins/image.html"))
renderer.register(models.Section, "")

Closing thoughts

Sometimes, I think to myself, I'll "just" write a "simple" blog post. I get what I deserve when using those forbidden words. This blog post is neither short or simple. That being said, the rendering code is a bit tricky, the rest is quite straightforward. The amount of code in django-content-editor and feincms3 is reasonable as well. Even though it may look like a lot you'll still be running less code in production than when using comparable solutions built using Django.

13 Sep 2024 5:00pm GMT

Django News - Python 3.13.0RC2 - Sep 13th 2024

News

Python 3.13.0RC2 and security updates for 3.8 through 3.12

Python 3.13.0RC2 and security updates for Python 3.12.6, 3.11.10, 3.10.15, 3.9.20, and 3.8.20 are now available!

blogspot.com

DjangoCon US 2024 last call!

DjangoCon US starts September 22nd. It's the last call to buy an in-person or online ticket to attend this year!

ti.to

Python in Visual Studio Code - September 2024 Release

The Python extension now supports Django unit tests.

microsoft.com

Updates to Django

Today 'Updates to Django' is presented by Raffaella Suardini from Djangonaut Space!

Last week we had 12 pull requests merged into Django by 10 different contributors - including 4 first-time contributors! Congratulations to SirenityK, Mariatta, Wassef Ben Ahmed and github-user-en for having their first commits merged into Django - welcome on board!

Last chance to apply for Djangonaut Space ๐Ÿš€

The application will close on September 14, for more information check this article that explains the selection process. Apply here

Django Newsletter

Sponsored Link 1

HackSoft - Your Django Development Partner Beyond Code

Elevate your Django projects with HackSoft! Try our expert consulting services and kickstart your project.

hacksoft.io

Articles

Django from first principles, part 18

The final post in a series on building and refactoring a Django blog site from scratch.

mostlypython.com

Django: rotate your secret key, fast or slow

Adam Johnson covers the two main ways to rotate secret keys, including a Django 4.1 feature that allows rotating to a new key whilst accepting data signed with the old one.

adamj.eu

django-filter: filtering a foreign key model property

How to filter a foreign key model property with django-filter.

valentinog.com

Django: a pattern for settings-configured API clients

How to get around the problem that an API client is instantiated as a module-level variable based on some settings.

adamj.eu

UV with Django

Using UV to manage dependencies of your Django application.

pecar.me

Signatures are like backups ยท Alex Gaynor

"Backups don't matter, only restores matter."

alexgaynor.net

Tutorials

Django-allauth: Site Matching Query Does Not Exist

How to fix a common configuration mistake in django-allauth.

learndjango.com

Videos

Djangonaut Space Overview and Ask Me Anything (AMA)

This is an explanation of the Djangonaut Space program sessions, with a Q&A at the end. It has specific details on Session 3 of 2024, but the information is relevant for future sessions.

Session 3 applications are closed on September 14th, so apply if interested!

youtu.be

DjangoCon EU 2013 - Class-Based Views: Untangling the mess

This talk is from 2013, but it is still relevant to anyone dealing with function-based and (generic) class-based views. Russell Keith-Magee goes into the history of why GCBVs were added.

youtu.be

Sponsored Link 2

Try Scout APM for free!

Sick of performance issues? Enter Scout's APM tool for Python apps. Easily pinpoint and fix slowdowns with intelligent tracing logic. Optimize performance hassle-free, delighting your users.

ter.li

Podcasts

Django Chat #165: Fall 2024 Podcast Relaunch

This mini-episode starts off the fall season and focuses on what's new in Django, upcoming DjangoCon US talks, thoughts on the User model, Carlton's new Stack Report newsletter, mentoring mentors, and more.

djangochat.com

Django News Jobs

Back-end developers at ISM Fantasy Games ๐Ÿ†•

Python Engineer - API and SaaS Application Development at Aidentified, LLC

Software Developer at Habitat Energy

Senior Fullstack Python Engineer at Safety Cybersecurity

Django Newsletter

Projects

kennethlove/django-migrator

The Migrator project provides custom Django management commands to manage database migrations. It includes commands to revert and redo migrations for a specified app or the entire project.

github.com

carltongibson/django-unique-user-email

Enable login-by-email with the default User model for your Django project by making auth.User.email unique.

github.com


This RSS feed is published on https://django-news.com/. You can also subscribe via email.

13 Sep 2024 3:00pm GMT

Cloud Migration Beginning - Building SaaS #202

In this episode, we started down the path of migrating School Desk off of Heroku and onto Digital Ocean. Most of the effort was on tool changes and beginning to make a Dockerfile for deploying the app to the new setup.

13 Sep 2024 5:00am GMT