157 строки
4.6 KiB
Python
157 строки
4.6 KiB
Python
import warnings
|
|
|
|
from utils import rc
|
|
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
|
from django.conf import settings
|
|
|
|
typemapper = { }
|
|
handler_tracker = [ ]
|
|
|
|
class HandlerMetaClass(type):
|
|
"""
|
|
Metaclass that keeps a registry of class -> handler
|
|
mappings.
|
|
"""
|
|
def __new__(cls, name, bases, attrs):
|
|
new_cls = type.__new__(cls, name, bases, attrs)
|
|
|
|
def already_registered(model, anon):
|
|
for k, (m, a) in typemapper.iteritems():
|
|
if model == m and anon == a:
|
|
return k
|
|
|
|
if hasattr(new_cls, 'model'):
|
|
if already_registered(new_cls.model, new_cls.is_anonymous):
|
|
if not getattr(settings, 'PISTON_IGNORE_DUPE_MODELS', False):
|
|
warnings.warn("Handler already registered for model %s, "
|
|
"you may experience inconsistent results." % new_cls.model.__name__)
|
|
|
|
typemapper[new_cls] = (new_cls.model, new_cls.is_anonymous)
|
|
else:
|
|
typemapper[new_cls] = (None, new_cls.is_anonymous)
|
|
|
|
if name not in ('BaseHandler', 'AnonymousBaseHandler'):
|
|
handler_tracker.append(new_cls)
|
|
|
|
return new_cls
|
|
|
|
class BaseHandler(object):
|
|
"""
|
|
Basehandler that gives you CRUD for free.
|
|
You are supposed to subclass this for specific
|
|
functionality.
|
|
|
|
All CRUD methods (`read`/`update`/`create`/`delete`)
|
|
receive a request as the first argument from the
|
|
resource. Use this for checking `request.user`, etc.
|
|
"""
|
|
__metaclass__ = HandlerMetaClass
|
|
|
|
allowed_methods = ('GET', 'POST', 'PUT', 'DELETE')
|
|
anonymous = is_anonymous = False
|
|
exclude = ( 'id', )
|
|
fields = ( )
|
|
|
|
def flatten_dict(self, dct):
|
|
return dict([ (str(k), dct.get(k)) for k in dct.keys() ])
|
|
|
|
def has_model(self):
|
|
return hasattr(self, 'model') or hasattr(self, 'queryset')
|
|
|
|
def queryset(self, request):
|
|
return self.model.objects.all()
|
|
|
|
def value_from_tuple(tu, name):
|
|
for int_, n in tu:
|
|
if n == name:
|
|
return int_
|
|
return None
|
|
|
|
def exists(self, **kwargs):
|
|
if not self.has_model():
|
|
raise NotImplementedError
|
|
|
|
try:
|
|
self.model.objects.get(**kwargs)
|
|
return True
|
|
except self.model.DoesNotExist:
|
|
return False
|
|
|
|
def read(self, request, *args, **kwargs):
|
|
if not self.has_model():
|
|
return rc.NOT_IMPLEMENTED
|
|
|
|
pkfield = self.model._meta.pk.name
|
|
|
|
if pkfield in kwargs:
|
|
try:
|
|
return self.queryset(request).get(pk=kwargs.get(pkfield))
|
|
except ObjectDoesNotExist:
|
|
return rc.NOT_FOUND
|
|
except MultipleObjectsReturned: # should never happen, since we're using a PK
|
|
return rc.BAD_REQUEST
|
|
else:
|
|
return self.queryset(request).filter(*args, **kwargs)
|
|
|
|
def create(self, request, *args, **kwargs):
|
|
if not self.has_model():
|
|
return rc.NOT_IMPLEMENTED
|
|
|
|
attrs = self.flatten_dict(request.data)
|
|
|
|
try:
|
|
inst = self.queryset(request).get(**attrs)
|
|
return rc.DUPLICATE_ENTRY
|
|
except self.model.DoesNotExist:
|
|
inst = self.model(**attrs)
|
|
inst.save()
|
|
return inst
|
|
except self.model.MultipleObjectsReturned:
|
|
return rc.DUPLICATE_ENTRY
|
|
|
|
def update(self, request, *args, **kwargs):
|
|
if not self.has_model():
|
|
return rc.NOT_IMPLEMENTED
|
|
|
|
pkfield = self.model._meta.pk.name
|
|
|
|
if pkfield not in kwargs:
|
|
# No pk was specified
|
|
return rc.BAD_REQUEST
|
|
|
|
try:
|
|
inst = self.queryset(request).get(pk=kwargs.get(pkfield))
|
|
except ObjectDoesNotExist:
|
|
return rc.NOT_FOUND
|
|
except MultipleObjectsReturned: # should never happen, since we're using a PK
|
|
return rc.BAD_REQUEST
|
|
|
|
attrs = self.flatten_dict(request.data)
|
|
for k,v in attrs.iteritems():
|
|
setattr( inst, k, v )
|
|
|
|
inst.save()
|
|
return rc.ALL_OK
|
|
|
|
def delete(self, request, *args, **kwargs):
|
|
if not self.has_model():
|
|
raise NotImplementedError
|
|
|
|
try:
|
|
inst = self.queryset(request).get(*args, **kwargs)
|
|
|
|
inst.delete()
|
|
|
|
return rc.DELETED
|
|
except self.model.MultipleObjectsReturned:
|
|
return rc.DUPLICATE_ENTRY
|
|
except self.model.DoesNotExist:
|
|
return rc.NOT_HERE
|
|
|
|
class AnonymousBaseHandler(BaseHandler):
|
|
"""
|
|
Anonymous handler.
|
|
"""
|
|
is_anonymous = True
|
|
allowed_methods = ('GET',)
|