django-piston/piston/handler.py

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',)