|
code@188
|
1 |
"""
|
|
code@188
|
2 |
Random Django snippets I like to keep for quick reference
|
|
code@188
|
3 |
|
|
code@188
|
4 |
"""
|
|
code@188
|
5 |
|
|
code@188
|
6 |
def cache_key_for_function(func, args=None, kwargs=None):
|
|
code@188
|
7 |
"""Calculate a cache key for a function
|
|
code@188
|
8 |
|
|
code@257
|
9 |
Prefixes keys with the module and function name.
|
|
code@188
|
10 |
|
|
code@188
|
11 |
Use sha1 of repr() of args and kwargs as the final piece of the
|
|
code@188
|
12 |
cache key. This limits the maximum length (so we don't go over
|
|
code@188
|
13 |
memcached's limit, which I don't remember offhand) and swallows
|
|
code@188
|
14 |
control characters.
|
|
code@188
|
15 |
|
|
code@188
|
16 |
This relies on accurate reprs - if the repr of the arguments are
|
|
code@188
|
17 |
the same, the hash will be the same, and the cached value will be
|
|
code@188
|
18 |
returned.
|
|
code@188
|
19 |
|
|
code@188
|
20 |
"""
|
|
code@188
|
21 |
from hashlib import sha1
|
|
code@188
|
22 |
|
|
code@188
|
23 |
if args is None:
|
|
code@188
|
24 |
args = ()
|
|
code@188
|
25 |
if kwargs is None:
|
|
code@188
|
26 |
kwargs = {}
|
|
code@188
|
27 |
|
|
code@188
|
28 |
cache_key = "%s.%s(%s)" % (
|
|
code@188
|
29 |
func.__module__, func.__name__,
|
|
code@188
|
30 |
sha1(repr(args)+repr(kwargs)).hexdigest())
|
|
code@188
|
31 |
|
|
code@188
|
32 |
return cache_key
|
|
code@188
|
33 |
|
|
code@188
|
34 |
|
|
code@188
|
35 |
def cache_key_for_method(obj, method, args=None, kwargs=None):
|
|
code@188
|
36 |
"Like cache_key_for_function, but for methods"
|
|
code@188
|
37 |
from hashlib import sha1
|
|
code@188
|
38 |
|
|
code@188
|
39 |
cache_key = "%s.%s.%s(%s)" % (
|
|
code@188
|
40 |
obj.__class__.__module__,
|
|
code@188
|
41 |
obj.__class__.__name__,
|
|
code@188
|
42 |
method.__name__,
|
|
code@188
|
43 |
sha1(repr(args)+repr(kwargs)).hexdigest())
|
|
code@188
|
44 |
|
|
code@188
|
45 |
return cache_key
|
|
code@188
|
46 |
|
|
code@188
|
47 |
|
|
code@257
|
48 |
def cached_function(func):
|
|
code@257
|
49 |
"""A caching decorator for functions"""
|
|
code@257
|
50 |
from functools import wraps
|
|
code@257
|
51 |
from django.core.cache import cache
|
|
code@257
|
52 |
|
|
code@257
|
53 |
@wraps(func)
|
|
code@257
|
54 |
def _closure(*args, **kwargs):
|
|
code@257
|
55 |
cache_key = cache_key_for_function(
|
|
code@257
|
56 |
func, args, kwargs)
|
|
code@257
|
57 |
|
|
code@257
|
58 |
val = cache.get(cache_key)
|
|
code@257
|
59 |
if val is None:
|
|
code@257
|
60 |
val = func(*args, **kwargs)
|
|
code@257
|
61 |
cache.set(cache_key, val)
|
|
code@257
|
62 |
return val
|
|
code@257
|
63 |
return _closure
|
|
code@257
|
64 |
|
|
code@257
|
65 |
|
|
code@257
|
66 |
def cached_method(method):
|
|
code@257
|
67 |
"""A caching decorator for methods"""
|
|
code@257
|
68 |
from functools import wraps
|
|
code@257
|
69 |
from django.core.cache import cache
|
|
code@257
|
70 |
|
|
code@257
|
71 |
@wraps(method)
|
|
code@257
|
72 |
def _closure(self, *args, **kwargs):
|
|
code@257
|
73 |
cache_key = cache_key_for_method(
|
|
code@257
|
74 |
self, method, (self,)+args, kwargs)
|
|
code@257
|
75 |
|
|
code@257
|
76 |
val = cache.get(cache_key)
|
|
code@257
|
77 |
if val is None:
|
|
code@257
|
78 |
val = method(self, *args, **kwargs)
|
|
code@257
|
79 |
cache.set(cache_key, val)
|
|
code@257
|
80 |
return val
|
|
code@257
|
81 |
return _closure
|
|
code@257
|
82 |
|
|
code@257
|
83 |
cached_property = decorators(property, cached_method)
|
|
code@257
|
84 |
|
|
code@257
|
85 |
|
|
code@188
|
86 |
def dictproperty(method):
|
|
code@188
|
87 |
"""Turn dictionary or attribute access into a function call"""
|
|
code@188
|
88 |
|
|
code@188
|
89 |
class _Object(object):
|
|
code@188
|
90 |
def __init__(self, obj):
|
|
code@188
|
91 |
self.obj = obj
|
|
code@188
|
92 |
def __getattr__(self, attr):
|
|
code@188
|
93 |
return method(self.obj, attr)
|
|
code@188
|
94 |
__getitem__ = __getattr__
|
|
code@189
|
95 |
_Object.__name__ = method.__name__
|
|
code@188
|
96 |
|
|
code@189
|
97 |
return property(_Object)
|
|
code@188
|
98 |
|
|
code@188
|
99 |
|
|
code@188
|
100 |
def decorators(*decos):
|
|
code@188
|
101 |
"""Some people say I need to handle my decorator problem.
|
|
code@188
|
102 |
|
|
code@188
|
103 |
They are wrong.
|
|
code@188
|
104 |
|
|
code@188
|
105 |
The evaulation is such that the things on the left are on the
|
|
code@188
|
106 |
"outside" of the decorator chain. EG::
|
|
code@188
|
107 |
|
|
code@188
|
108 |
@foo
|
|
code@188
|
109 |
@bar
|
|
code@188
|
110 |
|
|
code@188
|
111 |
Could also be::
|
|
code@188
|
112 |
|
|
code@188
|
113 |
@decorators(foo, bar)
|
|
code@188
|
114 |
|
|
code@188
|
115 |
Which itself is, of course, a shortcut for::
|
|
code@188
|
116 |
|
|
code@188
|
117 |
foo(bar(function))
|
|
code@188
|
118 |
|
|
code@188
|
119 |
"""
|
|
code@188
|
120 |
def _decorator(func):
|
|
code@188
|
121 |
# The reversed is needed - step through it, it'll make sense.
|
|
code@188
|
122 |
for deco in reversed(list(decos)):
|
|
code@188
|
123 |
func = deco(func)
|
|
code@188
|
124 |
return func
|
|
code@188
|
125 |
return _decorator
|
|
code@188
|
126 |
|
|
code@188
|
127 |
|
|
code@195
|
128 |
def use_template(template_name, request_context=True):
|
|
code@195
|
129 |
"""A view decorator that wraps render_to_response and uses RequestContext by default"""
|
|
code@195
|
130 |
from functools import wraps
|
|
code@195
|
131 |
from django.template import RequestContext
|
|
code@195
|
132 |
from django.shortcuts import render_to_response
|
|
code@195
|
133 |
|
|
code@195
|
134 |
def _decorator(func):
|
|
code@195
|
135 |
@wraps(func)
|
|
code@195
|
136 |
def _closure(request, *args, **kwargs):
|
|
code@195
|
137 |
# Use a different variable to avoid 'referenced before
|
|
code@195
|
138 |
# assignment'. 'template' is the kwarg used by
|
|
code@195
|
139 |
# direct_to_template; copy its interface for consistency.
|
|
code@195
|
140 |
actual_template = kwargs.pop("template", template_name)
|
|
code@195
|
141 |
actual_rc = kwargs.pop("request_context", request_context)
|
|
code@195
|
142 |
val = func(request, *args, **kwargs)
|
|
code@195
|
143 |
if isinstance(val, dict) and template_name is not None:
|
|
code@195
|
144 |
if actual_rc:
|
|
code@195
|
145 |
context = RequestContext(request)
|
|
code@195
|
146 |
return render_to_response(actual_template, val,
|
|
code@195
|
147 |
context_instance=context)
|
|
code@195
|
148 |
else:
|
|
code@195
|
149 |
return render_to_response(actual_template, val)
|
|
code@195
|
150 |
return val
|
|
code@195
|
151 |
return _closure
|
|
code@195
|
152 |
return _decorator
|
|
code@246
|
153 |
|
|
code@246
|
154 |
|
|
code@246
|
155 |
# http://www.djangosnippets.org/snippets/562/#c673
|
|
code@246
|
156 |
class QuerySetManager(models.Manager):
|
|
code@246
|
157 |
# http://docs.djangoproject.com/en/dev/topics/db/managers/#using-managers-for-related-object-access
|
|
code@246
|
158 |
# Not working cause of:
|
|
code@246
|
159 |
# http://code.djangoproject.com/ticket/9643
|
|
code@246
|
160 |
use_for_related_fields = True
|
|
code@246
|
161 |
def __init__(self, qs_class=models.query.QuerySet):
|
|
code@246
|
162 |
self.queryset_class = qs_class
|
|
code@246
|
163 |
super(QuerySetManager, self).__init__()
|
|
code@246
|
164 |
|
|
code@246
|
165 |
def get_query_set(self):
|
|
code@246
|
166 |
return self.queryset_class(self.model)
|
|
code@246
|
167 |
|
|
code@246
|
168 |
def __getattr__(self, attr, *args):
|
|
code@246
|
169 |
try:
|
|
code@246
|
170 |
return getattr(self.__class__, attr, *args)
|
|
code@246
|
171 |
except AttributeError:
|
|
code@246
|
172 |
return getattr(self.get_query_set(), attr, *args)
|
|
code@246
|
173 |
|
|
code@246
|
174 |
|
|
code@257
|
175 |
# http://adam.gomaa.us/blog/2009/feb/16/subclassing-django-querysets/
|
|
code@246
|
176 |
class QuerySet(models.query.QuerySet):
|
|
code@246
|
177 |
"""Base QuerySet class for adding custom methods that are made
|
|
code@246
|
178 |
available on both the manager and subsequent cloned QuerySets"""
|
|
code@246
|
179 |
|
|
code@246
|
180 |
@classmethod
|
|
code@246
|
181 |
def as_manager(cls, ManagerClass=QuerySetManager):
|
|
code@246
|
182 |
return ManagerClass(cls)
|
|
code@246
|
183 |
|
|
code@246
|
184 |
def random(self):
|
|
code@246
|
185 |
return self.order_by("?")
|
|
code@246
|
186 |
|
|
code@246
|
187 |
def first(self):
|
|
code@246
|
188 |
return self[0]
|