Base Models

class widgy.models.base.Content[source]

Accessor for the Node that the Content belongs to.

Tree Traversal

With the exception depth_first_order(), the following methods are all like the traversal API provided by Treebeard, but instead of returning Nodes, they return Contents.


Convenience method for iterating over all the Contents in a subtree in order. This is similar to Treebeard’s get_descendants(), but includes itself.

Tree Manipulation

The following methods mirror those of Node, but accept a WidgySite as the first argument. You must call these methods on Content and not on Node.

>>> root = Layout.add_root(widgy_site)
>>> main = root.add_child(widgy_site, MainContent)
>>> sidebar = main.add_sibling(widgy_site, Sidebar, title='Alerts')
# move the sidebar to the left of the main content.
>>> sidebar.reposition(widgy_site, right=main)
classmethod add_root(cls, site, **kwargs)[source]

Creates a root node widget. Any kwargs will be passed to the Content class’s initialize method.

add_child(self, site, cls, **kwargs)[source]

Adds a new instance of cls as the last child of the current widget.

add_sibling(self, site, cls, **kwargs)[source]

Adds a new instance of cls to the right of the current widget.

reposition(self, site, right=None, parent=None)[source]

Moves the current widget to the left of right or to the last child position of parent.

post_create(self, site)[source]

Hook for doing things after a widget has been created (a Content has been created and put in the tree). This is useful if you want to have default children for a widget, for example.

delete(self, raw=False)[source]

If raw is True the widget is being deleted due to a failure in widget creation, so post_create will not have been run yet.


This method is called by Node.clone_tree(). You may wish to override it if your Content has special needs like a ManyToManyField.


Clone is used to freeze tree state in Versioning. If your clone() method is incorrect, your history will be corrupt.



A human-readable short name for widgets. This defaults to the verbose_name of the widget.


You can use the @property decorator to make this dynamic.




A class attribute that sets the tooltip for this widget on the shelf.


A list of CSS classes to apply to the widget element in the Editor. Defaults to app_label and module_name of the widget.

shelf = False

Denotes whether this widget have a shelf. Root nodes automatically have a shelf. The shelf is where the widgets exist in the interface before they are dragged on. It is useful to set shelf to True if there are a large number of widgets who can only go in a specfic subtree.

component_name = 'widget'

Specifies which JavaScript component to use for this widget.


Write documentation about components.

pop_out = CANNOT_POP_OUT

It is possible to open a subtree in its own editing window. pop_out controls if a widget can be popped out. There are three values for pop_out:

form = ModelForm

The form class to use for editing. Also see get_form_class().

formfield_overrides = {}

Similar to ModelAdmin, Content allows you to override the form fields for specific model field classes.

draggable = True

Denotes whether this widget may be moved through the editing interface.

deletable = True

Denotes whether this widget may be deleted through the editing interface.

editable = False

Denotes whether this widget may be edited through the editing interface. Widgy will automatically generate a ModelForm to provide the editing functionality. Also see form and get_form_class().


A template name or list of template names for rendering in the widgy Editor. See get_templates_hierarchy() for how the default value is derived.


A template name or list of template names for rendering the edit interface in the widgy Editor. See get_templates_hierarchy() for how the default value is derived.

get_form_class(self, request)[source]

Returns a ModelForm class that is used for editing.

get_form(self, request, **form_kwargs)[source]

Returns a form instance to use for editing.

classmethod get_templates_hierarchy(cls, **kwargs)[source]

Loops through MRO to return a list of possible template names for a widget. For example the preview template for something like Tabs might look like:

  • widgy/page_builder/tabs/preview.html
  • widgy/mixins/tabbed/preview.html
  • widgy/page_builder/accordion/preview.html
  • widgy/page_builder/bucket/preview.html
  • widgy/models/content/preview.html
  • widgy/page_builder/preview.html
  • widgy/mixins/preview.html
  • widgy/page_builder/preview.html
  • widgy/models/preview.html
  • widgy/preview.html

Frontend Rendering

render(self, context, template=None)[source]

The method that is called by the render() template tag to render the Content. It is useful to override this if you need to inject things into the context.

get_render_templates(self, context)[source]

Returns a template name or list of template names for frontend rendering.


Widgy provide robust machinery for compatibility between Contents. Widgy uses the compatibility system to validate the relationships between parent and child Contents.

Compatibility is checked when rendering the shelf and when adding or moving widgets in the tree.

accepting_children = False

An easy compatibility configuration attribute. See valid_parent_of() for more details.

valid_parent_of(self, cls, obj=None)[source]

If obj is provided, return True if it could be a child of the current widget. cls is the type of obj.

If obj isn’t provided, return True if a new instance of cls could be a child of the current widget.

obj is None when the child widget is being created or Widgy is checking the compatibility of the widgets on the shelf. If it is being moved from another location, there will be an instance. A parent and child are only compatible if both valid_parent_of() and valid_child_of() return True. This defaults to the value of accepting_children.

Here is an example of a parent that only accepts three instances of B:

class A(Content):
    def valid_parent_of(self, cls, obj=None):
        # If this is already my child, it can stay my child.
        # This works for obj=None because self.get_children()
        # will never contain None.
        if obj in self.get_children():
            return True
            # Make sure it is of type B
            return (issubclass(cls, B)
            # And that I don't already have three children.
                and len(self.get_children()) < 3)
classmethod valid_child_of(cls, parent, obj=None)[source]

If obj is provided, return True if it can be a child of parent. obj will be an instance of cls—it may feel like an instance method.

If obj isn’t provided, return True if a new instance of cls could be a child of parent.

This defaults to True.

Here is an example of a Content that can not live inside another instance of itself:

class Foo(Content):
    def valid_child_of(cls, parent, obj=None):
        for p in list(parent.get_ancestors()) + [parent]:
            if isinstance(p, Foo):
                return False
        return super(Foo, cls).valid_child_of(parent, obj)
equal(self, other)[source]

Should return True if self is equal to other. The default implementation checks the equality of each widget’s get_attributes().

class widgy.models.base.Node[source]

A generic foreign key point to our Content instance.


A boolean field indicating whether this node is frozen and can’t be changed in any way. This is used to preserve old tree versions for versioning.

render(self, *args, **kwargs)[source]

Renders this subtree and returns a string. Normally you shouldn’t call it directly, use widgy.db.fields.WidgyField.render() or widgy.templatetags.widgy_tags.render().


Like Content.depth_first_order(), but over nodes.


Efficiently fetches an entire tree (or subtree), including content instances. It uses 1 + m queries, where m is the number of distinct content types in the tree.

classmethod prefetch_trees(cls, *root_nodes)[source]

Prefetches multiple trees. Uses n + m queries, where n is the number of trees and m is the number of distinct content types across all the trees.


Prefetches the tree unless it has been prefetched already.

classmethod find_widgy_problems(cls, site=None)[source]

When a Widgy tree is edited without protection from a transaction, it is possible to get into an inconsistent state. This method returns a tuple containing two lists:

  1. A list of node pks whose content pointer is dangling – pointing to a content that doesn’t exist.
  2. A list of node pks whose content_type doesn’t exist. This might happen when you switch branches and remove the code for a widget, but still have the widget in your database. These are represented by UnknownWidget instances.