Skip to main content

🧱 Form sets and layouts

By default, the edit page shows the model's fields in the order they are declared. Set edit_main and edit_sidebar on the studio to choose the fields and lay them out, with the building blocks in content_studio.form.

# blog/admin.py
from content_studio import register
from content_studio.admin import ModelStudio
from content_studio.form import Field, FormSet

from .models import Article


@register(Article)
class ArticleStudio(ModelStudio):
edit_main = [
FormSet(
title="Content",
description="The article itself",
fields=[
"title",
Field("status", col_span=1),
Field("body", col_span=3),
],
),
]
edit_sidebar = ["published_at", "featured"]

Building blocks​

  • Field(name, col_span=1, label=None, readonly=False, widget=None): one model field. A string is short for Field(name).
  • FieldLayout(fields=[...], columns=1): a group of fields shown in columns columns.
  • FormSet(title, description, fields): a titled block of fields, the main way to group the edit page.
  • FormSetGroup(label, formsets=[...]): a group of form sets.

You do not have to wrap everything: a list of fields becomes a form set, and a list of form sets becomes a group.

caution

Every required model field must be in edit_main or edit_sidebar. The edit page only saves the fields it shows, so a required field that is left out, also through exclude, makes saving fail. System check content_studio.W001 reports these fields. Fields with a default, nullable or blank fields, and the fields Content Studio fills in itself (the audit stamps and the tenant), are never required.

edit_sidebar works the same way and shows its fields in the narrow column next to the main area. A field with readonly=True shows its value without an input.

To edit one field with another widget, pass the widget class: Field("body", widget=widgets.TextAreaWidget). See Widgets for the widgets you can use.

Components​

Besides fields, the edit page can show components: links, and the object's activity log.

# blog/admin.py
from content_studio import register
from content_studio.admin import ModelStudio
from content_studio.form import ActivityLog, ButtonLink

from .models import Article


class ViewOnSiteButton(ButtonLink):
label = "View on site"
icon = "ph-bold ph-arrow-square-out"

def get_url(self, obj, request):
return obj.get_absolute_url()


@register(Article)
class ArticleStudio(ModelStudio):
edit_sidebar = ["published_at", "author", ViewOnSiteButton(), ActivityLog()]
  • Link: a text link that opens the URL get_url(obj, request) returns.
  • ButtonLink: the same as a button, with an optional icon. Set copy = True to add a button that copies the URL.
  • ActivityLog: the changes made to the object, newest first, under the title "Activity" or the title you pass.

Only these components are supported; other component types are not. Links appear once the object is saved.

Each component gets an ID from its class and its label, so every worker of a deployment agrees on it. Two components of the same class with the same label need an explicit component_id (a UUID); manage.py check reports duplicates.