Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Approved patches for fixing callable attributes on ToOneField and ToM…

…anyField. Thanks Donald Stufft and Valdimir Volodin for the fixes, and pennersr and sgarcez, for reports.

Closes #347
Closes #355
Closes #554
Closes #608
Closes #609
  • Loading branch information...
commit 94791908c29fe46023e1e4302624b4d56a0372fb 1 parent c38a667
@issackelly issackelly authored
View
2  AUTHORS
@@ -61,6 +61,8 @@ Contributors:
* Andrey Voronov (eyvoro) for fixing a typo in the AUTHORS file.
* D.B. Tsai (dbtsai) for a fix relating to ``detail_uri_kwargs``.
* maraujop for a patch adding to ``X-HTTP-Method-Override`` support.
+* Donald Stufft (dstufft) for patching ToOneField callable attributes
+* Vladimir Volodin (vvolodin) for patching ToManyField callable attributes
Thanks to Tav for providing validate_jsonp.py, placed in public domain.
View
29 tastypie/fields.py
@@ -619,21 +619,26 @@ def __init__(self, to, attribute, related_name=None, default=NOT_PROVIDED,
self.fk_resource = None
def dehydrate(self, bundle):
- attrs = self.attribute.split('__')
- foreign_obj = bundle.obj
+ foreign_obj = None
- for attr in attrs:
- previous_obj = foreign_obj
- try:
- foreign_obj = getattr(foreign_obj, attr, None)
- except ObjectDoesNotExist:
- foreign_obj = None
+ if isinstance(self.attribute, basestring):
+ attrs = self.attribute.split('__')
+ foreign_obj = bundle.obj
+
+ for attr in attrs:
+ previous_obj = foreign_obj
+ try:
+ foreign_obj = getattr(foreign_obj, attr, None)
+ except ObjectDoesNotExist:
+ foreign_obj = None
+ elif callable(self.attribute):
+ foreign_obj = self.attribute(bundle)
- if not foreign_obj:
- if not self.null:
- raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
+ if not foreign_obj:
+ if not self.null:
+ raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
- return None
+ return None
self.fk_resource = self.get_related_resource(foreign_obj)
fk_bundle = Bundle(obj=foreign_obj, request=bundle.request)
View
10 tastypie/resources.py
@@ -2067,7 +2067,15 @@ def save_m2m(self, bundle):
continue
# Get the manager.
- related_mngr = getattr(bundle.obj, field_object.attribute)
+ related_mngr = None
+
+ if isinstance(field_object.attribute, basestring):
+ related_mngr = getattr(bundle.obj, field_object.attribute)
+ elif callable(field_object.attribute):
+ related_mngr = field_object.attribute(bundle)
+
+ if not related_mngr:
+ continue
if hasattr(related_mngr, 'clear'):
# Clear it out, just to be safe.
View
10 tests/core/tests/fields.py
@@ -656,6 +656,16 @@ def test_dehydrate(self):
self.assertEqual(user_bundle.data['username'], u'johndoe')
self.assertEqual(user_bundle.data['email'], u'john@doe.com')
+ def test_dehydrate_with_callable(self):
+ note = Note.objects.get(pk=1)
+ bundle = Bundle(obj=note)
+
+ field_1 = ToOneField(UserResource, lambda bundle: User.objects.get(pk=1))
+ self.assertEqual(field_1.dehydrate(bundle), '/api/v1/users/1/')
+
+ field_2 = ToManyField(UserResource, lambda bundle: User.objects.filter(pk=1))
+ self.assertEqual(field_2.dehydrate(bundle), ['/api/v1/users/1/'])
+
def test_hydrate(self):
note = Note()
bundle = Bundle(obj=note)
Please sign in to comment.
Something went wrong with that request. Please try again.