Core Concepts: Widgets

Widget is the base class for all display elements on a dashboard. It's designed to be flexible and can fetch and display data from various sources.

Base Widget Properties

Here are the most common properties you can define on a widget class:

  • title: The display title of the widget. If not provided, the class name is used.
  • model: The Django model associated with this widget. This is used by get_queryset() if queryset is not defined, and helps in generating admin URLs.
  • queryset: A Django QuerySet to use as the data source. If provided, it overrides model.
  • limit_to: An integer to limit the number of items returned by the default values() method. Defaults to 10.
  • width: The widget's width in the grid system. Defaults to widgets.MEDIUM. See Dashboards for more details.
  • height: An integer specifying the max-height of the widget's body in pixels. If the content exceeds this, it becomes scrollable.
  • cache_timeout: Cache the widget's rendered body for a specified number of seconds. Default is None (no caching).
  • changelist_url: Adds a link from the widget to a model's admin changelist page. This is highly flexible:

    from .models import MyModel
    from controlcenter import widgets
    
    class MyWidget(widgets.ItemList):
        # 1. Simple model link
        changelist_url = MyModel
    
        # 2. Link with GET parameters from a dictionary
        changelist_url = (MyModel, {'status__exact': 0, 'o': '-7.-1'})
    
        # 3. Link with GET parameters from a string
        changelist_url = (MyModel, 'status__exact=0&o=-7.-1')
    
        # 4. A hardcoded internal or external URL
        changelist_url = '/admin/some/custom/view/'

Key Methods

  • get_queryset(): Returns the queryset for the widget. The default implementation returns self.queryset.all() if queryset is set, otherwise self.model._default_manager.all(). You can override this to provide custom filtering.

    class MyOrdersWidget(widgets.ItemList):
        model = Order
    
        def get_queryset(self):
            # Start with the default queryset
            queryset = super(MyOrdersWidget, self).get_queryset()
            # Filter based on the logged-in user
            if not self.request.user.is_superuser:
                return queryset.filter(manager=self.request.user)
            return queryset
  • values(): This is the primary method for fetching data. By default, it returns the result of get_queryset(), applying the limit_to slice. This method is automatically wrapped with Django's cached_property, meaning it runs only once per widget instance, and the result is cached. This prevents multiple database queries if you access the data more than once during rendering.

    Important Notes on values():

    1. Because it's a cached_property, you access it without parentheses: self.values not self.values().
    2. Do not use yield or return a generator, as they cannot be cached.
    class MyChartWidget(widgets.LineChart):
        def labels(self):
            # Access cached values
            return [item.date for item in self.values]
    
        def series(self):
            # Access cached values again without a new DB query
            return [[item.count for item in self.values]]
    
        def values(self):
            # Note: accessed as a property in other methods
            # This code runs only once.
            queryset = super(MyChartWidget, self).get_queryset()
            return queryset.order_by('date')