Created
March 31, 2015 05:04
-
-
Save svvitale/d3879f37e55b4e0d5246 to your computer and use it in GitHub Desktop.
Comparison of Traditional Django Views to Decorated Views for APIs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.views.generic import View | |
from django.shortcuts import get_object_or_404 | |
from .decorators import json | |
from .models import RoomModel | |
from django.http import HttpResponse | |
class RoomView(View): | |
"""Room view class that implements the primary HTTP verbs (POST, GET, PUT, DELETE). | |
All verb implementations expect to receive and return dictionary objects. All serialization/deserialization | |
is handled outside of the view itself. | |
""" | |
@json | |
def post(self, json_data, *args, **kwargs): | |
""" POST verb handler (database create). Only supports single item creation at this time. | |
:param json_data: Model attributes to use in the creation of a new database entry. | |
:return: Public representation of the created model. This may not include all model fields, depending | |
on how the model defines its to_data() member. | |
""" | |
room = RoomModel(**json_data) | |
try: | |
room.save() | |
except django.db.IntegrityError as ex: | |
# Foreign or unique key error | |
if "violates not-null" in str(ex): | |
return HttpResponse(str(ex), status=400) | |
else: | |
return HttpResponse(str(ex), status=409) | |
return room.to_data() | |
@json | |
def get(self, json_data, item_id=None, *args, **kwargs): | |
""" GET verb handler (database read) | |
:param json_data: Not used. | |
:param item_id: (optional) Unique ID of the object to retrieve. If not specified, all objects will be returned. | |
:return: Public representation of the requested object (if item_id specified) or a dictionary containing a | |
single key referencing a list of public representations of all available objects in this collection. | |
""" | |
if item_id: | |
return get_object_or_404(RoomModel, id=item_id).to_data() | |
else: | |
return { | |
"rooms": [item_obj.to_data() for item_obj in RoomModel.objects.all()] | |
} | |
@json | |
def put(self, json_data, item_id, *args, **kwargs): | |
""" PUT verb handler (database update). Only supports single item updates at this time. | |
:param json_data: Dictionary of key/value pairs that should be updated on the specified object | |
:param item_id: Unique ID of the object to update. | |
:return: Public representation of the updated object | |
""" | |
existing_item = get_object_or_404(RoomModel, id=item_id) | |
for key, value in json_data.items(): | |
setattr(existing_item, key, value) | |
try: | |
existing_item.save() | |
except django.db.IntegrityError as ex: | |
# Foreign or unique key error | |
if "violates not-null" in str(ex): | |
return HttpResponse(str(ex), status=400) | |
else: | |
return HttpResponse(str(ex), status=409) | |
return existing_item.to_data() | |
@json | |
def delete(self, json_data, item_id, *args, **kwargs): | |
""" DELETE verb handler (database delete). Only supports single item deletions at this time. | |
:param json_data: Not used. | |
:param item_id: Unique ID of the object to delete. | |
:return: Status 204 on success, error message on failure | |
""" | |
existing_item = get_object_or_404(RoomModel, id=item_id) | |
try: | |
existing_item.delete() | |
except django.db.Error as ex: | |
# General database error | |
return HttpResponse(str(ex), status=400) | |
except AssertionError as ex: | |
# Django error such as "object can't be deleted because its id attribute is set to None" | |
return HttpResponse(str(ex), status=400) | |
return existing_item.to_data() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.http import JsonResponse, HttpResponse | |
from json import loads | |
def json(view_func): | |
def wrapper(self, request, *args, **kwargs): | |
# Deserialize the request body into a native dictionary | |
if request.method == "GET": | |
json_data = {k: v for k, v in request.GET.items()} | |
elif request.body: | |
json_data = loads(request.body.decode('utf-8')) | |
else: | |
json_data = {} | |
# Call the view handler | |
response = view_func(self, json_data, *args, **kwargs) | |
# Translate the return into a JsonResponse if necessary. This allows us to return native Python | |
# data structures without having to remember to jsonify it. | |
if isinstance(response, HttpResponse): | |
# Most likely an error response. Just pass it through | |
return response | |
else: | |
# Return the appropriate HTTP status | |
if request.method == "POST": | |
status = 201 # CREATED | |
elif request.method == "DELETE": | |
status = 204 # NO CONTENT | |
else: | |
status = 200 # OK | |
# Serialize | |
return JsonResponse(response, status=status) | |
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
from django.forms import model_to_dict | |
import django.db | |
from django.http import HttpResponse | |
from datetime import datetime | |
class Room(models.Model): | |
""" A chat room. """ | |
name = models.CharField("room name", max_length=100, unique=True, default=None) | |
def to_data(self): | |
""" Iterate over all attributes and return a native Python dictionary containing all attributes. """ | |
data = {} | |
# Iterate over each of our fields and return a dictionary that contains only whitelisted fields. | |
for attr_name, attr_val in model_to_dict(self).items(): | |
data[attr_name] = attr_val | |
return data |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.views.generic import View | |
from django.shortcuts import get_object_or_404 | |
from .models import RoomModel | |
from json import loads | |
from django.http import JsonResponse, HttpResponse | |
class RoomView(View): | |
"""Room view class that implements the primary HTTP verbs (POST, GET, PUT, DELETE). | |
All verb implementations expect to receive and return dictionary objects. All serialization/deserialization | |
is handled outside of the view itself. | |
""" | |
def post(self, request, *args, **kwargs): | |
""" POST verb handler (database create). Only supports single item creation at this time. | |
:param json_data: Model attributes to use in the creation of a new database entry. | |
:return: Public representation of the created model. This may not include all model fields, depending | |
on how the model defines its to_data() member. | |
""" | |
json_data = loads(request.body.decode('utf-8')) | |
room = RoomModel(**json_data) | |
try: | |
room.save() | |
except django.db.IntegrityError as ex: | |
# Foreign or unique key error | |
if "violates not-null" in str(ex): | |
return HttpResponse(str(ex), status=400) | |
else: | |
return HttpResponse(str(ex), status=409) | |
return JsonResponse(room.to_data()) | |
def get(self, request, item_id=None, *args, **kwargs): | |
""" GET verb handler (database read) | |
:param json_data: Not used. | |
:param item_id: (optional) Unique ID of the object to retrieve. If not specified, all objects will be returned. | |
:return: Public representation of the requested object (if item_id specified) or a dictionary containing a | |
single key referencing a list of public representations of all available objects in this collection. | |
""" | |
if item_id: | |
return JsonResponse(get_object_or_404(RoomModel, id=item_id).to_data()) | |
else: | |
return JsonResponse({ | |
"rooms": [item_obj.to_data() for item_obj in RoomModel.objects.all()] | |
}) | |
def put(self, request, item_id, *args, **kwargs): | |
""" PUT verb handler (database update). Only supports single item updates at this time. | |
:param json_data: Dictionary of key/value pairs that should be updated on the specified object | |
:param item_id: Unique ID of the object to update. | |
:return: Public representation of the updated object | |
""" | |
existing_item = get_object_or_404(RoomModel, id=item_id) | |
json_data = loads(request.body.decode('utf-8')) | |
for key, value in json_data.items(): | |
setattr(existing_item, key, value) | |
try: | |
existing_item.save() | |
except django.db.IntegrityError as ex: | |
# Foreign or unique key error | |
if "violates not-null" in str(ex): | |
return HttpResponse(str(ex), status=400) | |
else: | |
return HttpResponse(str(ex), status=409) | |
return JsonResponse(existing_item.to_data()) | |
def delete(self, json_data, item_id, *args, **kwargs): | |
""" DELETE verb handler (database delete). Only supports single item deletions at this time. | |
:param json_data: Not used. | |
:param item_id: Unique ID of the object to delete. | |
:return: Status 204 on success, error message on failure | |
""" | |
existing_item = get_object_or_404(RoomModel, id=item_id) | |
try: | |
existing_item.delete() | |
except django.db.Error as ex: | |
# General database error | |
return HttpResponse(str(ex), status=400) | |
except AssertionError as ex: | |
# Django error such as "object can't be deleted because its id attribute is set to None" | |
return HttpResponse(str(ex), status=400) | |
return JsonResponse(existing_item.to_data()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment