Live demo

ID Blog Headline Body Text Publication Date Modified Date Age Interaction Comments Pingbacks


Description

datatableview.helpers is a module decidated to functions that can be supplied directly as column callback functions. Some of them are easy to use at runtime in your own callbacks, making some work easier for you, but the majority aim to solve common problems with as little fuss as possible.



link_to_model

Columns from demo: ID (no args), Blog (using key arg)

Shortcut for rendering a simple <a href="{instance.get_absolute_url}">{text}</a>, where instance is the row's object and text is whatever field you've set the column to represent.

This is primarily useful for converting the main "name" column (whatever that might be in your specific situation) for the row into a clickable link for that item's detail view, but it can be used to link to related models too via a key argument.

datatable_options = {
    'columns': [
        # Standard use, no need to actually call the helper
        ("Headline", 'headline', helpers.link_to_model),
        # Target a related field; helper returns a new customized helper
        ("Blog", 'blog__name', helpers.link_to_model(key=lambda instance: instance.blog)),
    ],
}

Note how the related case needs to give the key argument. This follows the idiom in Python for sorting, comparing, and mapping functions, described here. A "key function" is just a simple mapper: it takes a value in, and returns another. link_to_model uses this argument to let you accept the row's instance and return the foreign key you intend to link. Without the key function, you would end up with a link to the row's instance with the text of the blog name, which wouldn't be intuitive.

You can use this helper in your own custom callbacks if you want to avoid writing an HTML anchor tag in your Python code:

def get_column_Blog_data(self, instance, *args, **kwargs):
    # Simplest use, "text" will be the unicode of instance.blog
    return helpers.link_to_model(instance.blog)
    
    # Specify a custom text
    return helpers.link_to_model(instance.blog, text=instance.blog.name)


make_boolean_checkmark

Columns from demo: Interaction (no args)

Shortcut for coercing the column's data into a boolean True or False, but rendering a (&#10004;) or (&#10008;)

Any value can be used with this helper, as long as it can be assessed in an if value: statement. The helper can optionally be called with true_value and false_value arguments, which default to the entity strings shown above.

datatable_options = {
    'columns': [
        # Standard use, no need to actually call the helper
        ("Comments", 'n_comments', helpers.make_boolean_checkmark),
        # Specify custom string
        ("Blog", 'blog__name', helpers.make_boolean_checkmark(false_value="")),
    ],
}

You can use this helper in your own custom callbacks if there is some kind of value calculation that needs to be done before the helper should execute:

def get_column_Interaction_data(self, instance, *args, **kwargs):
    # Simplest use; grab the 'default_value' argument that DatatableView found for us
    return helpers.make_boolean_checkmark(kwargs['default_value'])
    
    # Specify custom true and/or false strings
    value = instance.get_some_value()
    return helpers.make_boolean_checkmark(value, true_value="Yes", false_value="No")


format_date

Columns from demo: Publication Date

Shortcut for supplying a standard strftime format to be applied to date and datetime objects.

This helper must be called inline with the column definition, in order to provide the format string. It will returned a stand-in callback to defer the formating until the callback is needed.

As of Django 1.5, support for localtime is available by passing in an extra keyword argument localize=True. Doing this on Django version 1.4 or earlier will raise an exception with a message detailing this fact.

datatable_options = {
    'columns': [
        # Standard use; must call the helper once to give it the format string
        ("Publication Date", 'pub_date', helpers.format_date("%m/%d/%Y"),
        # If Django 1.5 or later, you can ask for the localtime version
        ("Modified Date", 'mode_date', helpers.format_date("%Y-%m-%d", localize=True),
    ],
}

Using this helper in custom callbacks provides no tangible benefit over formatting the date or datetime instance yourself, but can still be done:

def get_column_Publication_Date_data(self, instance, *args, **kwargs):
    # Generate the real callback helper, then call it
    callback = helpers.format_date('%m/%d/%Y', localize=True)
    return callback(kwargs['default_value'])
    
    # This is equivalent real Python code, and better for readability
    from django.utils.timezone import localtime
    return localtime(kwargs['default_value']).strftime('%m/%d/%Y')


format

Columns from demo: Comments, Pingbacks

Shortcut for supplying a new-style format string (the "{}".format() variety) to a column value.

This helper must be called inline with the column definition, in order to provide the format string. It will returned a stand-in callback to defer the formating until the callback is needed.

This is a useful helper for adding things like locale digit separators to large numbers, etc. As a special case, if the column value is the wrong data type for the format string, you can provide a cast keyword argument to the helper to specify a type object that the value will be converted to. See the examples below.

datatable_options = {
    'columns': [
        # Standard use; must call the helper once to give it the format string
        ("Comments", 'n_comments', helpers.format("{:,}"),
        # If type cast is required first, you can provide that type
        ("2-places float", 'string_data', helpers.format("{:.2f}", cast=float),
    ],
}

Using this helper in custom callbacks provides no tangible benefit over formatting the string yourself, but can still be done:

def get_column_Comments_data(self, instance, *args, **kwargs):
    # Generate the real callback helper, then call it
    callback = helpers.format('{:,}')
    return callback(kwargs['default_value'])
    
    # This is equivalent real Python code, and better for readability
    return kwargs['default_value'].format('{:,}')


through_filter

Columns from demo: Age

Shortcut for letting a external mapping function accept the extra *args and **kwargs that DatatableView sends.

This helper must be called inline with the column definition, in order to provide the target function that you'd like to use. It will returned a stand-in callback that will avoid sending unwanted arguments to the target function.

This is a useful helper for applying the default template language filter functions to your column value, but it can work for any 1-argument or 2-argument function, where the first argument is just the value to process, and the second argument can be specified in advance. The template filters are great examples of this, where you can provide a number of characters to truncate. Secondary arguments must be specified in advance, and will always take the name arg, for simplicity, but will always be sent to the target function as a positional argument just after the main value.

from django.template.defaultfilters import timesince, truncatewords
datatable_options = {
    'columns': [
        # Standard use; must call the helper once to give it the target function
        ("Age", 'pub_date', helpers.through_filter(timesince),
        # Optionally specify a 'arg' that will be sent.
        # This target function will be called like: truncatewords(body_text, 10)
        ("Body Text", 'body_text', helpers.through_filter(truncatewords, arg=10),
    ],
}

If additional arguments or keywords need to be sent to the target function, try wrapping it in a functools.partial first. helpers.through_filter will continue guarding the target function from unwanted extra arguments:

from functools import partial
datatable_options = {
    'columns': [
        # Standard use; must call the helper once to give it the target function
        ("Age", 'pub_date', helpers.through_filter(partial(some_function, custom_arg=True)),
    ],
}

Using this helper in custom callbacks provides no tangible benefit over using the target function directly, but can still be done:

def get_column_Body_Text_data(self, instance, *args, **kwargs):
    # Generate the real callback helper, then call it
    callback = helpers.through_filter(truncatewords, arg=10)
    return callback(kwargs['default_value'])
    
    # This is equivalent real Python code, and better for readability
    return truncatewords(kwargs['default_value'], 10)


itemgetter

Columns from demo: Body Text (as a slice)

Shortcut for supplying an operator.itemgetter-type callback, but which accepts the additional arguments that DatatableView provides by default.

This helper's usefulness is supplanted by the helpers.through_fitler callback, which allows you to use operator.itemgetter directly.

This helper must be called inline with the column definition, in order to provide the item to get from the column value. It will returned a stand-in callback to defer the item-getting until the callback is needed.

helpers.itemgetter can be used to fetch a specific item or slice from a value. It includes the option to specify an ellipsis keyword argument, which, if provided along with a slice against a string, will be appended to a sliced string.

import operator
datatable_options = {
    'columns': [
        # Standard use; must call the helper once to give it the item to access
        ("Body Text", 'body_text', helpers.itemgetter(slice(0, 30)),
        # Better perhaps to use the through_filter() helper
        ("Body Text", 'body_text', helpers.through_filter(operator.itemgetter(slice(0, 30)),

        # Append an ellipsis
        ("Body Text", 'body_text', helpers.itemgetter(slice(0, 30), ellipsis="..."),
        # Again, better perhaps to use the through_filter() helper with the truncatechars filter
        ("Body Text", 'body_text', helpers.through_filter(truncatechars(30)),
    ],
}

Using this helper in custom callbacks provides no tangible benefit over getting an item or slice from the target value yourself, but can still be done:

def get_column_Body_Text_data(self, instance, *args, **kwargs):
    # Generate the real callback helper, then call it
    callback = helpers.itemgetter(slice(0, 30))
    return callback(kwargs['default_value'])
    
    # This is equivalent real Python code, and better for readability
    return kwargs['default_value'][:30]


attrgetter

No columns from demo, see examples below

Shortcut for supplying an operator.attrgetter-type callback, but which accepts the additional arguments that DatatableView provides by default.

This helper's usefulness is supplanted by the helpers.through_fitler callback, which allows you to use operator.attrgetter directly.

This helper must be called inline with the column definition, in order to provide the attribute to read from the column value. It will returned a stand-in callback to defer the attribte lookup until the callback is needed.

helpers.attrgetter can be used to read an attribute from the target value. The utility of this is mostly in the ability to specify your database fields for the column but still use a model method to actually supply the data in question. For example, if an address is to be displayed in a table column, supplying the model's get_address method as the "field" for the column would lose you the database field list, so database-level searching and sorting would not be possible. Instead, you can supply your field list and then have the presentational callback deferred to a model method:

import operator
datatable_options = {
    'columns': [
        # Standard use; must call the helper once to give it the attribute to read
        ("Address", ['street', 'city', 'state', 'zipcode'], helpers.attrgetter('get_address'),
        # Better perhaps to use the through_filter() helper
        ("Address", ['street', 'city', 'state', 'zipcode'],
                    helpers.through_filter(operator.attrgetter('get_address')),
    ],
}

Using this helper in custom callbacks provides no tangible benefit over getting the attribute from the target value yourself, but can still be done:

def get_column_Address_data(self, instance, *args, **kwargs):
    # Generate the real callback helper, then call it
    callback = helpers.attrgetter('get_address')
    return callback(instance)
    
    # This is equivalent real Python code, and better for readability
    return instance.get_address()


make_xeditable

Columns from demo: Headline

Shortcut for converting the value of the column into an interactive x-editable form.

This helper will generally require that you inherit your view from datatableview.views.XEditableDatatableView instead of just the normal DatatableView, so that the view can serve as the ajax endpoint for the updates that get made to the data. See x-editable columns for a full reference of how to get that view set up so that this helper can do its job.

This helper allows you to specify the HTML data-* API attributes expected by the x-editable javascript. By default you can get away with not sending any keyword arguments to the helper, and it will choose reasonable defaults for field types, etc.

The full list of default keyword arguments are as follows:

  • type: Defaults to the basic type of the Django field (e.g., "text", "number", "datetime")
  • title: Defaults to empty
  • placeholder: Defaults to the value of title if not provided
  • url: Defaults to request.path, so that the XEditableDatatableView can service the ajax updates.
  • source: Defaults to request.path, so that the XEditableDatatableView can service ajax queries for the choices data of the field.
  • pk: Defaults to the pk of the supplied instance. The instance should be the first argument to the final call to make_xeditable for this default to work as intended.

Extra data-* API attributes can be given by specifying what they are in the keyword argument extra_attrs:

helpers.make_xeditable(extra_attrs=['data_format'], data_format="yyyy-mm-dd")

Arguments given in this way will be converted to use "-" instead of "_", which simplifies how you give them as keyword arguments.

Calls to make_xeditable that don't include an "instance" as its first positional argument will create a functools.partial around the call and return it so that new arguments can be given. This lets you build up a set of custom attributes if you want to create certain common x-editable styles. See the examples below.

Following are some examples of how the helper can be used:

from datatableview.views import XEditableDatatableView
from datatableview import helpers
from .models import Entry

# See third and fourth example columns just below
xeditable_date = helpers.make_xeditable(type="date")

class EditableDatatableView(XEditableDatatableView):
    model = Entry
    datatable_options = {
        'columns': [
            # Standard use; supply callback directly for all default options
            ("Headline", 'headline', helpers.make_xeditable),

            # Customize options described above via kwargs
            ("Headline", 'headline', helpers.make_xeditable(type="textarea")),

            # Supply a previously created "partial" helper; calls chain until there is an instance
            ("Publication Date", 'pub_date', xeditable_date),
            ("Publication Date", 'pub_date', xeditable_date(placeholder="Enter a valid date")),
        ],
    }

If you're using a custom callback method, you can still ask make_xeditable to create a <a> tag to use in your own return value. Using this direct strategy, you can supply the instance at the same time as the other keyword arguments to avoid having to call the helper more than once for the final effect.

The only catch to using the helper manually is that you should take care to forward the **kwargs from your callback to it. Chances are good that some default value that the helper wants to fill out may need information that XEditableDatatableView is trying to supply to it.

def get_column_Headline_data(self, instance, *args, **kwargs):
    # Simplest use; direct return of the x-editable <a> HTML
    return helpers.make_xeditabe(instance, **kwargs)

    # You can also supply additional arguments at the same time
    return helpers.make_xeditabe(instance, type="textarea", **kwargs)

    # You can still chain calls together and reuse previously generated "partials"
    xeditable_date = helpers.make_xeditabe(type="date")
    return xeditable_date(instance, **kwargs)
    return xeditable_date(instance, placeholder="Enter a valid date", **kwargs)


Implementation in code

        
    class HelpersReferenceDatatableView(XEditableDatatableView):
        model = Entry
        datatable_options = {
            'columns': [
                ("ID", 'id', helpers.link_to_model),
                ("Blog", 'blog__name', helpers.link_to_model(key=lambda instance: instance.blog)),
                ("Headline", 'headline', helpers.make_xeditable),
                ("Body Text", 'body_text', helpers.itemgetter(slice(0, 30))),
                ("Publication Date", 'pub_date', helpers.format_date('%A, %b %d, %Y')),
                ("Modified Date", 'mod_date'),
                ("Age", 'pub_date', helpers.through_filter(timesince)),
                ("Interaction", 'get_interaction_total', helpers.make_boolean_checkmark),
                ("Comments", 'n_comments', helpers.format("{0:,}")),
                ("Pingbacks", 'n_pingbacks', helpers.format("{0:,}")),
            ],
        }