toolkit.views – Toolkit views

class toolkit.views.views.CCECreateView(**kwargs)

This view includes all the mixins required in all CreateViews.

Usage:
1
2
3
4
5
6
class PollCreateView(CCECreateView):
    model = Poll
    form_class = PollCreateForm
    page_title = "Create a poll"
    sidebar_group = ['polls', ]
    success_message = "Poll added successfully."
Advanced Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class PollCreateView(CCECreateView):
    model = Poll
    form_class = PollCreateForm
    template_name = "polls/add.html"
    page_title = "Create a poll"
    sidebar_group = ['polls', ]
    success_message = "Poll added successfully."

    def context_menu_items(self):
        items = super(PollListView, self).context_menu_items()
        items.append(
            # label, reversed url, icon class, sidebar_group
            (
                "Link to something else you want",
                reverse('link_to_something_else'),
                "glyphicon glyphicon-fire",
                "something_else",
            )
        )
        return items
class toolkit.views.views.CCECreateWithInlinesView(**kwargs)

This view includes all the mixins required in all CreateWithInlinesViews.

class toolkit.views.views.CCEDeleteView(**kwargs)

This view includes all the mixins required in all DeleteViews.

class toolkit.views.views.CCEDetailView(**kwargs)

This view includes all the mixins required in all DetailViews.

Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class PollDetailView(CCEDetailView):
    model = Poll
    page_title = "Poll Details"
    sidebar_group = ['polls']
    detail_fields = [
        ('Name', 'name'),
        ('Active', 'active'),
        ('Description', 'description'),
        ('Choices', lambda poll: some_function(poll)),
    ]
    show_context_menu = True
Advanced Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class PollDetailView(CCEDetailView):
    model = Poll
    page_title = "Poll Details"
    sidebar_group = ['polls']
    detail_fields = [
        ('Name', 'name'),
        ('Active', 'active'),
        ('Description', 'description'),
        ('Choices', lambda poll: some_function(poll)),
    ]
    show_context_menu = True

    def context_menu_items(self):
        items = super(PollDetailView, self).context_menu_items()
        items.append(
            # label, reversed url, icon class, sidebar_group
            (
                "Link to something else you want",
                reverse('link_to_something_else'),
                "glyphicon glyphicon-fire",
                "something_else",
            )
        )
        return items
class toolkit.views.views.CCEFormView(**kwargs)

This view includes the mixins required for all FormViews.

class toolkit.views.views.CCEListView(**kwargs)

This view includes all the mixins required in all ListViews.

Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class PollListView(CCEListView):
    model = Poll
    paginate_by = 10
    page_title = "Browse Polls"
    sidebar_group = ['polls', ]
    columns = [
        ('Name', 'name'),
        ('Active', 'active'),
    ]
    show_context_menu = True
Advanced Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class PollListView(CCEListView):
    model = Poll
    paginate_by = 10
    template_name = "polls/list.html"
    ordering = ['-created_at']
    page_title = "Browse Polls"
    sidebar_group = ['polls', ]
    # Column widths should add up to 12
    columns = [
        ('Name', 'name', 4),
        ('Active', 'active', 5),
    ]
    actions_column_width = 3
    show_context_menu = True
    show_add_button = True
    popover_rows = [
        ('Description', 'description'),
        ('Choices', lambda poll: some_function(poll)),
    ]

    def context_menu_items(self):
        items = super(PollListView, self).context_menu_items()
        items.append(
            # label, reversed url, icon class, sidebar_group
            (
                "Edit All Polls at Once",
                reverse('edit_all_polls'),
                "glyphicon glyphicon-pencil",
                "edit_all_polls",
            )
        )
        return items

    def render_buttons(self, user, obj, **kwargs):
        button_list = super(PollListView, self).render_buttons(user, obj, **kwargs)
        button_list.extend([
            self.render_button(
                url_name='edit_poll_permissions',
                pk=obj.pk,
                icon_classes='fa fa-lock',
            ),
            self.render_button(
                btn_class='warning',
                label='Button text',
                icon_classes='glyphicon glyphicon-fire',
                url=reverse('some_url_name_no_pk_required'),
                condensed=False,
            ),
        ])
        return button_list
class toolkit.views.views.CCEModelFormSetView(**kwargs)

This view includes all the mixins required in all ModelFormSetViews.

class toolkit.views.views.CCEObjectRedirectView(**kwargs)

This view includes all the mixins required in all RedirectViews.

class toolkit.views.views.CCERedirectView(**kwargs)

This view includes all the mixins required in all RedirectViews.

class toolkit.views.views.CCESearchView(**kwargs)

ListView variant that filters the queryset on search parameters.

The field ‘search_form_class’ must be defined as a subclass of SearchForm in inheriting classes.

The field ‘allow_empty’ (inherited from MultipleObjectMixin) is ignored, since this view must allow an empty object_list.

Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class PollListView(CCESearchView):
    model = Poll
    paginate_by = 10
    page_title = "Browse Polls"
    sidebar_group = ['polls', ]
    search_form_class = PollSimpleSearchForm
    advanced_search_form_class = PollAdvancedSearchForm
    columns = [
        ('Name', 'name'),
        ('Active', 'active'),
    ]
    show_context_menu = True
Advanced Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class PollListView(CCESearchView):
    model = Poll
    paginate_by = 10
    template_name = "polls/list.html"
    ordering = ['-created_at']
    page_title = "Browse Polls"
    sidebar_group = ['polls', ]
    search_form_class = PollSimpleSearchForm
    advanced_search_form_class = PollAdvancedSearchForm
    # Column widths should add up to 12
    columns = [
        ('Name', 'name', 4),
        ('Active', 'active', 5),
    ]
    actions_column_width = 3
    show_context_menu = True
    show_add_button = True
    popover_rows = [
        ('Description', 'description'),
        ('Choices', lambda poll: some_function(poll)),
    ]

    def context_menu_items(self):
        items = super(PollListView, self).context_menu_items()
        items.append(
            # label, reversed url, icon class, sidebar_group
            (
                "Edit All Polls at Once",
                reverse('edit_all_polls'),
                "glyphicon glyphicon-pencil",
                "edit_all_polls",
            )
        )
        return items

    def render_buttons(self, user, obj, **kwargs):
        button_list = super(PollListView, self).render_buttons(user, obj, **kwargs)
        button_list.extend([
            self.render_button(
                url_name='edit_poll_permissions',
                pk=obj.pk,
                icon_classes='fa fa-lock',
            ),
            self.render_button(
                btn_class='warning',
                label='Button text',
                icon_classes='glyphicon glyphicon-fire',
                url=reverse('some_url_name_no_pk_required'),
                condensed=False,
            ),
        ])
        return button_list
get_context_data(**kwargs)

Puts things into the context that the template needs: - the message to display when there are no results in the list - the context menu template name (calculated from the model name) - the table of data from generate_list_view_table

get_queryset()

Filters the default queryset based on self.search_form.search.

Requires self.search_form to be set before this function is called, probably in self.get.

If self.search_form is invalid, returns an empty list.

class toolkit.views.views.CCETemplateView(**kwargs)

This view includes all the mixins required in all TemplateViews.

class toolkit.views.views.CCEUpdateView(**kwargs)

This view includes all the mixins required in all UpdateViews.

Usage:
1
2
3
4
5
6
class PollUpdateView(CCECreateView):
    model = Poll
    form_class = PollUpdateForm
    page_title = "Edit Poll"
    sidebar_group = ['polls', ]
    success_message = "Poll saved successfully."
Advanced Usage:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class PollUpdateView(CCECreateView):
    model = Poll
    form_class = PollUpdateForm
    template_name = "polls/edit.html"
    page_title = "Edit Poll"
    sidebar_group = ['polls', ]
    success_message = "Poll saved successfully."

    def context_menu_items(self):
        items = super(PollUpdateView, self).context_menu_items()
        items.append(
            # label, reversed url, icon class, sidebar_group
            (
                "Link to something else you want",
                reverse('link_to_something_else'),
                "glyphicon glyphicon-fire",
                "something_else",
            )
        )
        return items
class toolkit.views.views.CCEUpdateWithInlinesView(**kwargs)

This view includes all the mixins required in all UpdateWithInlinesViews.

class toolkit.views.views.ReportDownloadDetailView(**kwargs)

Variant of CCEDetailView that downloads the object as an xls or pdf report.

class toolkit.views.views.ReportDownloadSearchView(**kwargs)

Variant of CCESearchView that downloads the search results as an xls or pdf report.

Raises Http404 if the GET parameters do not form a valid search query. If no query string is specified, gives a report of all objects returned by get_queryset.

The following fields must be defined on inheriting classes:
  • model or queryset (per BaseListView)
  • search_form_class (per SearchView)
  • report_function (see ReportView)
class toolkit.views.mixins.AbstractedDetailMixin

A Django DetailView mixin used to generate a list of label-value pairs and pass it to the template

Note:Mixin will also set the default template_name of the view to generic_detail.html template
get_detail_fields()

Override this method to make the details shown dynamic.

get_details()

How self.fields should be formatted: - The first item in each tuple should be the label. - The second item should be EITHER a dotted path from this object to what goes on the page, OR a function that takes exactly one argument. - The third item is an optional extra parameter. - - If the thing passed is a related manager, this is an optional dotted path to apply to each object in the manager.

Example:

1
2
3
4
5
6
7
8
fields = [
    ('Username', 'user.username'),
    ('Passport file', 'passport'),
    ('Zip codes', 'address_set', 'zip_code'),
    ('Active', 'is_active'),
    ('Joined date', 'joined_date'),
    ('Type', lambda obj: type(obj)),
]
Returns:OrderedDict of {label: (value, param)} that gets dropped into the template.
class toolkit.views.mixins.AbstractedListMixin

Assumes that it’s mixed in with a ListView that has self.model.

generate_list_view_table(columns, data)

Generates a data structure for use in the generic list template. The “columns” parameter is a list of 2-tuples or 3-tuples or 4 tuples. These contain - a column title - EITHER a function that takes one parameter (an object from the list) and returns a cell of data OR a dot-separated string of attributes, and - an optional column width number that will go into a Bootstrap class. - dot-separated string of attributes with underscore replacing the dots to be used in queryset ordering

All of these values will be coerced to strings in the template. So the function can return an object, and its string representation will be used. The column width can be a string or an integer.

Example:
columns = [
(“Column title”, lambda obj: obj.method_name(CONSTANT)), (“Other title”, previously_defined_function, ‘3’), (“Third”, ‘dotted.attribute’, 2, ‘dotted_attribute’), ]

The “data” parameter should be an iterable. This method returns a data structure of the following form (using the above example as input):

[
[(“Column title”, ‘’, ‘’, ‘’), (“Other title”, ‘3’, ‘’), (“Third”, 2, ‘’, ‘dotted_attribute’)], [data[0].method_name(CONSTANT), previously_defined_function(data[0]), data[0].dotted.attribute], [data[1].method_name(CONSTANT), previously_defined_function(data[1]), data[1].dotted.attribute], # etc. ]
get_context_data(**kwargs)

Puts things into the context that the template needs: - the message to display when there are no results in the list - the context menu template name (calculated from the model name) - the table of data from generate_list_view_table

render_button(pk=None, btn_class='', url_name='', label='', icon_classes='', button_text='', url='', condensed=True)

Takes of boatload of parameters and returns the HTML for a nice Bootstrap button-link. If the URL lookup fails, no button is returned.

Must have EITHER pk and url_name OR url.

render_buttons(user, obj, view_perm_func=None, edit_perm_func=None, delete_perm_func=None)

This method provides default buttons for an object in a ListView: View, Edit and Delete. The default permission functions are can_view, can_update and can_delete. We can depend on all three of these permissions methods being there because of CCEAuditModel. Other permission functions can be passed, though this is unlikely to happen under the current structure. If a URL is not found, or if the user doesn’t have permission to do that thing, the button is not rendered.

class toolkit.views.mixins.AppendURLObjectsMixin
this mixin is used to get and append objects, who’s pks are passed in view
kwargs making the objects available to all the methods in your view as well your template.
To use this mixin, you need to set the append_objects property with a list
of tuples each containing 3 values

append_object format: (Model, context_variable_name, field_lookup) example 1: append_objects = [(Course, ‘course’, ‘course_pk’), (Student, ‘student’, ‘student_pk’)] in this example, the mixin will try to get the Course and Student objects based on course_pk and student_pk which are passed through the view url. This mixin assumes that the value being passed by field_lookup contains the pk of the object you’re trying to fetch. The fetched objects will be appended to context data with variables named after the second value in the triple (‘course’ or ‘student’)

example 2: append_objects = [(Course, ‘course’, ‘course_pk’), (Student, ‘student’, {‘student_id’: ‘student_pk’})] In this example, we pass a dict in the field_lookup parameter which represents a mapping of model field lookup method and values that will be passed in the url.

the mixin will raise 404 exception if any object is not found

class toolkit.views.mixins.ClassPermissionsMixin

Use this mixin when table-level cce_permissions are required; i.e. CreateView, etc.

This class should implement three methods:

_check_resource()
should verify that the resource we wish to protect (object, model, etc.) exists
_check_perms_keys()
should verify that the permission functions exist
_check_permissions()
should actually make the call to the defined cce_permissions
class toolkit.views.mixins.FileDownloadMixin

View mixin to make that view return a file from a model field on GET. Views using this mixin must implement the method get_file_field_to_download Note: This is for serving a file as a response and is no longer recommended

class toolkit.views.mixins.ObjectPermissionsMixin

Use this mixin when get_object() is called in your view; i.e. DetailView, UpdateView, etc.

This class should implement three methods:

_check_resource()
should verify that the resource we wish to protect (object, model, etc.) exists
_check_perms_keys()
should verify that the permission functions exist
_check_permissions()
should actually make the call to the defined cce_permissions
class toolkit.views.mixins.PermissionsRequiredMixin

Inspired by django-braces: https://github.com/brack3t/django-braces

Requires django-rulez https://github.com/chrisglass/django-rulez TODO: Does this actually require django-rulez anymore?

Parent class of view mixins which allow you to specify a list of rules for access to a resource (model or instance of a model, currently) via django-rulez by http verb. Each permission that is listed will be required (logical AND for multiple cce_permissions).

A 403 will be raised if any of the checks fails.

Simply create a dictionary with http verbs as keys, and each of their values should be a list of functions (as strings) in ‘function_name’ format. Each permission should be a function in the same class as the model or model instance defined on the view that inherits one of the children mixins.

Example Usage on an UpdateView subclass:

cce_permissions = {
“get”: [“add_object”] “post”: [“change_object”, “delete_object”] }
class toolkit.views.mixins.SuccessMessageMixin

Use when you’d like a success message added to your Create or Update response.

Assumptions:
  • Class has method form_valid()
Limitations:
  • Class cannot override form_valid()
  • Success message may only be one line.

Use when you’d like a success message added to your Delete response.

Assumptions:
  • Class has method delete()
Limitations:
  • Class cannot override delete()
  • Success message may only be one line.
class toolkit.views.mixins.ViewMetaMixin
Mixin will be used capture optional and required meta data about each view
that are then passed to the template