Skip to content

Instantly share code, notes, and snippets.

@johanneskoch
Created December 2, 2013 12:39
Show Gist options
  • Select an option

  • Save johanneskoch/7748883 to your computer and use it in GitHub Desktop.

Select an option

Save johanneskoch/7748883 to your computer and use it in GitHub Desktop.
Mixins that can be used to easily create nested Tastypie resources. If you for example have a child resource accessible at /api/child-resources/ related to a parent resource accessible at /api/parent-resources/, these would create a URL structure like /api/parent-resources/{detail_uri_name}/child-resources/ that would allow you to access the chi…
from django.conf.urls.defaults import url
from django.db.models.sql.constants import LOOKUP_SEP
from tastypie.utils import trailing_slash
class ParentResourceMixin(object):
""" NOTE: Needs to be filterable on detail_uri_name if not pk """
def prepend_urls(self):
urls = []
for child_resource in self._meta.child_resources:
child = child_resource()
related_name = child.reverse_field_lookup(self)
if related_name is None:
continue
related_lookup = [related_name]
if self._meta.detail_uri_name != 'pk':
related_lookup.append(self._meta.detail_uri_name)
related_lookup = LOOKUP_SEP.join(related_lookup)
urls += [
url(
r'^%s/(?P<%s>\w[\w/-]*)/(?P<resource_name>%s)%s$' % (
self._meta.resource_name,
related_lookup,
child._meta.resource_name,
trailing_slash(),
),
child.wrap_view('nested_dispatch_list'),
{'parent_resource': self, 'parent_lookup': related_lookup},
'api_nested_dispatch_list',
),
url(
r'^%s/(?P<%s>\w[\w/-]*)/(?P<resource_name>%s)/(?P<%s>\w[\w/-]*)%s$' % (
self._meta.resource_name,
related_lookup,
child._meta.resource_name,
child._meta.detail_uri_name,
trailing_slash(),
),
child.wrap_view('nested_dispatch_detail'),
{'parent_resource': self, 'parent_lookup': related_lookup},
'api_nested_dispatch_detail',
),
]
return urls
class ChildResourceMixin(object):
""" NOTE: Needs to be filterable on all parent resources """
def reverse_field_lookup(self, resource_instance):
for field_name, field_object in self.fields.items():
if not getattr(field_object, 'is_related', False):
continue
if isinstance(resource_instance, field_object.to_class):
return field_name
return None
def get_parent_obj(self, bundle):
lookup_key = bundle.request.parent_lookup_key
lookup_value = bundle.request.parent_lookup_value
return bundle.request.parent_resource.obj_get(
bundle, **{lookup_key: lookup_value})
def nested_dispatch_list(self, request, **kwargs):
return self.nested_dispatch('list', request, **kwargs)
def nested_dispatch_detail(self, request, **kwargs):
return self.nested_dispatch('detail', request, **kwargs)
def nested_dispatch(self, request_type, request, **kwargs):
lookup = kwargs.pop('parent_lookup')
try:
lookup_key = lookup.split(LOOKUP_SEP)[1]
except IndexError:
lookup_key = 'pk'
request.is_nested = True
request.parent_resource = kwargs.pop('parent_resource')
request.parent_lookup_key = lookup_key
request.parent_lookup_value = kwargs[lookup]
return getattr(self, 'dispatch_%s' % request_type)(request, **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment