mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	Various cleanup
This commit is contained in:
		
							parent
							
								
									5557dfb54c
								
							
						
					
					
						commit
						764fbe335f
					
				| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
from django.template import RequestContext, loader
 | 
					from django.template import RequestContext, loader
 | 
				
			||||||
from django.core.handlers.wsgi import STATUS_CODE_TEXT
 | 
					 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
from utils import dict2xml
 | 
					from utils import dict2xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,14 +21,6 @@ class TemplatedEmitter(BaseEmitter):
 | 
				
			||||||
        template = loader.get_template(self.template)
 | 
					        template = loader.get_template(self.template)
 | 
				
			||||||
        context = RequestContext(self.resource.request, {
 | 
					        context = RequestContext(self.resource.request, {
 | 
				
			||||||
            'content': content,
 | 
					            'content': content,
 | 
				
			||||||
            'status': self.resource.resp_status,
 | 
					 | 
				
			||||||
            'reason': STATUS_CODE_TEXT.get(self.resource.resp_status, ''),
 | 
					 | 
				
			||||||
            'headers': self.resource.resp_headers,
 | 
					 | 
				
			||||||
            'resource_name': self.resource.__class__.__name__,
 | 
					 | 
				
			||||||
            'resource_doc': self.resource.__doc__,
 | 
					 | 
				
			||||||
            'create_form': self.resource.form,
 | 
					 | 
				
			||||||
            'update_form': self.resource.form,
 | 
					 | 
				
			||||||
            'request': self.resource.request,
 | 
					 | 
				
			||||||
            'resource': self.resource,
 | 
					            'resource': self.resource,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,9 @@
 | 
				
			||||||
from django.http import HttpResponse
 | 
					from django.http import HttpResponse
 | 
				
			||||||
from django.core.urlresolvers import reverse
 | 
					from django.core.urlresolvers import reverse
 | 
				
			||||||
 | 
					from django.core.handlers.wsgi import STATUS_CODE_TEXT
 | 
				
			||||||
from rest import emitters, parsers
 | 
					from rest import emitters, parsers
 | 
				
			||||||
from decimal import Decimal
 | 
					from decimal import Decimal
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 
 | 
					# 
 | 
				
			||||||
STATUS_400_BAD_REQUEST = 400
 | 
					STATUS_400_BAD_REQUEST = 400
 | 
				
			||||||
| 
						 | 
					@ -22,6 +24,10 @@ class ResourceException(Exception):
 | 
				
			||||||
class Resource(object):
 | 
					class Resource(object):
 | 
				
			||||||
    # List of RESTful operations which may be performed on this resource.
 | 
					    # List of RESTful operations which may be performed on this resource.
 | 
				
			||||||
    allowed_operations = ('read',)
 | 
					    allowed_operations = ('read',)
 | 
				
			||||||
 | 
					    anon_allowed_operations = ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Optional form for input validation and presentation of HTML formatted responses. 
 | 
				
			||||||
 | 
					    form = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # List of content-types the resource can respond with, ordered by preference
 | 
					    # List of content-types the resource can respond with, ordered by preference
 | 
				
			||||||
    emitters = ( ('application/json', emitters.JSONEmitter),
 | 
					    emitters = ( ('application/json', emitters.JSONEmitter),
 | 
				
			||||||
| 
						 | 
					@ -36,9 +42,6 @@ class Resource(object):
 | 
				
			||||||
                'application/x-www-form-urlencoded': parsers.FormParser,
 | 
					                'application/x-www-form-urlencoded': parsers.FormParser,
 | 
				
			||||||
                'multipart/form-data': parsers.FormParser }
 | 
					                'multipart/form-data': parsers.FormParser }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Optional form for input validation and presentation of HTML formatted responses. 
 | 
					 | 
				
			||||||
    form = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Map standard HTTP methods to RESTful operations
 | 
					    # Map standard HTTP methods to RESTful operations
 | 
				
			||||||
    CALLMAP = { 'GET': 'read', 'POST': 'create', 
 | 
					    CALLMAP = { 'GET': 'read', 'POST': 'create', 
 | 
				
			||||||
                'PUT': 'update', 'DELETE': 'delete' }
 | 
					                'PUT': 'update', 'DELETE': 'delete' }
 | 
				
			||||||
| 
						 | 
					@ -57,20 +60,34 @@ class Resource(object):
 | 
				
			||||||
        """Make the class callable so it can be used as a Django view."""
 | 
					        """Make the class callable so it can be used as a Django view."""
 | 
				
			||||||
        self = object.__new__(cls)
 | 
					        self = object.__new__(cls)
 | 
				
			||||||
        self.__init__()
 | 
					        self.__init__()
 | 
				
			||||||
        self.request = request
 | 
					        return self._handle_request(request, *args, **kwargs)
 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            return self._handle_request(request, *args, **kwargs)
 | 
					 | 
				
			||||||
        except:
 | 
					 | 
				
			||||||
            import traceback
 | 
					 | 
				
			||||||
            traceback.print_exc()
 | 
					 | 
				
			||||||
            raise
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def name(self):
 | 
				
			||||||
 | 
					        """Provide a name for the resource.
 | 
				
			||||||
 | 
					        By default this is the class name, with 'CamelCaseNames' converted to 'Camel Case Names',
 | 
				
			||||||
 | 
					        although this behaviour may be overridden."""
 | 
				
			||||||
 | 
					        class_name = self.__class__.__name__
 | 
				
			||||||
 | 
					        return re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def description(self):
 | 
				
			||||||
 | 
					        """Provide a description for the resource.
 | 
				
			||||||
 | 
					        By default this is the class's docstring,
 | 
				
			||||||
 | 
					        although this behaviour may be overridden."""
 | 
				
			||||||
 | 
					        return "%s" % self.__doc__
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    def resp_status_text(self):
 | 
				
			||||||
 | 
					        """Return reason text corrosponding to our HTTP response status code.
 | 
				
			||||||
 | 
					        Provided for convienience."""
 | 
				
			||||||
 | 
					        return STATUS_CODE_TEXT.get(self.resp_status, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def reverse(self, view, *args, **kwargs):
 | 
					    def reverse(self, view, *args, **kwargs):
 | 
				
			||||||
        """Return a fully qualified URI for a given view or resource, using the current request as the base URI.
 | 
					        """Return a fully qualified URI for a given view or resource, using the current request as the base URI.
 | 
				
			||||||
        TODO: Add SITEMAP option.
 | 
					        TODO: Add SITEMAP option.
 | 
				
			||||||
| 
						 | 
					@ -125,8 +142,14 @@ class Resource(object):
 | 
				
			||||||
        return method
 | 
					        return method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def authenticate(self):
 | 
				
			||||||
 | 
					        """..."""
 | 
				
			||||||
 | 
					        # user = ...
 | 
				
			||||||
 | 
					        # if anon_user and not anon_allowed_operations raise PermissionDenied
 | 
				
			||||||
 | 
					        # return 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_method_allowed(self, method):
 | 
					    def check_method_allowed(self, method):
 | 
				
			||||||
        """Ensure the request method is acceptable fot this resource."""
 | 
					        """Ensure the request method is acceptable for this resource."""
 | 
				
			||||||
        if not method in self.CALLMAP.keys():
 | 
					        if not method in self.CALLMAP.keys():
 | 
				
			||||||
            raise ResourceException(STATUS_501_NOT_IMPLEMENTED,
 | 
					            raise ResourceException(STATUS_501_NOT_IMPLEMENTED,
 | 
				
			||||||
                                    {'detail': 'Unknown or unsupported method \'%s\'' % method})
 | 
					                                    {'detail': 'Unknown or unsupported method \'%s\'' % method})
 | 
				
			||||||
| 
						 | 
					@ -137,13 +160,12 @@ class Resource(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def determine_form(self, data=None, is_response=False):
 | 
					    def get_bound_form(self, data=None, is_response=False):
 | 
				
			||||||
        """Optionally return a Django Form instance, which may be used for validation
 | 
					        """Optionally return a Django Form instance, which may be used for validation
 | 
				
			||||||
        and/or rendered by an HTML/XHTML emitter.
 | 
					        and/or rendered by an HTML/XHTML emitter.
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        If data is not None the form will be bound to data.  is_response indicates if data should be
 | 
					        If data is not None the form will be bound to data.  is_response indicates if data should be
 | 
				
			||||||
        treated as the input data (bind to client input) or the response data (bind to an existing object).
 | 
					        treated as the input data (bind to client input) or the response data (bind to an existing object)."""
 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        if self.form:
 | 
					        if self.form:
 | 
				
			||||||
            if data:
 | 
					            if data:
 | 
				
			||||||
                return self.form(data)
 | 
					                return self.form(data)
 | 
				
			||||||
| 
						 | 
					@ -156,15 +178,25 @@ class Resource(object):
 | 
				
			||||||
        """Perform any resource-specific data deserialization and/or validation
 | 
					        """Perform any resource-specific data deserialization and/or validation
 | 
				
			||||||
        after the initial HTTP content-type deserialization has taken place.
 | 
					        after the initial HTTP content-type deserialization has taken place.
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        Returns a tuple containing the cleaned up data, and optionally a form bound to that data.
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        By default this uses form validation to filter the basic input into the required types."""
 | 
					        By default this uses form validation to filter the basic input into the required types."""
 | 
				
			||||||
        if self.form is None:
 | 
					        if self.form is None:
 | 
				
			||||||
            return data
 | 
					            return (data, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        form_instance = self.get_bound_form(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not form_instance.is_valid():
 | 
				
			||||||
 | 
					            if not form_instance.errors:
 | 
				
			||||||
 | 
					                details = 'No content was supplied'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                details = dict((key, map(unicode, val)) for (key, val) in form_instance.errors.iteritems())
 | 
				
			||||||
 | 
					                if form_instance.non_field_errors():
 | 
				
			||||||
 | 
					                    details['_extra'] = self.form.non_field_errors()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not self.form.is_valid():
 | 
					 | 
				
			||||||
            details = dict((key, map(unicode, val)) for (key, val) in self.form.errors.iteritems())
 | 
					 | 
				
			||||||
            raise ResourceException(STATUS_400_BAD_REQUEST, {'detail': details})
 | 
					            raise ResourceException(STATUS_400_BAD_REQUEST, {'detail': details})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.form.cleaned_data
 | 
					        return (form_instance.cleaned_data, form_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def cleanup_response(self, data):
 | 
					    def cleanup_response(self, data):
 | 
				
			||||||
| 
						 | 
					@ -188,7 +220,7 @@ class Resource(object):
 | 
				
			||||||
            return self.parsers[content_type]
 | 
					            return self.parsers[content_type]
 | 
				
			||||||
        except KeyError:
 | 
					        except KeyError:
 | 
				
			||||||
            raise ResourceException(STATUS_415_UNSUPPORTED_MEDIA_TYPE,
 | 
					            raise ResourceException(STATUS_415_UNSUPPORTED_MEDIA_TYPE,
 | 
				
			||||||
                                    {'detail': 'Unsupported content type \'%s\'' % content_type})
 | 
					                                    {'detail': 'Unsupported media type \'%s\'' % content_type})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def determine_emitter(self, request):
 | 
					    def determine_emitter(self, request):
 | 
				
			||||||
| 
						 | 
					@ -253,13 +285,13 @@ class Resource(object):
 | 
				
			||||||
        5. serialize response data into response content, using standard HTTP content negotiation
 | 
					        5. serialize response data into response content, using standard HTTP content negotiation
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        emitter = None
 | 
					        emitter = None
 | 
				
			||||||
 | 
					        method = self.determine_method(request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # We make these attributes to allow for a certain amount of munging,
 | 
					        # We make these attributes to allow for a certain amount of munging,
 | 
				
			||||||
        # eg The HTML emitter needs to render this information
 | 
					        # eg The HTML emitter needs to render this information
 | 
				
			||||||
        self.method = self.determine_method(request)
 | 
					        self.request = request
 | 
				
			||||||
        self.form = None
 | 
					        self.form_instance = None
 | 
				
			||||||
        self.resp_status = None
 | 
					        self.resp_status = None
 | 
				
			||||||
        self.resp_content = None
 | 
					 | 
				
			||||||
        self.resp_headers = {}
 | 
					        self.resp_headers = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -267,32 +299,31 @@ class Resource(object):
 | 
				
			||||||
            mimetype, emitter = self.determine_emitter(request)
 | 
					            mimetype, emitter = self.determine_emitter(request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Ensure the requested operation is permitted on this resource
 | 
					            # Ensure the requested operation is permitted on this resource
 | 
				
			||||||
            self.check_method_allowed(self.method)
 | 
					            self.check_method_allowed(method)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Get the appropriate create/read/update/delete function
 | 
					            # Get the appropriate create/read/update/delete function
 | 
				
			||||||
            func = getattr(self, self.CALLMAP.get(self.method, ''))
 | 
					            func = getattr(self, self.CALLMAP.get(method, ''))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
            # Either generate the response data, deserializing and validating any request data
 | 
					            # Either generate the response data, deserializing and validating any request data
 | 
				
			||||||
            if self.method in ('PUT', 'POST'):
 | 
					            if method in ('PUT', 'POST'):
 | 
				
			||||||
                parser = self.determine_parser(request)
 | 
					                parser = self.determine_parser(request)
 | 
				
			||||||
                data = parser(self).parse(request.raw_post_data)
 | 
					                data = parser(self).parse(request.raw_post_data)
 | 
				
			||||||
                self.form = self.determine_form(data)
 | 
					                (data, self.form_instance) = self.cleanup_request(data)
 | 
				
			||||||
                data = self.cleanup_request(data)
 | 
					 | 
				
			||||||
                (self.resp_status, ret, self.resp_headers) = func(data, request.META, *args, **kwargs)
 | 
					                (self.resp_status, ret, self.resp_headers) = func(data, request.META, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                (self.resp_status, ret, self.resp_headers) = func(request.META, *args, **kwargs)
 | 
					                (self.resp_status, ret, self.resp_headers) = func(request.META, *args, **kwargs)
 | 
				
			||||||
                self.form = self.determine_form(ret, is_response=True)
 | 
					                self.form_instance = self.get_bound_form(ret, is_response=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        except ResourceException, exc:
 | 
					        except ResourceException, exc:
 | 
				
			||||||
            (self.resp_status, ret, self.resp_headers) = (exc.status, exc.content, exc.headers)
 | 
					            (self.resp_status, ret, self.resp_headers) = (exc.status, exc.content, exc.headers)
 | 
				
			||||||
            if emitter is None:
 | 
					            if emitter is None:
 | 
				
			||||||
                mimetype, emitter = self.emitters[0] 
 | 
					                mimetype, emitter = self.emitters[0] 
 | 
				
			||||||
            if self.form is None:
 | 
					            if self.form_instance is None:
 | 
				
			||||||
                self.form = self.determine_form()
 | 
					                self.form_instance = self.get_bound_form()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        # Always add the allow header
 | 
					        # Always add the allow header
 | 
				
			||||||
        self.resp_headers['Allow'] = ', '.join([self.REVERSE_CALLMAP[operation] for operation in self.allowed_operations])
 | 
					        self.resp_headers['Allow'] = ', '.join([self.REVERSE_CALLMAP[operation] for operation in self.allowed_operations])
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
| 
						 | 
					@ -315,17 +346,16 @@ from django.db.models.query import QuerySet
 | 
				
			||||||
from django.db.models import Model
 | 
					from django.db.models import Model
 | 
				
			||||||
import decimal
 | 
					import decimal
 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ModelResource(Resource):
 | 
					class ModelResource(Resource):
 | 
				
			||||||
    model = None
 | 
					    model = None
 | 
				
			||||||
    fields = None
 | 
					    fields = None
 | 
				
			||||||
    form_fields = None
 | 
					    form_fields = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def determine_form(self, data=None, is_response=False):
 | 
					    def get_bound_form(self, data=None, is_response=False):
 | 
				
			||||||
        """Return a form that may be used in validation and/or rendering an html emitter"""
 | 
					        """Return a form that may be used in validation and/or rendering an html emitter"""
 | 
				
			||||||
        if self.form:
 | 
					        if self.form:
 | 
				
			||||||
            return super(self.__class__, self).determine_form(data, is_response=is_response)
 | 
					            return super(self.__class__, self).get_bound_form(data, is_response=is_response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        elif self.model:
 | 
					        elif self.model:
 | 
				
			||||||
            class NewModelForm(ModelForm):
 | 
					            class NewModelForm(ModelForm):
 | 
				
			||||||
| 
						 | 
					@ -640,7 +670,7 @@ class ModelResource(Resource):
 | 
				
			||||||
class QueryModelResource(ModelResource):
 | 
					class QueryModelResource(ModelResource):
 | 
				
			||||||
    allowed_methods = ('read',)
 | 
					    allowed_methods = ('read',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def determine_form(self, data=None, is_response=False):
 | 
					    def get_bound_form(self, data=None, is_response=False):
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def read(self, headers={}, *args, **kwargs):
 | 
					    def read(self, headers={}, *args, **kwargs):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,26 +7,27 @@
 | 
				
			||||||
      pre {border: 1px solid black; padding: 1em; background: #ffd}
 | 
					      pre {border: 1px solid black; padding: 1em; background: #ffd}
 | 
				
			||||||
      div.action {padding: 0.5em 1em; margin-bottom: 0.5em; background: #ddf}
 | 
					      div.action {padding: 0.5em 1em; margin-bottom: 0.5em; background: #ddf}
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
 | 
					    <title>API - {{ resource.name }}</title>
 | 
				
			||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
  <body>
 | 
					  <body>
 | 
				
			||||||
    <h1>{{ resource_name }}</h1>
 | 
					    <h1>{{ resource.name }}</h1>
 | 
				
			||||||
    <p>{{ resource_doc }}</p>
 | 
					    <p>{{ resource.description }}</p>
 | 
				
			||||||
    <pre><b>{{ status }} {{ reason }}</b>{% autoescape off %}
 | 
					    <pre><b>{{ resource.resp_status }} {{ resource.resp_status_text }}</b>{% autoescape off %}
 | 
				
			||||||
{% for key, val in headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
 | 
					{% for key, val in resource.resp_headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
 | 
				
			||||||
{% endfor %}
 | 
					{% endfor %}
 | 
				
			||||||
{{ content|urlize_quoted_links }}    </pre>{% endautoescape %}
 | 
					{{ content|urlize_quoted_links }}    </pre>{% endautoescape %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% if 'read' in resource.allowed_operations %}
 | 
					{% if 'read' in resource.allowed_operations %}
 | 
				
			||||||
	<div class='action'>
 | 
						<div class='action'>
 | 
				
			||||||
		<a href='{{ request.path }}'>Read</a>
 | 
							<a href='{{ resource.request.path }}'>Read</a>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% if 'create' in resource.allowed_operations %}
 | 
					{% if 'create' in resource.allowed_operations %}
 | 
				
			||||||
	<div class='action'>
 | 
						<div class='action'>
 | 
				
			||||||
		<form action="{{ request.path }}" method="POST">
 | 
							<form action="{{ resource.request.path }}" method="POST">
 | 
				
			||||||
		    {% csrf_token %}
 | 
							    {% csrf_token %}
 | 
				
			||||||
			{{ create_form.as_p }}
 | 
								{{ resource.form_instance.as_p }}
 | 
				
			||||||
			<input type="submit" value="Create" />
 | 
								<input type="submit" value="Create" />
 | 
				
			||||||
		</form>
 | 
							</form>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
| 
						 | 
					@ -34,10 +35,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% if 'update' in resource.allowed_operations %}
 | 
					{% if 'update' in resource.allowed_operations %}
 | 
				
			||||||
	<div class='action'>
 | 
						<div class='action'>
 | 
				
			||||||
		<form action="{{ request.path }}" method="POST">
 | 
							<form action="{{ resource.request.path }}" method="POST">
 | 
				
			||||||
			<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="PUT" />
 | 
								<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="PUT" />
 | 
				
			||||||
			{% csrf_token %}
 | 
								{% csrf_token %}
 | 
				
			||||||
			{{ create_form.as_p }}
 | 
								{{ resource.form_instance.as_p }}
 | 
				
			||||||
			<input type="submit" value="Update" />
 | 
								<input type="submit" value="Update" />
 | 
				
			||||||
		</form>
 | 
							</form>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
| 
						 | 
					@ -45,7 +46,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% if 'delete' in resource.allowed_operations %}
 | 
					{% if 'delete' in resource.allowed_operations %}
 | 
				
			||||||
	<div class='action'>
 | 
						<div class='action'>
 | 
				
			||||||
		<form action="{{ request.path }}" method="POST">
 | 
							<form action="{{ resource.request.path }}" method="POST">
 | 
				
			||||||
		    {% csrf_token %}
 | 
							    {% csrf_token %}
 | 
				
			||||||
			<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="DELETE" />
 | 
								<input type="hidden" name="{{ resource.METHOD_PARAM}}" value="DELETE" />
 | 
				
			||||||
			<input type="submit" value="Delete" />
 | 
								<input type="submit" value="Delete" />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,7 @@
 | 
				
			||||||
{% autoescape off %}HTTP Status {{ status }}
 | 
					{{ resource.name }}
 | 
				
			||||||
{% for key, val in headers.items %}{{ key }}: {{ val }}
 | 
					{{ resource.description }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% autoescape off %}HTTP/1.0 {{ resource.resp_status }} {{ resource.resp_status_text }}
 | 
				
			||||||
 | 
					{% for key, val in resource.resp_headers.items %}{{ key }}: {{ val }}
 | 
				
			||||||
{% endfor %}
 | 
					{% endfor %}
 | 
				
			||||||
{{ content }}{% endautoescape %}
 | 
					{{ content }}{% endautoescape %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
from rest.resource import Resource, ModelResource, QueryModelResource
 | 
					from rest.resource import Resource, ModelResource, QueryModelResource
 | 
				
			||||||
from testapp.models import BlogPost, Comment
 | 
					from testapp.models import BlogPost, Comment
 | 
				
			||||||
 
 | 
					
 | 
				
			||||||
 | 
					##### Root Resource #####
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RootResource(Resource):
 | 
					class RootResource(Resource):
 | 
				
			||||||
    """This is the top level resource for the API.
 | 
					    """This is the top level resource for the API.
 | 
				
			||||||
    All the sub-resources are discoverable from here."""
 | 
					    All the sub-resources are discoverable from here."""
 | 
				
			||||||
| 
						 | 
					@ -11,49 +13,53 @@ class RootResource(Resource):
 | 
				
			||||||
                      'blog-post': self.reverse(BlogPostCreator)}, {})
 | 
					                      'blog-post': self.reverse(BlogPostCreator)}, {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Blog Post Resources
 | 
					##### Blog Post Resources #####
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BLOG_POST_FIELDS = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BlogPostList(QueryModelResource):
 | 
					class BlogPostList(QueryModelResource):
 | 
				
			||||||
    """A resource which lists all existing blog posts."""
 | 
					    """A resource which lists all existing blog posts."""
 | 
				
			||||||
    allowed_operations = ('read', )
 | 
					    allowed_operations = ('read', )
 | 
				
			||||||
    model = BlogPost
 | 
					    model = BlogPost
 | 
				
			||||||
 | 
					    fields = BLOG_POST_FIELDS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BlogPostCreator(ModelResource):
 | 
					class BlogPostCreator(ModelResource):
 | 
				
			||||||
    """A resource with which blog posts may be created."""
 | 
					    """A resource with which blog posts may be created."""
 | 
				
			||||||
    allowed_operations = ('create',)
 | 
					    allowed_operations = ('create',)
 | 
				
			||||||
    model = BlogPost
 | 
					    model = BlogPost
 | 
				
			||||||
    fields = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
 | 
					    fields = BLOG_POST_FIELDS
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BlogPostInstance(ModelResource):
 | 
					class BlogPostInstance(ModelResource):
 | 
				
			||||||
    """A resource which represents a single blog post."""
 | 
					    """A resource which represents a single blog post."""
 | 
				
			||||||
    allowed_operations = ('read', 'update', 'delete')
 | 
					    allowed_operations = ('read', 'update', 'delete')
 | 
				
			||||||
    model = BlogPost
 | 
					    model = BlogPost
 | 
				
			||||||
    fields = ('created', 'title', 'slug', 'content', 'absolute_url', 'comment_url', 'comments_url')
 | 
					    fields = BLOG_POST_FIELDS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Comment Resources
 | 
					##### Comment Resources #####
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMENT_FIELDS = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CommentList(QueryModelResource):
 | 
					class CommentList(QueryModelResource):
 | 
				
			||||||
    """A resource which lists all existing comments for a given blog post."""
 | 
					    """A resource which lists all existing comments for a given blog post."""
 | 
				
			||||||
    allowed_operations = ('read', )
 | 
					    allowed_operations = ('read', )
 | 
				
			||||||
    model = Comment
 | 
					    model = Comment
 | 
				
			||||||
 | 
					    fields = COMMENT_FIELDS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CommentCreator(ModelResource):
 | 
					class CommentCreator(ModelResource):
 | 
				
			||||||
    """A resource with which blog comments may be created for a given blog post."""
 | 
					    """A resource with which blog comments may be created for a given blog post."""
 | 
				
			||||||
    allowed_operations = ('create',)
 | 
					    allowed_operations = ('create',)
 | 
				
			||||||
    model = Comment
 | 
					    model = Comment
 | 
				
			||||||
    fields = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url')
 | 
					    fields = COMMENT_FIELDS
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CommentInstance(ModelResource):
 | 
					class CommentInstance(ModelResource):
 | 
				
			||||||
    """A resource which represents a single comment."""
 | 
					    """A resource which represents a single comment."""
 | 
				
			||||||
    allowed_operations = ('read', 'update', 'delete')
 | 
					    allowed_operations = ('read', 'update', 'delete')
 | 
				
			||||||
    model = Comment
 | 
					    model = Comment
 | 
				
			||||||
    fields = ('username', 'comment', 'created', 'rating', 'absolute_url', 'blogpost_url')
 | 
					    fields = COMMENT_FIELDS
 | 
				
			||||||
    
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#'read-only-api': self.reverse(ReadOnlyResource),
 | 
					#'read-only-api': self.reverse(ReadOnlyResource),
 | 
				
			||||||
#                      'write-only-api': self.reverse(WriteOnlyResource),
 | 
					#                      'write-only-api': self.reverse(WriteOnlyResource),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user