My favorites | Sign in
Project Logo
                
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
"""
Generic resource class.
"""
from django.utils.translation import ugettext as _
from authentication import NoAuthentication
from django.core.urlresolvers import reverse as _reverse
from django.http import Http404, HttpResponse, HttpResponseNotAllowed

def load_put_and_files(request):
"""
Populates request.PUT and request.FILES from
request.raw_post_data. PUT and POST requests differ
only in REQUEST_METHOD, not in the way data is encoded.
Therefore we can use Django's POST data retrieval method
for PUT.
"""
if request.method == 'PUT':
request.method = 'POST'
request._load_post_and_files()
request.method = 'PUT'
request.PUT = request.POST
del request._post

def reverse(viewname, args=(), kwargs=None):
"""
Return the URL associated with a view and specified parameters.
If the regular expression used specifies an optional slash at
the end of the URL, add the slash.
"""
if not kwargs:
kwargs = {}
url = _reverse(viewname, None, args, kwargs)
if url[-2:] == '/?':
url = url[:-1]
return url

class HttpMethodNotAllowed(Exception):
"""
Signals that request.method was not part of
the list of permitted methods.
"""

class ResourceBase(object):
"""
Base class for both model-based and non-model-based
resources.
"""
def __init__(self, authentication=None, permitted_methods=None):
"""
authentication:
the authentication instance that checks whether a
request is authenticated
permitted_methods:
the HTTP request methods that are allowed for this
resource e.g. ('GET', 'PUT')
"""
# Access restrictions
if not authentication:
authentication = NoAuthentication()
self.authentication = authentication

if not permitted_methods:
permitted_methods = ["GET"]
self.permitted_methods = [m.upper() for m in permitted_methods]

def dispatch(self, request, target, *args, **kwargs):
"""
"""
request_method = request.method.upper()
if request_method not in self.permitted_methods:
raise HttpMethodNotAllowed

if request_method == 'GET':
return target.read(request, *args, **kwargs)
elif request_method == 'POST':
return target.create(request, *args, **kwargs)
elif request_method == 'PUT':
load_put_and_files(request)
return target.update(request, *args, **kwargs)
elif request_method == 'DELETE':
return target.delete(request, *args, **kwargs)
else:
raise Http404

def get_url(self):
"""
Returns resource URL.
"""
return reverse(self)

# The four CRUD methods that any class that
# inherits from Resource may implement:

def create(self, request):
raise Http404

def read(self, request):
raise Http404

def update(self, request):
raise Http404

def delete(self, request):
raise Http404

class Resource(ResourceBase):
"""
Generic resource class that can be used for
resources that are not based on Django models.
"""
def __init__(self, authentication=None, permitted_methods=None,
mimetype=None):
"""
authentication:
the authentication instance that checks whether a
request is authenticated
permitted_methods:
the HTTP request methods that are allowed for this
resource e.g. ('GET', 'PUT')
mimetype:
if the default None is not changed, any HttpResponse calls
use settings.DEFAULT_CONTENT_TYPE and settings.DEFAULT_CHARSET
"""
ResourceBase.__init__(self, authentication, permitted_methods)
self.mimetype = mimetype

def __call__(self, request, *args, **kwargs):
"""
Redirects to one of the CRUD methods depending
on the HTTP method of the request. Checks whether
the requested method is allowed for this resource.
"""
# Check permission
if not self.authentication.is_authenticated(request):
response = HttpResponse(_('Authorization Required'), mimetype=self.mimetype)
challenge_headers = self.authentication.challenge_headers()
for k,v in challenge_headers.items():
response[k] = v
response.status_code = 401
return response

try:
return self.dispatch(request, self, *args, **kwargs)
except HttpMethodNotAllowed:
response = HttpResponseNotAllowed(self.permitted_methods)
response.mimetype = self.mimetype
return response

Show details Hide details

Change log

r80 by alaasalman on Jan 11, 2009   Diff
Applied patch to fix missing import
reported by  issue #31 . Thanks to semadk
for the original patch.
Go to: 
Project members, sign in to write a code review

Older revisions

r77 by alaasalman on Jul 29, 2008   Diff
Fixes for authentication including a
patch from madssj. Fixes #24.
r73 by stuhlmueller on Oct 03, 2007   Diff
Fixed #17: Works with case-insensitive
headers, i.e. Django versions from
[6212]
r71 by stuhlmueller on Aug 20, 2007   Diff
Extracted code common to Resource and
ModelResource to ResourceBase.
All revisions of this file

File info

Size: 4903 bytes, 148 lines
Hosted by Google Code