1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 | try:
frozenset
except NameError:
# Import from the sets module for python 2.3
from sets import Set as set
from sets import ImmutableSet as frozenset
from datetime import datetime, timedelta
from threading import Thread
import time
from django.shortcuts import render_to_response
from django.http import (
Http404, HttpResponse, HttpResponseRedirect,
HttpResponsePermanentRedirect, HttpResponseGone, HttpResponseNotAllowed,
HttpResponseForbidden, HttpResponseBadRequest, HttpResponseNotModified,
HttpResponseServerError
)
from django.template import RequestContext
from django.core.urlresolvers import reverse
from django.conf import settings
class View(object):
"""
View class that lets you do at least 90% of what you can do in a normal
view function, but without having to import all the normal boilerplate
code first since this class wraps methods around most if not all the
HttpResponse types
"""
context = {}
template = None
allowed_methods = frozenset(['GET', 'POST', 'HEAD', 'OPTIONS', 'PUT',
'DELETE', 'TRACE', 'CONNECT'])
build_response = False
mimetype = None
def __call__(self, request, *args, **kwargs):
"""
This is the meat of the class, it lets it act as a callable
Thus allowing the url handler to call the correct view
Whats happening is it first sets the class request attribute,
so it can be accessed via the other class methods
Second it checks to make sure the requests method (GET, POST, etc)
is in the allowed types list, if it is not then retuns a not allowed
page
Next it check to see if you want to build your own response (False by default),
thus setting self.response to an empty HttpResponse that you can
use to manualy build up your response. If you just want the normal
way of using render_to_response it sets self.response to self.http_response
Finnaly it attempts to call render without sending it the request object
Since render will have access to the request object via self.request
this should be the normal way of sending it, BUT if you need to
decorate render with somnething like @login_required, then it needs
to pass the request object along with it so it can be used by the
decorator
"""
self.request = request
if self.request.method not in self.allowed_methods:
return self.not_allowed(self.allowed_methods)
if self.build_response:
self.response = HttpResponse()
else:
self.response = self.http_response
try:
return self.render(*args, **kwargs)
except TypeError:
return self.render(request, *args, **kwargs)
def render(self, *args, **kwargs):
"""
This is the method that gets called when your view gets called
So this is the method you need to override in your subclass
"""
return HttpResponse("This View is not yet Implimented!")
def http_response(self):
"""
Wrapper around the render_to_response shortcut. It uses the classes
self.template, self.context, and self.mimetype and ensures that you
get a normal request_context
"""
return render_to_response(self.template, self.context,
context_instance=RequestContext(self.request), mimetype=self.mimetype)
def raw_response(self, msg, **kwargs):
"""
Wrapper around the HttpResponse object so you can deal with a raw
response instead of being forced to use the render_to_response
"""
return HttpResponse(msg, **kwargs)
def redirect(self, url, reverse=True):
"""
Wrapper around the HttpResponseRedirect class. Takes a url, and assumes
that you want to use reverse to find the actual url
"""
if reverse:
url = reverse(url)
return HttpResponseRedirect(url)
def permanent_redirect(self, url, reverse=True):
"""
Wrapper around the HttpResponsePermanentRedirect class. Takes a url, and assumes
that you want to use reverse to find the actual url
"""
if reverse:
url = reverse(url)
return HttpResponsePermanentRedirect(url)
def gone(self):
"""
Wrapper around the HttpResponseGone class.
"""
return HttpResponseGone()
def not_allowed(self, methods):
"""
Wrapper around the HttpResponseNotAllowed class.
"""
return HttpResponseNotAllowed(methods)
def forbidden(self):
"""
Wrapper around the HttpResponseForbidden class.
"""
return HttpResponseForbidden()
def server_error(self):
"""
Wrapper around the HttpResponseServerError class.
"""
return self.Http500()
def not_found(self):
"""
Wrapper around the HttpResponseNotFound class.
"""
self.Http404()
def bad(self):
"""
Wrapper around the HttpResponseBadRequest class.
"""
return HttpResponseBadRequest()
def unmodified(self):
"""
Wrapper around the HttpResponseNotModified class.
"""
return HttpResponseNotModified()
def Http404(self):
"""
Raises the 404 exception
"""
raise Http404
def Http500(self):
"""
Wrapper around the HttpResponseServerError class.
"""
return HttpResponseServerError()
def is_ajax(self):
"""
Wrapper around the request.is_ajax method
Should work on 0.96 as well if anyone is still using that
"""
try:
return self.request.is_ajax()
except:
idx = self.request.META['HTTP_X_REQUESTED_WITH'].find('XMLHttpRequest')
if idx > -1:
return True
return False
def is_secure(self):
"""
Wrapper around the request.is_secure method
"""
return self.request.is_secure()
class StatefulView(View):
"""
This is a StatefulView class that maintains its state across page loads
This is especialy useful for ajax type calls where you wish to maintain
some form of state while the use is doing something but do not wish to
make DB calls and do not wish to polute the session with trivial things
NOTE: On my system it maintains state across browsers and computers as it is
not tied to the session, BUT for this to happen all requests must be handled
by the same proccess. So requests going to a differing process with not have
the state maintained.
"""
def __new__(cls, *args, **kwds):
it = cls.__dict__.get("__it__")
if it is not None:
return it
cls.__it__ = it = object.__new__(cls)
it.init(*args, **kwds)
return it
def init(self, *args, **kwds):
pass
"""
from apps.utils.views import View, StatefulView
class Home(View):
template = 'index.html'
def render(self):
return self.response()
class Test(StatefulView):
counter = 0
build_response = True
def render(self):
self.counter += 1
self.response.write("You have viewed this page %d times" % (self.counter,))
return self.response
index = Home()
test = Test()
"""
|
Comments