aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/relations.py
diff options
context:
space:
mode:
authorTom Christie2014-09-18 14:23:00 +0100
committerTom Christie2014-09-18 14:23:00 +0100
commit9fdb2280d11db126771686d626aa8a0247b8a46c (patch)
tree4dd3e7d39e2bff75f38ed0a748befa478ff889a1 /rest_framework/relations.py
parent3bc628edc01a6bd4feeceaefa45168549b79a31a (diff)
downloaddjango-rest-framework-9fdb2280d11db126771686d626aa8a0247b8a46c.tar.bz2
First pass on ManyRelation
Diffstat (limited to 'rest_framework/relations.py')
-rw-r--r--rest_framework/relations.py42
1 files changed, 41 insertions, 1 deletions
diff --git a/rest_framework/relations.py b/rest_framework/relations.py
index 9f44ab63..474d3e75 100644
--- a/rest_framework/relations.py
+++ b/rest_framework/relations.py
@@ -10,7 +10,6 @@ from django.utils.translation import ugettext_lazy as _
class RelatedField(Field):
def __init__(self, **kwargs):
self.queryset = kwargs.pop('queryset', None)
- self.many = kwargs.pop('many', False)
assert self.queryset is not None or kwargs.get('read_only', None), (
'Relational field must provide a `queryset` argument, '
'or set read_only=`True`.'
@@ -21,6 +20,13 @@ class RelatedField(Field):
)
super(RelatedField, self).__init__(**kwargs)
+ def __new__(cls, *args, **kwargs):
+ # We override this method in order to automagically create
+ # `ManyRelation` classes instead when `many=True` is set.
+ if kwargs.pop('many', False):
+ return ManyRelation(child_relation=cls(*args, **kwargs))
+ return super(RelatedField, cls).__new__(cls, *args, **kwargs)
+
def get_queryset(self):
queryset = self.queryset
if isinstance(queryset, QuerySet):
@@ -216,3 +222,37 @@ class SlugRelatedField(RelatedField):
def to_representation(self, obj):
return getattr(obj, self.slug_field)
+
+
+class ManyRelation(Field):
+ """
+ Relationships with `many=True` transparently get coerced into instead being
+ a ManyRelation with a child relationship.
+
+ The `ManyRelation` class is responsible for handling iterating through
+ the values and passing each one to the child relationship.
+
+ You shouldn't need to be using this class directly yourself.
+ """
+
+ def __init__(self, child_relation=None, *args, **kwargs):
+ self.child_relation = child_relation
+ assert child_relation is not None, '`child_relation` is a required argument.'
+ super(ManyRelation, self).__init__(*args, **kwargs)
+
+ def bind(self, field_name, parent, root):
+ # ManyRelation needs to provide the current context to the child relation.
+ super(ManyRelation, self).bind(field_name, parent, root)
+ self.child_relation.bind(field_name, parent, root)
+
+ def to_internal_value(self, data):
+ return [
+ self.child_relation.to_internal_value(item)
+ for item in data
+ ]
+
+ def to_representation(self, obj):
+ return [
+ self.child_relation.to_representation(value)
+ for value in obj.all()
+ ]