├── .gitignore ├── README.md ├── cookbook ├── __init__.py ├── admin.py ├── apps.py ├── fixtures │ ├── __init__.py │ └── cookbook.json ├── models.py ├── services.py ├── templates │ └── cookbook │ │ └── recipes.html ├── urls.py └── views.py ├── example ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── manage.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # IPython Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # dotenv 81 | .env 82 | 83 | # virtualenv 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | db.sqlite3 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Caching in Django with Redis 2 | 3 | ## Want to learn how to build this project? 4 | 5 | Check out the [blog post](https://realpython.com/blog/python/caching-in-django-with-redis/). 6 | 7 | ## Want to use this project? 8 | 9 | 1. Fork/Clone 10 | 1. Create and activate a virtual environment 11 | 1. Install dependencies - `pip install -r requirements` 12 | 1. Make migrations - `python manage.py makemigrations cookbook` 13 | 1. Build the database - `python manage.py migrate` 14 | 1. Create a superuser - `python manage.py createsuperuser` 15 | 1. Add seed data - `python manage.py loaddata cookbook/fixtures/cookbook.json` 16 | 1. Run the development server - `python manage.py runserver` 17 | -------------------------------------------------------------------------------- /cookbook/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpython/django-redis-cache/64c4e47b24f9a2d4fb1e484cbc590987829de8ea/cookbook/__init__.py -------------------------------------------------------------------------------- /cookbook/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Recipe, Food, Ingredient 3 | 4 | 5 | class IngredientInline(admin.TabularInline): 6 | model = Ingredient 7 | 8 | 9 | @admin.register(Recipe) 10 | class RecipeAdmin(admin.ModelAdmin): 11 | inlines = (IngredientInline,) 12 | 13 | 14 | @admin.register(Food) 15 | class FoodAdmin(admin.ModelAdmin): 16 | pass 17 | -------------------------------------------------------------------------------- /cookbook/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class CookbookConfig(AppConfig): 7 | name = 'cookbook' 8 | -------------------------------------------------------------------------------- /cookbook/fixtures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpython/django-redis-cache/64c4e47b24f9a2d4fb1e484cbc590987829de8ea/cookbook/fixtures/__init__.py -------------------------------------------------------------------------------- /cookbook/fixtures/cookbook.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "model": "cookbook.recipe", 4 | "pk": 1, 5 | "fields": { 6 | "name": "Classic Teriyaki Sauce", 7 | "desc": "Many Americans think of teriyaki as a marinade, but in traditional Japanese cuisine it's actually a glaze or barbecue sauce brushed on simply grilled meats and seafood. Teri is the Japanese word for gloss or luster; yaki means grilled. Zen-like in its simplicity, this recipe was inspired by the late Shizuo Tsuji, founder of the Ecole Technique H\u00f4teli\u00e8re Tsuji in Osaka and author of the seminal book Japanese Cooking: A Simple Art.", 8 | "instructions": "
{{ recipe.desc }}
10 | {% endautoescape %} 11 |{{ recipe.instructions }}
20 | {% endautoescape %} 21 | {% endfor %} 22 | 23 | 24 | -------------------------------------------------------------------------------- /cookbook/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from .views import recipes_view 3 | 4 | 5 | urlpatterns = [ 6 | url(r'^$', recipes_view), 7 | ] 8 | -------------------------------------------------------------------------------- /cookbook/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.cache.backends.base import DEFAULT_TIMEOUT 3 | from django.shortcuts import render 4 | from django.views.decorators.cache import cache_page 5 | from .services import get_recipes_with_cache as get_recipes 6 | 7 | CACHE_TTL = getattr(settings, 'CACHE_TTL', DEFAULT_TIMEOUT) 8 | 9 | 10 | @cache_page(CACHE_TTL) 11 | def recipes_view(request): 12 | return render(request, 'cookbook/recipes.html', { 13 | 'recipes': get_recipes() 14 | }) 15 | -------------------------------------------------------------------------------- /example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/realpython/django-redis-cache/64c4e47b24f9a2d4fb1e484cbc590987829de8ea/example/__init__.py -------------------------------------------------------------------------------- /example/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for example project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.9.8. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.9/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '7#w^)8%x1r=902vwea^(@ros*wwkwttur_bxsq3s4h2z6)@d7m' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | DEFAULT_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | ] 41 | 42 | THIRD_PARTY_APPS = ['debug_toolbar'] 43 | 44 | LOCAL_APPS = ['cookbook'] 45 | 46 | INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + LOCAL_APPS 47 | 48 | MIDDLEWARE_CLASSES = [ 49 | 'django.middleware.security.SecurityMiddleware', 50 | 'django.contrib.sessions.middleware.SessionMiddleware', 51 | 'django.middleware.common.CommonMiddleware', 52 | 'django.middleware.csrf.CsrfViewMiddleware', 53 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 54 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 55 | 'django.contrib.messages.middleware.MessageMiddleware', 56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 | ] 58 | 59 | ROOT_URLCONF = 'example.urls' 60 | 61 | TEMPLATES = [ 62 | { 63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 64 | 'DIRS': [], 65 | 'APP_DIRS': True, 66 | 'OPTIONS': { 67 | 'context_processors': [ 68 | 'django.template.context_processors.debug', 69 | 'django.template.context_processors.request', 70 | 'django.contrib.auth.context_processors.auth', 71 | 'django.contrib.messages.context_processors.messages', 72 | ], 73 | }, 74 | }, 75 | ] 76 | 77 | WSGI_APPLICATION = 'example.wsgi.application' 78 | 79 | 80 | # Database 81 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 82 | 83 | DATABASES = { 84 | 'default': { 85 | 'ENGINE': 'django.db.backends.sqlite3', 86 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 87 | } 88 | } 89 | 90 | 91 | # Password validation 92 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 93 | 94 | AUTH_PASSWORD_VALIDATORS = [ 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 106 | }, 107 | ] 108 | 109 | 110 | # Internationalization 111 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 112 | 113 | LANGUAGE_CODE = 'en-us' 114 | 115 | TIME_ZONE = 'UTC' 116 | 117 | USE_I18N = True 118 | 119 | USE_L10N = True 120 | 121 | USE_TZ = True 122 | 123 | 124 | # Static files (CSS, JavaScript, Images) 125 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 126 | 127 | STATIC_URL = '/static/' 128 | 129 | CACHES = { 130 | "default": { 131 | "BACKEND": "django_redis.cache.RedisCache", 132 | "LOCATION": "redis://127.0.0.1:6379/1", 133 | "OPTIONS": { 134 | "CLIENT_CLASS": "django_redis.client.DefaultClient" 135 | }, 136 | "KEY_PREFIX": "example" 137 | } 138 | } 139 | 140 | # Cache time to live is 15 minutes. 141 | CACHE_TTL = 60 * 15 142 | -------------------------------------------------------------------------------- /example/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.contrib import admin 3 | 4 | urlpatterns = [ 5 | url(r'^admin/', admin.site.urls), 6 | ] 7 | 8 | urlpatterns += [ 9 | url(r'^cookbook/', include('cookbook.urls')) 10 | ] 11 | -------------------------------------------------------------------------------- /example/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for example project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.9.8 2 | django-debug-toolbar==1.5 3 | django-redis==4.4.4 4 | redis==2.10.5 5 | sqlparse==0.2.0 6 | --------------------------------------------------------------------------------