Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save AndrewJHart/3daf2fdc3f092139e867 to your computer and use it in GitHub Desktop.
Save AndrewJHart/3daf2fdc3f092139e867 to your computer and use it in GitHub Desktop.
Different ways to use Tastypie's resource serialization and build a response outside of the API or a resource.. e.g. a separate view in views.py, building a custom view within the resource, etc..
"""
Credit to the parker library (https://github.com/coxmediagroup/parker/) and their TastyPieHandler.
"""
# Examples of building manual responses anywhere, w/i extra views, and overridden methods
############################################################################
# example of building a serialized response from anywhere
req = HttpRequest()
resource = YourResource()
bundle = resource.build_bundle(obj=your_model)
bundle = resource.full_dehydrate(bundle)
bundle = resource.alter_detail_data_to_serialize(req, bundle)
json_string = resource.serialize(req, bundle, 'application/json')
# building a view & response for the API for our own view
# that provides login & logout functionality for a User Object
# represented as a JSON consumable API Resource `UserResource`
class UserResource(subclassedResource):
# must define urls for views within a resource
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/login%s$" %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('login'), name="api_login"),
url(r'^(?P<resource_name>%s)/logout%s$' %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('logout'), name='api_logout'),
]
def login(self, request, **kwargs):
"""
Custom view, wrapped by the tastypie for handling auth over the API
uses method_check for post to allow only post requests to this endpoint; since this is a different
endpoint, we can use method_check to do per-view override on the allowed_methods or list_allowed_methods in meta :)
"""
self.method_check(request, allowed=['post'])
data = self.deserialize(request, request.body)
username = data.get('username', '')
password = data.get('password', '')
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
key = user.api_key.key
# use create_response for simple responses or non-complex data, here we're
# returning the users api-key in the response to be stored in a device, etc..
return self.create_response(request, {
'api_key': key
})
else:
# simple response with status code for HTTP Forbbiden since acct is inactive
return self.create_response(request, {
'success': False,
'reason': 'disabled',
}, HttpForbidden)
else:
# simple response with proper status code HTTP Unathorized since credentials didnt match
return self.create_response(request, {
'success': False,
'reason': 'incorrect',
}, HttpUnauthorized)
def logout(self, request, **kwargs):
""" logout method - much simpler version of the login method """
# check that only GET requests are allowed
self.method_check(request, allowed=['get'])
if request.user and request.user.is_authenticated():
logout(request)
return self.create_response(request, {'success': True})
else:
return self.create_response(request, {'success': False}, HttpUnauthorized)
# overriding tastypie built-in `detail` view & response for the purpose of
# altering this resources default detail (api/{resource_name}/{primary_key}/)
# response behavior to perform some special function that is not normally
# provided by a typical "GET" request for the default `detail` endpoint
# *all methods are prefixed with the corresponding HTTP verb*
class KeyResource(subclassedResource):
""" Represents an api key resource for the API """
class Meta:
queryset = Key.objects.all()
resource_name = "api_key"
fields = ["key"]
authorization = DjangoAuthorization()
authentication = MultiAuthentication(SessionAuthentication(), BasicAuthentication())
list_allowed_methods = []
detail_allowed_methods = ["get"] # this is safe since we have overridden get_detail
def get_detail(self, request, **kwargs):
"""
modifies default response to allow only a logged in user/device to get their api key
by calling this resources detail view e.g. api/v1/resource_name/key/
"""
if kwargs["pk"] != "key":
# override default behavior that looks for an ID and always expect resource/key/
raise NotImplementedError("Resource not found")
# no need to check if user is authenticated since this class's authentication attr
# requires BasicHttpAuth or SessionAuth (Only use over SSL https)
obj = Key.objects.get(user=request.user)
# Manually build the serialized HTTP response to return
########################################################
bundle = self.build_bundle(obj=obj, request=request) # take queryset obj & request
bundle = self.full_dehydrate(bundle) # serialize the object to default format (Xml / Json)
bundle = self.alter_detail_data_to_serialize(request, bundle) # call to ensure any special handling is in response
# again we use the tastypie create_response method with our bundle & current request & return it
return self.create_response(request, bundle)
@AndrewJHart
Copy link
Author

Simple way to use built-in tastypie methods for serialization anywhere in your django code e.g. special views, etc..

@stodge
Copy link

stodge commented Nov 28, 2018

I tried using lines 10-17, but I get:

AttributeError: 'HttpRequest' object has no attribute 'user'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment