Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rahul-baberwal/django-var-cms/llms.txt

Use this file to discover all available pages before exploring further.

django-var-cms renders every add/edit form on a 12-column CSS grid. You can control the width of each field, group fields into visual rows, enable a rich text editor, enforce regex patterns, swap in custom dropdown widgets, and inject CSS classes, inline styles, placeholders, and help text — all from your VarCMSModelAdmin subclass without touching any template.

12-Column Grid — form_field_widths

The form grid spans 12 columns and automatically stretches to fill the available screen width. Use form_field_widths to set a named width preset for any field.
PresetGrid columnsDescription
"full"12Full row width — default for TextField and BooleanField
"half"6Half the row — default for most other field types
"one-third"4One-third of the row
"two-thirds"8Two-thirds of the row
"one-fourth"3One-quarter of the row
"three-fourths"9Three-quarters of the row
class ArticleAdmin(VarCMSModelAdmin):
    form_field_widths = {
        "title":    "two-thirds",   # 8 columns — wide title input
        "status":   "one-third",    # 4 columns — sits beside title
        "category": "half",         # 6 columns
        "author":   "half",         # 6 columns — sits beside category
    }
Width presets that add up to 12 columns will sit side-by-side on a single visual row (e.g., "two-thirds" + "one-third" = 8 + 4 = 12). Fields that don’t sum to 12 wrap naturally.
form_field_widths takes the highest priority in the layout system. A field listed in form_field_widths always uses its explicit preset, regardless of any form_field_rows grouping for that field.

Field Row Grouping — form_field_rows

form_field_rows lets you declare groups of fields that should always appear on the same visual row. Fields within a group automatically share the available 12 columns equally — you don’t need to calculate widths manually.
  • A row of 2 fields → each field gets 6 columns ("half")
  • A row of 3 fields → each field gets 4 columns ("one-third")
  • A row of 4 fields → each field gets 3 columns ("one-fourth")
form_field_rows is evaluated after form_field_widths. If a field already has an entry in form_field_widths, that explicit preset wins and the row grouping is ignored for that field.
class CustomerAdmin(VarCMSModelAdmin):
    form_field_rows = [
        ["first_name", "last_name"],               # 2 fields → each 6 columns
        ["mobile", "email", "date_of_birth"],      # 3 fields → each 4 columns
    ]
Fields not listed in any row continue to use the default heuristic: full-width for textareas and checkboxes, half-width for everything else.

Rich Text Editor — html_fields

Add any TextField name to html_fields to replace the plain <textarea> with a Quill.js rich text editor. The editor is fully embedded — no external CDN or additional configuration is required. Non-html TextField fields receive a plain <textarea> with rows=4.
class ArticleAdmin(VarCMSModelAdmin):
    html_fields = ["body"]   # Quill.js editor with rows=10

class PageAdmin(VarCMSModelAdmin):
    html_fields = ["body"]   # works on any TextField
The raw HTML produced by Quill is stored directly in the database column, exactly as a regular TextField would store its value.

Regex Validators — regex_validators

regex_validators maps a field name to a (pattern, message) tuple. django-var-cms applies the validation both client-side (HTML5 pattern and title attributes on the input widget) and server-side (a Django RegexValidator attached to the form field), ensuring consistent enforcement regardless of whether JavaScript is enabled.
class CategoryAdmin(VarCMSModelAdmin):
    regex_validators = {
        "slug": (
            r"^[a-z0-9-]+$",
            "Slug must consist of lowercase letters, numbers, and hyphens only."
        )
    }
You can add validators for multiple fields in a single dict:
class CustomerAdmin(VarCMSModelAdmin):
    regex_validators = {
        "phone":    (r"^\+?[0-9\s\-]{7,15}$",  "Enter a valid phone number."),
        "postcode": (r"^[A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2}$", "Enter a valid UK postcode."),
    }

Custom Dropdown Widgets — form_field_widgets

form_field_widgets maps a field name to a widget type string, giving you control over how ForeignKey, CharField with choices, and ManyToManyField fields are rendered in the form.
Widget typeRendered asCSS classes applied
"select"Standard <select> dropdown(no override — Django default)
"select_search"Searchable <select> with live filtervcms-searchable-select
"multiselect"CheckboxSelectMultiple (all choices visible)vcms-checkbox-multi
"multiselect_search"CheckboxSelectMultiple with a search inputvcms-checkbox-multi vcms-checkbox-search
class OrderAdmin(VarCMSModelAdmin):
    form_field_widgets = {
        "status":   "select",              # plain dropdown (default behaviour)
        "customer": "select_search",       # searchable dropdown for FK
        "tags":     "multiselect_search",  # checkbox list with search for M2M
    }
"multiselect" and "multiselect_search" use CheckboxSelectMultiple and are designed for ManyToManyField relationships. Use "select_search" for ForeignKey fields instead.

Widget CSS Classes — form_widget_classes

form_widget_classes injects CSS class names directly onto the underlying <input>, <select>, or <textarea> HTML element. The classes are appended to any existing class attributes already on the widget.
class ArticleAdmin(VarCMSModelAdmin):
    form_widget_classes = {
        "title": "form-control-lg",   # appended onto <input>
        "body":  "editor-full",       # appended onto <textarea>
    }

Placeholders — form_field_placeholders

form_field_placeholders sets the HTML placeholder attribute on each input widget, giving users contextual guidance before they type.
class ArticleAdmin(VarCMSModelAdmin):
    form_field_placeholders = {
        "title":  "Enter article title...",
        "author": "Full name of the author",
        "slug":   "auto-generated-if-left-blank",
    }

Help Text — form_field_help_texts

form_field_help_texts sets the help_text property on each form field, overriding any help_text defined on the model field itself.
class ArticleAdmin(VarCMSModelAdmin):
    form_field_help_texts = {
        "body":  "Write the full article details using the Quill editor.",
        "slug":  "URL-friendly identifier — leave blank to auto-generate from title.",
        "tags":  "Comma-separated list of tags, e.g. python, django, web.",
    }

Readonly Fields and Disabled Fields

Fields listed in readonly_fields are excluded from the form entirely and displayed separately as static values. They cannot be edited by any user. Per-role edit control is handled through role_editable_fields. When a user’s role restricts editable fields to a subset, any form field not in that subset has field.disabled = True applied — the field remains visible in the form but cannot be changed.

Container Classes and Styles

Two additional dicts apply to the wrapper <div> that surrounds each field (rather than the input element itself).

form_field_classes

Injects CSS class names onto the field’s container <div>:
class ArticleAdmin(VarCMSModelAdmin):
    form_field_classes = {
        "rating": "highlight-field",
    }

form_field_styles

Appends inline CSS style rules to the field’s container <div>. These are merged with the grid-column span rule that the 12-column system injects:
class ArticleAdmin(VarCMSModelAdmin):
    form_field_styles = {
        "rating": "border-left: 3px solid var(--accent); padding-left: 8px;",
    }

Complete Example

The example below combines all form layout features into a realistic ArticleAdmin:
# myapp/var_cms_admin.py
from var_cms.registry import var_cms_site, VarCMSModelAdmin
from .models import Article


class ArticleAdmin(VarCMSModelAdmin):

    # ── List view ─────────────────────────────────────────────────────────────
    list_display    = ["title", "category", "author", "status", "is_featured", "created_at"]
    list_filter     = ["status", "is_featured", "category"]
    search_fields   = ["title", "body", "author"]
    ordering        = ["-created_at"]
    list_per_page   = 20
    readonly_fields = ["created_at", "updated_at", "view_count"]
    icon            = "file-text"

    # ── Rich text editor ──────────────────────────────────────────────────────
    html_fields = ["body"]

    # ── 12-column grid widths ─────────────────────────────────────────────────
    form_field_widths = {
        "title":    "two-thirds",   # 8 cols
        "status":   "one-third",    # 4 cols  → title + status fill the row
        "category": "half",         # 6 cols
        "author":   "half",         # 6 cols  → category + author fill the row
        "rating":   "one-fourth",   # 3 cols
    }

    # ── Row grouping (used only for fields NOT in form_field_widths) ──────────
    # form_field_rows is evaluated after form_field_widths, so fields already
    # listed in form_field_widths keep their explicit preset.
    # form_field_rows = [
    #     ["title", "status"],
    #     ["category", "author"],
    # ]

    # ── Regex validation ──────────────────────────────────────────────────────
    regex_validators = {
        "slug": (r"^[a-z0-9-]+$", "Slug must use lowercase letters, numbers, and hyphens only.")
    }

    # ── Custom widget types ───────────────────────────────────────────────────
    form_field_widgets = {
        "category": "select_search",   # searchable FK dropdown
    }

    # ── Widget-level CSS classes ──────────────────────────────────────────────
    form_widget_classes = {
        "title": "form-control-lg",
    }

    # ── Placeholders ──────────────────────────────────────────────────────────
    form_field_placeholders = {
        "title":  "Enter article title...",
        "author": "Full name",
        "slug":   "auto-generated-if-left-blank",
    }

    # ── Help texts ────────────────────────────────────────────────────────────
    form_field_help_texts = {
        "body":   "Write the full article using the Quill rich text editor.",
        "rating": "Decimal value between 0.0 and 9.9.",
    }

    # ── Container styles ──────────────────────────────────────────────────────
    form_field_styles = {
        "rating": "border-left: 3px solid var(--accent); padding-left: 8px;",
    }


var_cms_site.register(Article, ArticleAdmin)

Build docs developers (and LLMs) love