Skip to content

Commit 62cae36

Browse files
committed
Subclassed tastypie's ToOneField in order to provide caching for FK entries.
- Legacy-Id: 10927
1 parent 781a552 commit 62cae36

2 files changed

Lines changed: 45 additions & 3 deletions

File tree

ietf/api/__init__.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
from django.conf import settings
66
from django.http import HttpResponse
7+
from django.core.exceptions import ObjectDoesNotExist
78
from django.core.urlresolvers import reverse
89
from django.utils.encoding import force_text
910

11+
import tastypie
1012
from tastypie.api import Api
1113
from tastypie.bundle import Bundle
1214
from tastypie.serializers import Serializer as BaseSerializer
@@ -172,5 +174,42 @@ def hydrate(self, bundle):
172174
raise ApiFieldError("Datetime provided to '%s' field must be a string: %s" % (self.instance_name, value))
173175

174176
return value
175-
176-
177+
178+
class ToOneField(tastypie.fields.ToOneField):
179+
"Subclass of tastypie.fields.ToOneField which adds caching in the dehydrate method."
180+
181+
def dehydrate(self, bundle, for_list=True):
182+
foreign_obj = None
183+
184+
if callable(self.attribute):
185+
previous_obj = bundle.obj
186+
foreign_obj = self.attribute(bundle)
187+
elif isinstance(self.attribute, six.string_types):
188+
foreign_obj = bundle.obj
189+
190+
for attr in self._attrs:
191+
previous_obj = foreign_obj
192+
try:
193+
foreign_obj = getattr(foreign_obj, attr, None)
194+
except ObjectDoesNotExist:
195+
foreign_obj = None
196+
197+
if not foreign_obj:
198+
if not self.null:
199+
if callable(self.attribute):
200+
raise ApiFieldError("The related resource for resource %s could not be found." % (previous_obj))
201+
else:
202+
raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (previous_obj, attr))
203+
return None
204+
205+
fk_resource = self.get_related_resource(foreign_obj)
206+
207+
# Up to this point we've copied the code from tastypie 0.13.1. Now
208+
# we add caching.
209+
cache_key = fk_resource.generate_cache_key('related', for_list=for_list)
210+
dehydrated = fk_resource._meta.cache.get(cache_key)
211+
if dehydrated is None:
212+
fk_bundle = Bundle(obj=foreign_obj, request=bundle.request)
213+
dehydrated = self.dehydrate_related(fk_bundle, fk_resource, for_list=for_list)
214+
fk_resource._meta.cache.set(cache_key, dehydrated)
215+
return dehydrated

ietf/api/management/commands/makeresources.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
resource_head_template = """# Autogenerated by the makeresources management command {{date}}
1818
from tastypie.resources import ModelResource
19-
from tastypie.fields import ToOneField, ToManyField # pyflakes:ignore
19+
from tastypie.fields import ToManyField # pyflakes:ignore
2020
from tastypie.constants import ALL, ALL_WITH_RELATIONS # pyflakes:ignore
21+
from tastypie.cache import SimpleCache
2122
2223
from ietf import api
24+
from ietf.api import ToOneField # pyflakes:ignore
2325
2426
from {{app}}.models import * # pyflakes:ignore
2527
"""
@@ -33,6 +35,7 @@ class {{model.name}}Resource(ModelResource):{% if model.foreign_keys %}{% for fk
3335
class Meta:
3436
queryset = {{model.name}}.objects.all()
3537
serializer = api.Serializer()
38+
cache = SimpleCache()
3639
#resource_name = '{{model.resource_name}}'
3740
filtering = { {% for name in model.plain_names %}
3841
"{{ name }}": ALL,{%endfor%}{% for name in model.fk_names%}

0 commit comments

Comments
 (0)