Skip to content

Commit

Permalink
Fixes jazzband#96: Improve string representation of sortedm2m relatio…
Browse files Browse the repository at this point in the history
…nships
  • Loading branch information
rohithasrk committed Mar 28, 2017
1 parent 7d0c3bb commit 3279680
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 9 deletions.
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ Specifies how the field is called in the intermediate database table by which
the relationship is ordered. You can change its name if you have a legacy
database that you need to integrate into your application.

``base_class``
~~~~~~~~~~~~~~

**Default:** ``None``

You can set the ``base_class``, which is the base class of the through model of
the sortedm2m relationship between models to an abstract base class containing
a ``__str__`` method to improve the string representations of sortedm2m
relationships.

Migrating a ``ManyToManyField`` to be a ``SortedManyToManyField``
=================================================================

Expand Down
7 changes: 6 additions & 1 deletion example/testapp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ def __unicode__(self):
return self.plate


class BaseCarThrough(object):
def __unicode__(self):
return unicode(self.car) + " in " + unicode(self.parkingarea)


class ParkingArea(models.Model):
name = models.CharField(max_length=50)
cars = SortedManyToManyField(Car)
cars = SortedManyToManyField(Car, base_class=BaseCarThrough)

def __unicode__(self):
return self.name
Expand Down
19 changes: 14 additions & 5 deletions sortedm2m/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,19 @@ class SortedManyToManyField(_ManyToManyField):
Accept a boolean ``sorted`` attribute which specifies if relation is
ordered or not. Default is set to ``True``. If ``sorted`` is set to
``False`` the field will behave exactly like django's ``ManyToManyField``.
Accept a class ``base_class`` attribute which specifies the base class of
the intermediate model. It allows to customize the intermediate model.
'''
def __init__(self, to, sorted=True, **kwargs):
def __init__(self, to, sorted=True, base_class=None, **kwargs):
self.sorted = sorted
self.sort_value_field_name = kwargs.pop(
'sort_value_field_name',
SORT_VALUE_FIELD_NAME)

# Base class of through model
self.base_class = base_class

super(SortedManyToManyField, self).__init__(to, **kwargs)
if self.sorted:
self.help_text = kwargs.get('help_text', None)
Expand Down Expand Up @@ -376,16 +382,19 @@ def get_intermediate_model_to_field(self, klass):

def create_intermediate_model_from_attrs(self, klass, attrs):
name = self.get_intermediate_model_name(klass)
return type(str(name), (models.Model,), attrs)
base_classes = (self.base_class, models.Model) if self.base_class else (models.Model,)

return type(str(name), base_classes, attrs)

def create_intermediate_model(self, klass):
# Construct and return the new class.
from_field_name, from_field = self.get_intermediate_model_from_field(klass)
to_field_name, to_field = self.get_intermediate_model_to_field(klass)
sort_value_field_name, sort_value_field = self.get_intermediate_model_sort_value_field(klass)

meta = self.get_intermediate_model_meta_class(
klass, from_field_name, to_field_name, sort_value_field_name)
meta = self.get_intermediate_model_meta_class(klass,
from_field_name,
to_field_name,
sort_value_field_name)

attrs = {
'Meta': meta,
Expand Down
11 changes: 9 additions & 2 deletions sortedm2m_tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
from sortedm2m.fields import SortedManyToManyField


class BaseBookThrough(object):

def __str__(self):
return "Relationship to {0}".format(self.book.name)


class Shelf(models.Model):
books = SortedManyToManyField('Book', related_name='shelves')
books = SortedManyToManyField('Book', related_name='shelves', base_class=BaseBookThrough)


class Book(models.Model):
Expand All @@ -17,7 +23,8 @@ def __unicode__(self):
class DoItYourselfShelf(models.Model):
books = SortedManyToManyField(Book,
sort_value_field_name='diy_sort_number',
related_name='diy_shelves')
related_name='diy_shelves',
base_class=BaseBookThrough)


class Store(models.Model):
Expand Down
10 changes: 9 additions & 1 deletion sortedm2m_tests/test_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from sortedm2m.compat import get_field

from .models import (
Book, Shelf, DoItYourselfShelf, Store, MessyStore, SelfReference)
Book, Shelf, DoItYourselfShelf, Store, MessyStore, SelfReference, BaseBookThrough)


str_ = six.text_type
Expand Down Expand Up @@ -183,6 +183,14 @@ def get_ids(queryset):
return [obj.id for obj in queryset]
self.assertEqual(get_ids(shelf.books.all()), get_ids(books))

def test_base_class_str(self):
shelf = self.model.objects.create()
shelf.books.add(self.books[0])
through_model = shelf.books.through
instance = through_model.objects.all()[0]
self.assertEqual(str(instance), "Relationship to {0}".format(instance.book.name))


class TestStringReference(TestSortedManyToManyField):
'''
Test the same things as ``TestSortedManyToManyField`` but using a model
Expand Down

0 comments on commit 3279680

Please sign in to comment.