class popupcrud.views.PopupCrudViewSet(*args, **kwargs)

This is the base class from which you derive a class in your project for each model that you need to build CRUD views for.

model = None

The model to build CRUD views for. This is a required attribute.

new_url = None

URL to the create view for creating a new object. This is a required attribute.

list_display = ()

Lists the fields to be displayed in the list view columns. This attribute is modelled after ModelAdmin.list_display and supports model methods as as ViewSet methods much like ModelAdmin. This is a required attribute.

So you have four possible values that can be used in list_display:

  • A field of the model
  • A callable that accepts one parameter for the model instance.
  • A string representing an attribute on ViewSet class.
  • A string representing an attribute on the model

See ModelAdmin.list_display documentation for examples.

A note about list_display fields with respect to how it differs from ModelAdmin’s list_display.

In ModelAdmin, if a field specified in list_display is not a database field, it can be set as a sortable field by setting the method’s admin_order_field attribute to the relevant database field that can be used as the sort field. In PopupCrudViewSet, this attribute is named order_Field.

fields = ()

A list of names of fields. This is interpreted the same as the Meta.fields attribute of ModelForm. This is a required attribute.

form_class = None

The form class to instantiate for Create and Update views. This is optional and if not specified a ModelForm using the values of fields attribute will be instantiated. An optional attribute, if specified, overrides fields attribute value.

list_url = None

The url where the list view is rooted. This will be used as the success_url attribute value for the individual CRUD views. This is a required attribute.

paginate_by = 10

Number of entries per page in list view. Defaults to 10. Setting this to None will disable pagination. This is an optional attribute.

list_permission_required = ()

List of permission names for the list view. Permission names are of the same format as what is specified in permission_required() decorator. Defaults to no permissions, meaning no permission is required.

Depracated. Use permissions_required dictionary instead.

create_permission_required = ()

List of permission names for the create view. Defaults to no permissions, meaning no permission is required.

Depracated. Use permissions_required dictionary instead.

detail_permission_required = ()

List of permission names for the detail view. Defaults to no permissions, meaning no permission is required.

Depracated. Use permissions_required dictionary instead.

update_permission_required = ()

List of permission names for the update view. Defaults to no permissions, meaning no permission is required.

Depracated. Use permissions_required dictionary instead.

delete_permission_required = ()

List of permission names for the delete view. Defaults to no permissions, meaning no permission is required.

Depracated. Use permissions_required dictionary instead.

permissions_required = {}

Permissions table for the various CRUD views. Use this instead of list_permission_required, create_permission_required, etc. Entries in this table are indexed by the CRUD view code and its required permissions tuple. CRUD view codes are: ‘list’, ‘create’, ‘detail’, ‘update’ & ‘delete’.

Note that if both the legacy <crud-op>_permission_required and permissons_required are specified, permissions_required setting value takes effect.

For example you can specify:

permissions_required = {
    'list': ('library.list_author',),
    'create': ('library.list_author',),
    'detail': ('library.view_author',),
    'update': ('library.update_author',),
    'delete': ('library.delete_author',)
list_template = None

The template file to use for list view. If not specified, defaults to the internal template.

related_object_popups = {}

A table that maps foreign keys to its target model’s PopupCrudViewSet.create() view url. This would result in the select box for the foreign key to display a ‘New {model}’ link at its bottom, which the user can click to add a new {model} object from another popup. The newly created {model} object will be added to the select’s options and set as its selected option.

Defaults to empty dict, meaning creation of target model objects, for the foreign keys of a model, from a popup is disabled.

page_title = ''

Page title for the list view page.

legacy_crud = False

Enables legacy CRUD views where each of the Create, Detail, Update & Delete views are performed from their own dedicated web views like Django admin (hence the term legacy_crud :-)).

This property can accept either a boolean value, which in turn enables/ disables the legacy mode for all the CRUD views or it can accept a dict of CRUD operation codes and its corresponding legacy mode specified as boolean value.

This dict looks like:

legacy_crud = {
    'create': False,
    'detail': False,
    'update': False,
    'delete': False

So by setting legacy_crud[detail] = True, you can enable legacy style crud for the detail view whereas the rest of the CRUD operations are performed from a modal popup.

In other words, legacy_crud boolean value results in a dict that consists of True or False values for all its keys, as the case may be.

This defaults to False, which translates into a dict consisting of False values for all its keys.

login_url = None

Same as django.contrib.auth.mixins.AccessMixin login_url, but applicable for all CRUD views.

raise_exception = False

Same as django.contrib.auth.mixins.AccessMixin raise_exception, but applicable for all CRUD views.

empty_list_icon = None

Icon to be displayed above the empty list state message. Defaults to None, which displays no icon. To specify an icon, set this property to the CSS class of the required icon.

For example to use the glyphicon-book icon, set this property to:

empty_list_icon = 'glyphicon glyphicon-book'

Icons displayed are enlarged to 5 times the standard font size.

empty_list_message = 'No records found.'

Message to be displayed when list view contains no records, that is, empty list state. Defaults to ‘No records found`.

Empty list state rendering can be customized further by overriding popupcrud/empty_list.html template in your own project.

breadcrumbs = []

List of breadcrumbs that will be added to ViewSet views’ context, allowing you build a breadcrumb hierarchy that reflects the ViewSet’s location in the site.

Note that for legacy_crud views, system would add the list view url to the breadcrumbs list.

breadcrumbs_context_variable = 'breadcrumbs'

The template context variable name that will be initialized with the value of breadcrumbs property. You can enumerate this variable in your base template to build a breadcrumbs list that reflects the hierarchy of the page.

item_actions = []
  • its title
    • its icon css such as glyphicon glyphicon-ok

    • its action handler, which is the name of the CrudViewSet method to be called when user selects the action. This method has the following signature:

      def action_handler(self, request, item):
          # action processing
          return (True, "Action completed")

      The return value from the action handler is a 2-tuple that consists of a boolean success indicator and a message. The message is displayed to the user when the action is completed.

Also see get_item_actions() documentation below.

modal_sizes = {}

Defaults to:

modal_sizes = {
    'create_update': 'normal',
    'delete': 'normal',
    'detail': 'normal'

You only need to specify the modal whose size you want to adjust. So if you want to adjust the size of the create_update modal to large while leaving the rest to their default size, you may specify modal_sizes as:

modal_sizes = {
    'create_update': 'large',
context_object_name = None

If specified, the name of the context variable that will be used to assign the object instance value. By default the context variable object will be assigned the object instance. If context_object_name is specified, that too will be assigned the object instance.

pk_url_kwarg = 'pk'

Same as SingleObjectMixin.pk_url_kwarg, which is the name of the URLConf keyword argument that contains the primary key. By default, pk_url_kwarg is pk`.

slug_field = 'slug'

Same as SingleObjectMixin.slug_field, which is the name of the field on the model that contains the slug. By default, slug_field is slug.

To use slug_field as the key to access object instances (for detail, update & delete views), set pk_url_kwarg = None in the ViewSet class and initialize slug_field and slug_url_kwarg to the relevant slug field’s name & its corresponding URLconf parameter name respectively.

slug_url_kwarg = 'slug'

Same as SingleObjectMixin.slug_url_kwarg, which is the name of the URLConf keyword argument that contains the slug. By default, slug_url_kwarg is slug.

classmethod list(**initkwargs)

Returns the list view that can be specified as the second argument to url() in

classmethod create(**initkwargs)

Returns the create view that can be specified as the second argument to url() in

classmethod detail(**initkwargs)

Returns the create view that can be specified as the second argument to url() in

classmethod update(**initkwargs)

Returns the update view that can be specified as the second argument to url() in

classmethod delete(**initkwargs)

Returns the delete view that can be specified as the second argument to url() in


Returns the URL to create a new model object. Returning None would disable the new object creation feature and will hide the New {model} button.

You may override this to dynamically determine if new object creation ought to be allowed. Default implementation returns the value of ViewSet.new_url.


Override this returning the URL where PopupCrudViewSet.detail() is placed in the URL namespace such that ViewSet can generate the appropriate href to display item detail in list view.

When this hyperlink is clicked, a popup containing the object’s detail will be shown. By default this popup only shows the object’s string representation. To show additional information in this popup, implement <object>_detail.html in your project, typically in the app’s template folder. If this file exists, it will be used to render the object detail popup. True to Django’s DetailView convention, you may use the {{ object }} template variable in the template file to access the object and its properties.

Default implementations returns None, which results in object detail popup being disabled.


Override this returning the URL where PopupCrudViewSet.update() is placed in the URL namespace such that ViewSet can generate the appropriate href to the item edit hyperlink in list view.

If None is returned, link to edit the specified item won’t be shown in the object row.


Override this returning the URL where PopupCrudViewSet.delete() is placed in the URL namespace such that ViewSet can generate the appropriate href to the item delete hyperlink in list view.

If None is returned, link to delete the specified item won’t be shown in the object row.


Return the name of the object that will be displayed in item action prompts for confirmation. Defaults to str(obj), ie., the string representation of the object. Override this to provide the user with additional object details. The returned string may contain embedded HTML tags.

For example, you might want to display the balance due from a customer when confirming user action to delete the customer record.


Return the permission required for the CRUD operation specified in op. Default implementation returns the value of one {list|create|detail|update|delete}_permission_required class attributes. Overriding this allows you to return dynamically computed permissions.

Parameters:op – The CRUD operation code. One of {'list'|'create'|'detail'|'update'|'delete'}.
Return type:The permission_required tuple for the specified operation. Determined by looking up the given op from the table:
permission_table = {
    'list': self.list_permission_required,
    'create': self.create_permission_required,
    'detail': self.detail_permission_required,
    'update': self.update_permission_required,
    'delete': self.delete_permission_required
get_page_title(view, obj=None)

Returns page title for the CRUD view. Parameter view specifies the CRUD view whose page title is being queried and is one of create, detail, update, delete or list.

For detail, update & delete views, the model instance is is passed as second argument. For the rest of the views, this is set to None.

classmethod urls(namespace=None, views=('create', 'update', 'delete', 'detail'))

Returns the CRUD urls for the viewset that can be added to the URLconf. The URLs returned can be controlled by the views parameter which is tuple of strings specifying the CRUD operations URLs to be returned. This defaults to all the CRUD operations: create, read(detail), update & delete (List view URL is added by default).

This method can be seen as a wrapper to calling the individual view generator methods, list(), detail(), create(), update() & delete(), to register them with the URLconf.

The urls for CRUD actions involving a single object (detail, update & delete) are by default composed using pk as URLConf keyword argument. However, if pk_url_kwarg is set to None and slug_field and slug_url_kwarg are initialized, it will be based as the field used to locate the individual object and URLConf keyword argument respectively.

  • namespace – The namespace under which the CRUD urls are registered. Defaults to the value of <model>.Meta.verbose_name_plural (in lowercase and in English).
  • views – A tuple of strings representing the CRUD views whose URL patterns are to be registered. Defaults to ('create', 'update', 'delete', 'detail'), that is all the CRUD operations for the model.
Return type:

A collection of URLs, packaged using django.conf.urls.include(), that can be used as argument 2 to url() (see example below).


The following pattern registers all the CRUD urls for model Book (in app library), generated by BooksCrudViewSet:

urlpatterns += [
    url(r'^books/', BooksCrudViewSet.urls())

This allows us to refer to individual CRUD operation url as:

reverse("library:books:detail", kwargs={'pk':})
reverse("library:books:update", kwargs={'pk':})
reverse("library:books:delete", kwargs={'pk':})

Provides a normalized dict of crud view types to use for the viewset depending on client.legacy_crud setting.

Computes this dict only once per object as an optimization.


Determine the icon used to display empty list state.

Returns the value of empty_list_icon property by default.


Determine the message used to display empty table state.

Returns the value of empty_list_message property by default.


Returns the value of ViewSet.breadcrumbs property. You can use this method to return breadcrumbs that contain runtime computed values.


Called by ListView allowing ViewSet to do further filtering of the queryset, if necessary. By default returns the queryset argument unchanged.

Parameters:qs – Queryset that is used for rendering ListView content.
Return type:A valid Django queryset.

For Create and Update views, this method allows passing custom arguments to the form class constructor. The return value from this method is combined with the default form constructor **kwargs before it is passed to the form class’ __init__() routine’s **kwargs.

Since Django CBVs use kwargs initial & instance, be careful when using these, unless of course, you want to override the objects provided by these keys.


Return the formset class to the child model of this parent model allowing create/edit of multiple objects of the child model.

Typically, though not required, the return value will be a class generated by the django formset factory function inlineformset_factory().

By default, this method returns None, which indicates that the model Create/Edit forms do not have a formset for a child model.


Returns the formset object instantiated from the class returned by the get_formset_class() method.

By default returns None indicating no formset is associated with the model.


Determine the custom actions for the given model object that is displayed after the standard Edit & Delete actions in list view.

Parameters:obj – The row object for which actions are being queried.
Return type:A list of action 3-tuple (as explained in item_actions) objects relevant for the given object. If no actions are to be presented for the object, an empty list([]) can be returned.

Default implementation returns the value of item_actions class variable.

Since this method is called once for each row item, you can customize the actions that is presented for each object. You can also altogether turn off all actions for an object by returning an empty list([]).

invoke_action(request, index, item)

Invokes the custom action specified by the index.

request - HttpRequest object index - the index of the action into get_item_actions() list item_or_list - the item upon which action is to be performed
Action result as a 2-tuple: (bool, message)
Index error if the action index specified is outside the scope of the array returned by get_item_actions().

Called for every CRUD view’s get_context_data() method, this method allows additional data to be added to the CRUD view’s template context.

Parameters:kwargs – The kwargs dictionary that is the usual argument to View.get_context_data()
Return type:None

If you want to add context data for a specific CRUD view, you can achieve this by checking the view object’s class type. For example the following code adds context data only for DetailView:

if isinstance(self.view, DetailView):
    obj = kwargs['object']
    kwargs['user_fullname'] = obj.user.first_name + ' ' + obj.user.last_name


class popupcrud.widgets.RelatedFieldPopupFormWidget(widget, new_url, *args, **kwargs)

A modified version of django.admin’s RelatedFieldWidgetWrapper, adds a Create New hyperlink to the bottom of the select box of a related object field. This hyperlink will have CSS class add-another and its id set to add_id_<field_name> with its href set to javascript:void(0);.

The associated JavaScript popupcrud/js/popupcrud.js, binds a click handler to .add-another, which then activates the Bootstrap modal associated with the hyperlink. The modal body will be filled with the HTML response from an AJAX request to the hyperlink’s data-url attribute value.

The JavaScript file is added to the form’s media list automatically.

__init__(widget, new_url, *args, **kwargs)

Constructor takes the following required parameters:

  • widget – The underlying Select widget that this widget replaces.
  • url – The url to load the HTML content to fill the assocaited modal body.

Template Tags


A tag to help creation of Bootstrap modal dialogs. You may use this tag as:

{% bsmodal dialogTitle dialogId [close_title_button={Yes|No}] %}
    <dialog content goes here>
{% endbsmodal %}
dialogTitle:Required. The title of the modal window. This can be a template variable (created with {% trans 'something' as var %}) or a string literal.
dialogId:Required. The id of the modal window specified as string literal.
 Optional. A flag indicating whether to show the modal window close button on the titlebar. Specify one of Yes or No.
size:Optional. Dialog size hint. Acceptable values: {small|normal|large}. Defaults to normal.

This would create a hidden dialog with title dialogTitle and id dialogId. The content of the dialog body is to be written between the pair of tags {% bsmodal %} and {% endbsmodal %}.

The final rendered html fragment would look like this:

<div class="modal fade" tabindex="-1" role="dialog">
    <div class="modal-dialog modal-dialog-top" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title">{{dialogTitle}}</h4>
            <div class="modal-body">
                <..content between bsmodal & endbsmodal tags..>

The html template for the modal is stored in popupcrud/modal.html. So if you want to custom styling of the modal windows, you may define your own template in your projects templates folder.

Refer to Boostrap docs on modals for more information on how to show and hide the modal windows.