Contents and Regions

Regions

The included Contents class and its helpers (contents_*) and the ContentEditor admin class expect a regions attribute or property (not a method) on their model which returns a list of Region instances.

Regions have the following attributes:

  • title: Something nice, will be visible in the content editor.

  • key: The region key, used in the content proxy as attribute name for the list of plugins. Must contain a valid Python identifier. "regions" and names starting with an underscore cannot be used. The recommendation is to use "main" when you only have a single region and no better idea.

  • inherited: Only has an effect if you are using the inherit_from argument to contents_for_item: Model instances inherit content from their other instances if a region with inherited = True is empty.

You are free to define additional attributes – simply pass them when instantiating a new region.

Example:

from content_editor.models import Region

class Article(models.Model):
    title = models.CharField(max_length=200)

    regions = [
        Region(key="main", title="Main content"),
        Region(key="sidebar", title="Sidebar", inherited=True),
    ]

Contents class and helpers

The content_editor.contents module offers a few helpers for fetching content blocks from the database. The Contents class knows how to group content blocks by region and how to merge contents from several main models. This is especially useful in inheritance scenarios, for example when a page in a hierarchical page tree inherits some aside-content from its ancestors.

Note

Historical note

The Contents class and the helpers replace the monolithic ContentProxy concept in FeinCMS.

Contents class

Simple usage is as follows:

from content_editor.contents import Contents

article = Article.objects.get(...)
c = Contents(article.regions)
for item in article.app_richtext_set.all():
    c.add(item)
for item in article.app_download_set.all():
    c.add(item)

# Returns a list of all items, sorted by the definition
# order of article.regions and by item ordering
list(c)

# Returns a list of all items from the given region
c["main"]
# or
c.main

# How many items do I have?
len(c)

# Inherit content from the given contents instance if one of my
# own regions is empty and has its "inherited" flag set.
c.inherit_regions(some_other_contents_instance)

# Plugins from unknown regions end up in _unknown_region_contents:
c._unknown_region_contents

For most use cases you’ll probably want to take a closer look at the following helper methods instead of instantiating a Contents class directly:

contents_for_items

Returns a contents instance for a list of main models:

articles = Article.objects.all()[:10]
contents = contents_for_items(
    articles,
    plugins=[RichText, Download],
)

something = [
    (article, contents[article])
    for article in articles
]

contents_for_item

Returns the contents instance for a given main model (note that this helper calls contents_for_items to do the real work):

# ...
contents = contents_for_item(
    article,
    plugins=[RichText, Download],
)

It is also possible to add additional items for inheriting regions. This is most useful with a page tree where i.e. sidebar contents are inherited from ancestors (this example uses methods added by django-tree-queries as used in feincms3):

page = ...
contents = contents_for_item(
    page,
    plugins=[RichText, Download],
    page.ancestors().reverse(),  # Prefer content closer to the
                                 # current page
)