django_tables2.columns.manytomanycolumn — django-tables2 1.14.1 documentation

# Source code for django_tables2.columns.manytomanycolumn

    # coding: utf-8
    from __future__ import absolute_import, unicode_literals

    from django.db import models
    from django.utils.encoding import force_text
    from django.utils.html import conditional_escape, mark_safe

    from django_tables2.templatetags.django_tables2 import title

    from .base import Column, library

    @library.register
    class ManyToManyColumn(Column):
        '''
        Display the list of objects from a `ManyRelatedManager`

        Ordering is disabled for this column.

        Arguments:
            transform: callable to transform each item to text, it gets an item as argument
                and must return a string-like representation of the item.
                By default, it calls `~django.utils.force_text` on each item.
            filter: callable to filter, limit or order the QuerySet, it gets the
                `ManyRelatedManager` as first argument and must return.
                By default, it returns `all()``
            separator: separator string to join the items with. default: ', '

        For example, when displaying a list of friends with their full name::

            # models.py
            class Person(models.Model):
                first_name = models.CharField(max_length=200)
                last_name = models.CharField(max_length=200)
                friends = models.ManyToManyField(Person)

                @property
                def name(self):
                    return '{} {}'.format(self.first_name, self.last_name)

            # tables.py
            class PersonTable(tables.Table):
                name = tables.Column(order_by=('last_name', 'first_name'))
                friends = tables.ManyToManyColumn(transform=lamda user: u.name)

        '''
        def __init__(self, transform=None, filter=None, separator=', ', *args, **kwargs):
            if transform is not None:
                self.transform = transform
            if filter is not None:
                self.filter = filter
            self.separator = separator

            kwargs.setdefault('orderable', False)

            super(ManyToManyColumn, self).__init__(*args, **kwargs)

        def transform(self, obj):
            '''
            Transform is applied to each item of the list of objects from the ManyToMany relation.
            '''
            return force_text(obj)

        def filter(self, qs):
            '''
            Filter is called on the ManyRelatedManager to allow ordering, filtering or limiting
            on the set of related objects.
            '''
            return qs.all()

        def render(self, value):
            # if value is None or not value.exists():
            if not value.exists():
                return '-'

            return mark_safe(
                conditional_escape(self.separator).join(
                    map(conditional_escape, map(self.transform, self.filter(value)))
                )
            )

        @classmethod
        def from_field(cls, field):
            if isinstance(field, models.ManyToManyField):
                return cls(verbose_name=title(field.verbose_name))