🧱 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 forField(name).FieldLayout(fields=[...], columns=1): a group of fields shown incolumnscolumns.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.
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.
Sidebar
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 URLget_url(obj, request)returns.ButtonLink: the same as a button, with an optionalicon. Setcopy = Trueto add a button that copies the URL.ActivityLog: the changes made to the object, newest first, under the title "Activity" or thetitleyou 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.