Skip to content

Commit

Permalink
Merge branch 'feature-caching'
Browse files Browse the repository at this point in the history
Conflicts:
	docs/usage.rst
  • Loading branch information
george.whewell committed Jan 19, 2015
2 parents 743db9e + cc2ccf4 commit 5568509
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 7 deletions.
18 changes: 18 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
============
Configuration
============

Provided your Django project has a working cache backend, django-sheets will cache requests to the Google Sheets API for 5 minutes.

- Performance- making an extra HTTP request per page-view (or more) will lead to poor response times.
- Reliability- The Google Sheets API may experience failing requests- having a cached copy on your servers means this is less likely to affect you.
- Exceeding quota- By making excessive requests you risk exceeding the API Quota and having requests denied until the quota is refreshed, making your page unusable.

If you wish to disable this cache, add to your settings file::

SHEETS_CACHE_DISABLED = True

You can lower the cache timeout if you wish to sacrifice performance to lessen the chance of stale data, or extend it to improve performance and reduce server load::

# Set timeout to 1 hour
SHEETS_CACHE_TIMEOUT = 3600
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Welcome to django-sheets's documentation!
:maxdepth: 2

installation
configuration
usage
authors
history
11 changes: 9 additions & 2 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ Google Sheets spreadsheet. To find it, open your sheet and select
Click *Get sharable link* from the dialog. You'll find the 44-character key as
part of the URL.

<<<<<<< HEAD
For example, the sample link ``https://docs.google.com/spreadsheets/d/1bJNR7SLqpzWJNvstNcFR4gtS-M7Bmn0D1X2lGTJPvGM/pubhtml``
has key ``1bJNR7SLqpzWJNvstNcFR4gtS-M7Bmn0D1X2lGTJPvGM``
=======
Press Share, and select the link. You'll find the 44-character key as
part of the link. For example, the sample link:

`https://docs.google.com/spreadsheets/d/**1bJNR7SLqpzWJNvstNcFR4gtS-M7Bmn0D1X2lGTJPvGM**/pubhtml`
>>>>>>> feature-caching

Load the django-sheets template tags in your template::

Expand All @@ -22,9 +29,9 @@ Assign the CSV data to a variable using the ``{% csv %}`` tag::
Try it using the sample key above::

{% load sheets %}
{% csv "1uPsdcGUnUsf3d2xGHRGUUb7_k5IQPtBvfQY61u8Z8wE" as uk500 %}
{% csv "1uPsdcGUnUsf3d2xGHRGUUb7_k5IQPtBvfQY61u8Z8wE" as csv_data %}
<table>
{% for row in uk500 %}
{% for row in csv_data %}
<tr>
{% for cell in row %}
<td>{{ cell }}</td>
Expand Down
28 changes: 23 additions & 5 deletions sheets/templatetags/sheets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import unicode_literals

from django import template
from django.conf import settings
from django.core.cache import cache
from django.utils.encoding import force_str, force_text

import csv
Expand All @@ -13,10 +15,12 @@
gdocs_format = \
'https://docs.google.com/spreadsheets/d/{key}/export?format=csv&id={key}'

CACHE_TIMEOUT = getattr(settings, 'SHEETS_CACHE_TIMEOUT', 300)
CACHE_KEY = 'django-sheets-{key}'


def get_sheet(key):
try:
print(gdocs_format.format(key=key))
response = requests.get(gdocs_format.format(key=key))
response.raise_for_status()
return response
Expand All @@ -33,16 +37,30 @@ def read_csv(csv_content):
)


class ExplicitNone:
pass


@register.assignment_tag(name='csv')
def csv_tag(key):
if not key:
raise RuntimeError('Sheet key not supplied')

cache_enabled = not getattr(settings, 'SHEETS_CACHE_DISABLED', False)

if cache_enabled:
cache_key = CACHE_KEY.format(key=key)
cached_output = cache.get(cache_key)
if cached_output is not None:
return cached_output

response_data = get_sheet(key)

if response_data is None:
return None
if response_data:
reader = read_csv(response_data.content)
response_data = [[force_text(cell) for cell in row] for row in reader]

reader = read_csv(response_data.content)
if cache_enabled:
cache.set(cache_key, response_data, CACHE_TIMEOUT)

return [[force_text(cell) for cell in row] for row in reader]
return response_data
50 changes: 50 additions & 0 deletions tests/test_templatetags.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from django import template
from django.test import SimpleTestCase
from django.test.utils import override_settings
from django.core.cache import cache

sample_template = \
"""{% spaceless %}
Expand Down Expand Up @@ -46,6 +48,9 @@

class TestSheets(SimpleTestCase):

def setUp(self):
cache.clear()

def test_no_key(self):
"""
Empty keys should throw exception
Expand Down Expand Up @@ -83,3 +88,48 @@ def test_sample_mocked(self):
gdocs_format.format(key=sample_key))

self.assertEqual(output, open(sample_output).read())

@responses.activate
def test_cache(self):
"""
When cache enabled, rendering tag twice should issue one request
"""
responses.add(
responses.GET, gdocs_format.format(key=sample_key),
body=open(sample_response).read(),
match_querystring=True, status=200)
t = template.Template(sample_template)
t.render(template.Context({'key': sample_key}))
output = t.render(template.Context({'key': sample_key}))
self.assertEqual(output, open(sample_output).read())
self.assertEqual(1, len(responses.calls))

@responses.activate
@override_settings(SHEETS_CACHE_DISABLED=True)
def test_cache_disabled(self):
"""
When cache disabled, rendering tag twice should issue two requests
"""
responses.add(
responses.GET, gdocs_format.format(key=sample_key),
body=open(sample_response).read(),
match_querystring=True, status=200)
t = template.Template(sample_template)
t.render(template.Context({'key': sample_key}))
t.render(template.Context({'key': sample_key}))

self.assertEqual(2, len(responses.calls))

@responses.activate
def test_cache_when_empty(self):
"""
Make sure that empty spreadsheets are not mistaken for cache miss
"""
responses.add(
responses.GET, gdocs_format.format(key=sample_key),
body='',
match_querystring=True, status=200)
t = template.Template(sample_template)
t.render(template.Context({'key': sample_key}))
t.render(template.Context({'key': sample_key}))
self.assertEqual(1, len(responses.calls))

0 comments on commit 5568509

Please sign in to comment.