diff --git a/easy/__init__.py b/easy/__init__.py
index d01c375..49bc271 100644
--- a/easy/__init__.py
+++ b/easy/__init__.py
@@ -4,7 +4,7 @@
)
from .admin import * # noqa
from .admin.field import ( # noqa
- BaseAdminField, BooleanAdminField, ExternalLinkAdminField, ForeignKeyAdminField, ImageAdminField,
+ BaseAdminField, BooleanAdminField, ExternalLinkAdminField, ForeignKeyAdminField, ManyToManyAdminField, ImageAdminField,
LinkChangeListAdminField, SimpleAdminField, TemplateAdminField, ModelImageField, FilterAdminField,
CacheAdminField, FormatAdminField
)
diff --git a/easy/admin/field.py b/easy/admin/field.py
index f04a251..209dd30 100644
--- a/easy/admin/field.py
+++ b/easy/admin/field.py
@@ -46,6 +46,9 @@ def __init__(self, attr, short_description=None, admin_order_field=None, allow_t
super(SimpleAdminField, self).__init__(short_description, admin_order_field, allow_tags)
+ def __name__(self):
+ return 'SimpleAdminField'
+
def render(self, obj):
return helper.call_or_get(obj, self.attr, self.default)
@@ -85,6 +88,39 @@ def render(self, obj):
return self.default
+class ManyToManyAdminField(SimpleAdminField):
+ """Renders a ManyToManyField as links."""
+
+ def __init__(self, attr, display=None, short_description=None, admin_order_field=None, default=None):
+ self.display = display
+ super(ManyToManyAdminField, self).__init__(attr, short_description, admin_order_field, True, default)
+
+ def __name__(self):
+ return 'ManyToManyAdminField'
+
+ def render(self, obj):
+ ref = getattr(obj, self.attr, None)
+ display = None
+ if self.display:
+ display = helper.call_or_get(obj, self.display, self.default)
+
+ list_str = display
+ if hasattr(ref, 'get_queryset'):
+ list_str = '
'
+ objects = ref.get_queryset()
+ for obj in objects:
+ list_str += '- %s
' % (
+ reverse(
+ admin_urlname(obj._meta, 'change'),
+ args=(obj.pk,)
+ ),
+ conditional_escape(display or obj)
+ )
+ list_str += '
'
+
+ return list_str
+
+
class LinkChangeListAdminField(BaseAdminField):
def __init__(self, app, model, attr, params=None, params_static=None, short_description=None, admin_order_field=None):
@@ -203,7 +239,7 @@ def render(self, obj):
class CacheAdminField(SimpleAdminField):
- def __init__(self, attr, django_filter, load=None, extra=None, short_description=None,
+ def __init__(self, attr, django_filter, load=None, extra=None, short_description=None,
admin_order_field=None, allow_tags=False, default=None):
self.filter = django_filter
self.load = load
diff --git a/easy/tests.py b/easy/tests.py
index c64afac..9505ccb 100644
--- a/easy/tests.py
+++ b/easy/tests.py
@@ -18,7 +18,7 @@
import easy
from easy.helper import Nothing
from test_app.admin import PollAdmin
-from test_app.models import Question, Poll
+from test_app.models import Question, Poll, PollGroup
class TestSimpleAdminField(test.TestCase):
@@ -126,6 +126,57 @@ def test_foreignkey_display_sub_property(self):
self.assertTrue(custom_field.allow_tags)
+class TestManyToManyAdminField(test.TestCase):
+ def test_manytomany(self):
+ poll_group = mommy.make(
+ PollGroup,
+ name='Test Poll Group'
+ )
+
+ poll_one = mommy.make(Poll, name='Test Poll #1')
+ poll_two = mommy.make(Poll, name='Test Poll #2')
+ poll_group.polls.add(poll_one)
+ poll_group.polls.add(poll_two)
+
+ custom_field = easy.ManyToManyAdminField('polls')
+ ret = custom_field(poll_group)
+ if django.VERSION < (1, 9):
+ expected = u'' % (poll_two.id, )
+ elif django.VERSION < (2, 0):
+ expected = u'' % (poll_two.id, )
+ else:
+ expected = u'' % (poll_two.id, )
+
+ self.assertEqual(expected, ret)
+ self.assertTrue(custom_field.allow_tags)
+
+ def test_manytomany_display(self):
+ poll_group = mommy.make(
+ PollGroup,
+ name='Test Poll Group'
+ )
+
+ poll_one = mommy.make(Poll, name='Test Poll #1')
+ poll_two = mommy.make(Poll, name='Test Poll #2')
+ poll_group.polls.add(poll_one)
+ poll_group.polls.add(poll_two)
+
+ custom_field = easy.ManyToManyAdminField('polls', 'name')
+ ret = custom_field(poll_group)
+ if django.VERSION < (1, 9):
+ expected = u'- %s
' % (poll_one.id, poll_group.name, )
+ expected += u'- %s
' % (poll_two.id, poll_group.name, )
+ else:
+ expected = u'- %s
' % (poll_one.id, poll_group.name, )
+ expected += u'- %s
' % (poll_two.id, poll_group.name, )
+
+ self.assertEqual(expected, ret)
+ self.assertTrue(custom_field.allow_tags)
+
+
class TestTemplateAdminField(test.TestCase):
def test_template(self):
diff --git a/test_app/models.py b/test_app/models.py
index 185301f..c24c429 100644
--- a/test_app/models.py
+++ b/test_app/models.py
@@ -6,6 +6,13 @@ class Poll(models.Model):
name = models.CharField(max_length=200)
+class PollGroup(models.Model):
+ """Add this model to test the ManyToManyAdminField."""
+
+ name = models.CharField(max_length=200)
+ polls = models.ManyToManyField(Poll, related_name='poll_groups')
+
+
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')