diff --git a/ietf/api/__init__.py b/ietf/api/__init__.py index 958a14ff1..229f1633d 100644 --- a/ietf/api/__init__.py +++ b/ietf/api/__init__.py @@ -4,9 +4,11 @@ import datetime from django.conf import settings from django.http import HttpResponse +from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.utils.encoding import force_text +import tastypie from tastypie.api import Api from tastypie.bundle import Bundle from tastypie.serializers import Serializer as BaseSerializer @@ -172,5 +174,42 @@ class TimedeltaField(ApiField): raise ApiFieldError("Datetime provided to '%s' field must be a string: %s" % (self.instance_name, value)) return value - - + +class ToOneField(tastypie.fields.ToOneField): + "Subclass of tastypie.fields.ToOneField which adds caching in the dehydrate method." + + def dehydrate(self, bundle, for_list=True): + foreign_obj = None + + if callable(self.attribute): + previous_obj = bundle.obj + foreign_obj = self.attribute(bundle) + elif isinstance(self.attribute, six.string_types): + foreign_obj = bundle.obj + + for attr in self._attrs: + previous_obj = foreign_obj + try: + foreign_obj = getattr(foreign_obj, attr, None) + except ObjectDoesNotExist: + foreign_obj = None + + if not foreign_obj: + if not self.null: + if callable(self.attribute): + raise ApiFieldError("The related resource for resource %s could not be found." % (previous_obj)) + else: + raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr)) + return None + + fk_resource = self.get_related_resource(foreign_obj) + + # Up to this point we've copied the code from tastypie 0.13.1. Now + # we add caching. + cache_key = fk_resource.generate_cache_key('related', for_list=for_list) + dehydrated = fk_resource._meta.cache.get(cache_key) + if dehydrated is None: + fk_bundle = Bundle(obj=foreign_obj, request=bundle.request) + dehydrated = self.dehydrate_related(fk_bundle, fk_resource, for_list=for_list) + fk_resource._meta.cache.set(cache_key, dehydrated) + return dehydrated diff --git a/ietf/api/management/commands/makeresources.py b/ietf/api/management/commands/makeresources.py index 9997a69ba..1de450128 100644 --- a/ietf/api/management/commands/makeresources.py +++ b/ietf/api/management/commands/makeresources.py @@ -16,10 +16,12 @@ from tastypie.resources import ModelResource resource_head_template = """# Autogenerated by the makeresources management command {{date}} from tastypie.resources import ModelResource -from tastypie.fields import ToOneField, ToManyField # pyflakes:ignore +from tastypie.fields import ToManyField # pyflakes:ignore from tastypie.constants import ALL, ALL_WITH_RELATIONS # pyflakes:ignore +from tastypie.cache import SimpleCache from ietf import api +from ietf.api import ToOneField # pyflakes:ignore from {{app}}.models import * # pyflakes:ignore """ @@ -33,6 +35,7 @@ class {{model.name}}Resource(ModelResource):{% if model.foreign_keys %}{% for fk class Meta: queryset = {{model.name}}.objects.all() serializer = api.Serializer() + cache = SimpleCache() #resource_name = '{{model.resource_name}}' filtering = { {% for name in model.plain_names %} "{{ name }}": ALL,{%endfor%}{% for name in model.fk_names%}