mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 09:57:55 +03:00 
			
		
		
		
	yet more API cleanup
This commit is contained in:
		
							parent
							
								
									15f9e7c566
								
							
						
					
					
						commit
						b5b231a874
					
				| 
						 | 
				
			
			@ -48,23 +48,18 @@ class RequestMixin(object):
 | 
			
		|||
 | 
			
		||||
    parsers = ()
 | 
			
		||||
 | 
			
		||||
    def _get_method(self):
 | 
			
		||||
    @property
 | 
			
		||||
    def method(self):
 | 
			
		||||
        """
 | 
			
		||||
        Returns the HTTP method for the current view.
 | 
			
		||||
        Returns the HTTP method.
 | 
			
		||||
        """
 | 
			
		||||
        if not hasattr(self, '_method'):
 | 
			
		||||
            self._method = self.request.method
 | 
			
		||||
        return self._method
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _set_method(self, method):
 | 
			
		||||
        """
 | 
			
		||||
        Set the method for the current view.
 | 
			
		||||
        """
 | 
			
		||||
        self._method = method
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _get_content_type(self):
 | 
			
		||||
    @property
 | 
			
		||||
    def content_type(self):
 | 
			
		||||
        """
 | 
			
		||||
        Returns the content type header.
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -73,11 +68,32 @@ class RequestMixin(object):
 | 
			
		|||
        return self._content_type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _set_content_type(self, content_type):
 | 
			
		||||
    @property
 | 
			
		||||
    def DATA(self):
 | 
			
		||||
        """
 | 
			
		||||
        Set the content type header.
 | 
			
		||||
        Returns the request data.
 | 
			
		||||
        """
 | 
			
		||||
        self._content_type = content_type
 | 
			
		||||
        if not hasattr(self, '_data'):
 | 
			
		||||
            self._load_data_and_files()
 | 
			
		||||
        return self._data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def FILES(self):
 | 
			
		||||
        """
 | 
			
		||||
        Returns the request files.
 | 
			
		||||
        """
 | 
			
		||||
        if not hasattr(self, '_files'):
 | 
			
		||||
            self._load_data_and_files()
 | 
			
		||||
        return self._files
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _load_data_and_files(self):
 | 
			
		||||
        """
 | 
			
		||||
        Parse the request content into self.DATA and self.FILES.
 | 
			
		||||
        """
 | 
			
		||||
        stream = self._get_stream()
 | 
			
		||||
        (self._data, self._files) = self._parse(stream, self.content_type)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _get_stream(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -134,27 +150,6 @@ class RequestMixin(object):
 | 
			
		|||
        return self._stream
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _set_stream(self, stream):
 | 
			
		||||
        """
 | 
			
		||||
        Set the stream representing the request body.
 | 
			
		||||
        """
 | 
			
		||||
        self._stream = stream
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def _load_data_and_files(self):
 | 
			
		||||
        (self._data, self._files) = self._parse(self.stream, self.content_type)
 | 
			
		||||
 | 
			
		||||
    def _get_data(self):
 | 
			
		||||
        if not hasattr(self, '_data'):
 | 
			
		||||
            self._load_data_and_files()
 | 
			
		||||
        return self._data
 | 
			
		||||
 | 
			
		||||
    def _get_files(self):
 | 
			
		||||
        if not hasattr(self, '_files'):
 | 
			
		||||
            self._load_data_and_files()
 | 
			
		||||
        return self._files
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # TODO: Modify this so that it happens implictly, rather than being called explicitly
 | 
			
		||||
    # ie accessing any of .DATA, .FILES, .content_type, .method will force
 | 
			
		||||
    # form overloading.
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +159,10 @@ class RequestMixin(object):
 | 
			
		|||
        If it is then alter self.method, self.content_type, self.CONTENT to reflect that rather than simply
 | 
			
		||||
        delegating them to the original request.
 | 
			
		||||
        """
 | 
			
		||||
        if not self._USE_FORM_OVERLOADING or self.method != 'POST' or not is_form_media_type(self.content_type):
 | 
			
		||||
 | 
			
		||||
        # We only need to use form overloading on form POST requests
 | 
			
		||||
        content_type = self.request.META.get('HTTP_CONTENT_TYPE', self.request.META.get('CONTENT_TYPE', ''))
 | 
			
		||||
        if not self._USE_FORM_OVERLOADING or self.request.method != 'POST' or not not is_form_media_type(content_type):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # Temporarily switch to using the form parsers, then parse the content
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +173,7 @@ class RequestMixin(object):
 | 
			
		|||
 | 
			
		||||
        # Method overloading - change the method and remove the param from the content
 | 
			
		||||
        if self._METHOD_PARAM in content:
 | 
			
		||||
            self.method = content[self._METHOD_PARAM].upper()
 | 
			
		||||
            self._method = content[self._METHOD_PARAM].upper()
 | 
			
		||||
            del self._data[self._METHOD_PARAM]
 | 
			
		||||
 | 
			
		||||
        # Content overloading - rewind the stream and modify the content type
 | 
			
		||||
| 
						 | 
				
			
			@ -207,28 +205,21 @@ class RequestMixin(object):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def parsed_media_types(self):
 | 
			
		||||
    def _parsed_media_types(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return an list of all the media types that this view can parse.
 | 
			
		||||
        Return a list of all the media types that this view can parse.
 | 
			
		||||
        """
 | 
			
		||||
        return [parser.media_type for parser in self.parsers]
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    @property
 | 
			
		||||
    def default_parser(self):
 | 
			
		||||
    def _default_parser(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return the view's most preferred parser.
 | 
			
		||||
        (This has no behavioral effect, but is may be used by documenting renderers)
 | 
			
		||||
        Return the view's default parser.
 | 
			
		||||
        """        
 | 
			
		||||
        return self.parsers[0]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    method = property(_get_method, _set_method)
 | 
			
		||||
    content_type = property(_get_content_type, _set_content_type)
 | 
			
		||||
    stream = property(_get_stream, _set_stream)
 | 
			
		||||
    DATA = property(_get_data)
 | 
			
		||||
    FILES = property(_get_files)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
########## ResponseMixin ##########
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -240,8 +231,9 @@ class ResponseMixin(object):
 | 
			
		|||
    Also supports overriding the content type by specifying an _accept= parameter in the URL.
 | 
			
		||||
    Ignores Accept headers from Internet Explorer user agents and uses a sensible browser Accept header instead.
 | 
			
		||||
    """
 | 
			
		||||
    ACCEPT_QUERY_PARAM = '_accept'        # Allow override of Accept header in URL query params
 | 
			
		||||
    REWRITE_IE_ACCEPT_HEADER = True
 | 
			
		||||
 | 
			
		||||
    _ACCEPT_QUERY_PARAM = '_accept'        # Allow override of Accept header in URL query params
 | 
			
		||||
    _IGNORE_IE_ACCEPT_HEADER = True
 | 
			
		||||
 | 
			
		||||
    renderers = ()
 | 
			
		||||
     
 | 
			
		||||
| 
						 | 
				
			
			@ -256,7 +248,7 @@ class ResponseMixin(object):
 | 
			
		|||
        try:
 | 
			
		||||
            renderer = self._determine_renderer(self.request)
 | 
			
		||||
        except ErrorResponse, exc:
 | 
			
		||||
            renderer = self.default_renderer
 | 
			
		||||
            renderer = self._default_renderer
 | 
			
		||||
            response = exc.response
 | 
			
		||||
        
 | 
			
		||||
        # Serialize the response content
 | 
			
		||||
| 
						 | 
				
			
			@ -287,10 +279,10 @@ class ResponseMixin(object):
 | 
			
		|||
        See: RFC 2616, Section 14 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        if self.ACCEPT_QUERY_PARAM and request.GET.get(self.ACCEPT_QUERY_PARAM, None):
 | 
			
		||||
        if self._ACCEPT_QUERY_PARAM and request.GET.get(self._ACCEPT_QUERY_PARAM, None):
 | 
			
		||||
            # Use _accept parameter override
 | 
			
		||||
            accept_list = [request.GET.get(self.ACCEPT_QUERY_PARAM)]
 | 
			
		||||
        elif (self.REWRITE_IE_ACCEPT_HEADER and
 | 
			
		||||
            accept_list = [request.GET.get(self._ACCEPT_QUERY_PARAM)]
 | 
			
		||||
        elif (self._IGNORE_IE_ACCEPT_HEADER and
 | 
			
		||||
              request.META.has_key('HTTP_USER_AGENT') and
 | 
			
		||||
              MSIE_USER_AGENT_REGEX.match(request.META['HTTP_USER_AGENT'])):
 | 
			
		||||
            accept_list = ['text/html', '*/*']
 | 
			
		||||
| 
						 | 
				
			
			@ -299,7 +291,7 @@ class ResponseMixin(object):
 | 
			
		|||
            accept_list = request.META["HTTP_ACCEPT"].split(',')
 | 
			
		||||
        else:
 | 
			
		||||
            # No accept header specified
 | 
			
		||||
            return self.default_renderer
 | 
			
		||||
            return self._default_renderer
 | 
			
		||||
        
 | 
			
		||||
        # Parse the accept header into a dict of {qvalue: set of media types}
 | 
			
		||||
        # We ignore mietype parameters
 | 
			
		||||
| 
						 | 
				
			
			@ -340,25 +332,24 @@ class ResponseMixin(object):
 | 
			
		|||
 | 
			
		||||
            # Return default
 | 
			
		||||
            if '*/*' in accept_set:
 | 
			
		||||
                return self.default_renderer
 | 
			
		||||
                return self._default_renderer
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
        raise ErrorResponse(status.HTTP_406_NOT_ACCEPTABLE,
 | 
			
		||||
                                {'detail': 'Could not satisfy the client\'s Accept header',
 | 
			
		||||
                                 'available_types': self.rendered_media_types})
 | 
			
		||||
                                 'available_types': self._rendered_media_types})
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rendered_media_types(self):
 | 
			
		||||
    def _rendered_media_types(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return an list of all the media types that this resource can render.
 | 
			
		||||
        Return an list of all the media types that this view can render.
 | 
			
		||||
        """
 | 
			
		||||
        return [renderer.media_type for renderer in self.renderers]
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def default_renderer(self):
 | 
			
		||||
    def _default_renderer(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return the resource's most preferred renderer.
 | 
			
		||||
        (This renderer is used if the client does not send and Accept: header, or sends Accept: */*)
 | 
			
		||||
        Return the view's default renderer.
 | 
			
		||||
        """
 | 
			
		||||
        return self.renderers[0]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -367,8 +358,7 @@ class ResponseMixin(object):
 | 
			
		|||
 | 
			
		||||
class AuthMixin(object):
 | 
			
		||||
    """
 | 
			
		||||
    Simple mixin class to provide authentication and permission checking,
 | 
			
		||||
    by adding a set of authentication and permission classes on a ``View``.
 | 
			
		||||
    Simple mixin class to add authentication and permission checking to a ``View`` class.
 | 
			
		||||
    """
 | 
			
		||||
    authentication = ()
 | 
			
		||||
    permissions = ()
 | 
			
		||||
| 
						 | 
				
			
			@ -408,12 +398,12 @@ class ResourceMixin(object):
 | 
			
		|||
    @property
 | 
			
		||||
    def CONTENT(self):
 | 
			
		||||
        if not hasattr(self, '_content'):
 | 
			
		||||
            self._content = self._get_content(self.DATA, self.FILES)
 | 
			
		||||
            self._content = self._get_content()
 | 
			
		||||
        return self._content
 | 
			
		||||
 | 
			
		||||
    def _get_content(self, data, files):
 | 
			
		||||
    def _get_content(self):
 | 
			
		||||
        resource = self.resource(self)
 | 
			
		||||
        return resource.validate(data, files)
 | 
			
		||||
        return resource.validate(self.DATA, self.FILES)
 | 
			
		||||
 | 
			
		||||
    def get_bound_form(self, content=None):
 | 
			
		||||
        resource = self.resource(self)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ class BaseRenderer(object):
 | 
			
		|||
        should render the output.
 | 
			
		||||
        EG: 'application/json; indent=4'
 | 
			
		||||
 | 
			
		||||
        By default render simply returns the ouput as-is.
 | 
			
		||||
        By default render simply returns the output as-is.
 | 
			
		||||
        Override this method to provide for other behavior.
 | 
			
		||||
        """
 | 
			
		||||
        if obj is None:
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +61,41 @@ class BaseRenderer(object):
 | 
			
		|||
        return str(obj)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JSONRenderer(BaseRenderer):
 | 
			
		||||
    """
 | 
			
		||||
    Renderer which serializes to JSON
 | 
			
		||||
    """
 | 
			
		||||
    media_type = 'application/json'
 | 
			
		||||
 | 
			
		||||
    def render(self, obj=None, media_type=None):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return ''
 | 
			
		||||
 | 
			
		||||
        # If the media type looks like 'application/json; indent=4', then
 | 
			
		||||
        # pretty print the result.
 | 
			
		||||
        indent = get_media_type_params(media_type).get('indent', None)
 | 
			
		||||
        sort_keys = False
 | 
			
		||||
        try:
 | 
			
		||||
            indent = max(min(int(indent), 8), 0)
 | 
			
		||||
            sort_keys = True
 | 
			
		||||
        except (ValueError, TypeError):
 | 
			
		||||
            indent = None
 | 
			
		||||
 | 
			
		||||
        return json.dumps(obj, indent=indent, sort_keys=sort_keys)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XMLRenderer(BaseRenderer):
 | 
			
		||||
    """
 | 
			
		||||
    Renderer which serializes to XML.
 | 
			
		||||
    """
 | 
			
		||||
    media_type = 'application/xml'
 | 
			
		||||
 | 
			
		||||
    def render(self, obj=None, media_type=None):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return ''
 | 
			
		||||
        return dict2xml(obj)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TemplateRenderer(BaseRenderer):
 | 
			
		||||
    """
 | 
			
		||||
    A Base class provided for convenience.
 | 
			
		||||
| 
						 | 
				
			
			@ -161,8 +196,8 @@ class DocumentingTemplateRenderer(BaseRenderer):
 | 
			
		|||
                Add the fields dynamically."""
 | 
			
		||||
                super(GenericContentForm, self).__init__()
 | 
			
		||||
 | 
			
		||||
                contenttype_choices = [(media_type, media_type) for media_type in view.parsed_media_types]
 | 
			
		||||
                initial_contenttype = view.default_parser.media_type
 | 
			
		||||
                contenttype_choices = [(media_type, media_type) for media_type in view._parsed_media_types]
 | 
			
		||||
                initial_contenttype = view._default_parser.media_type
 | 
			
		||||
 | 
			
		||||
                self.fields[view._CONTENTTYPE_PARAM] = forms.ChoiceField(label='Content Type',
 | 
			
		||||
                                                                         choices=contenttype_choices,
 | 
			
		||||
| 
						 | 
				
			
			@ -204,16 +239,19 @@ class DocumentingTemplateRenderer(BaseRenderer):
 | 
			
		|||
        template = loader.get_template(self.template)
 | 
			
		||||
        context = RequestContext(self.view.request, {
 | 
			
		||||
            'content': content,
 | 
			
		||||
            'resource': self.view,        # TODO: rename to view
 | 
			
		||||
            'view': self.view,
 | 
			
		||||
            'request': self.view.request, # TODO: remove
 | 
			
		||||
            'response': self.view.response,
 | 
			
		||||
            'description': description,
 | 
			
		||||
            'name': name,
 | 
			
		||||
            'markeddown': markeddown,
 | 
			
		||||
            'breadcrumblist': breadcrumb_list,
 | 
			
		||||
            'available_media_types': self.view._rendered_media_types,
 | 
			
		||||
            'form': form_instance,
 | 
			
		||||
            'login_url': login_url,
 | 
			
		||||
            'logout_url': logout_url,
 | 
			
		||||
            'ACCEPT_PARAM': self.view._ACCEPT_QUERY_PARAM,
 | 
			
		||||
            'METHOD_PARAM': self.view._METHOD_PARAM,
 | 
			
		||||
            'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX
 | 
			
		||||
        })
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -228,39 +266,6 @@ class DocumentingTemplateRenderer(BaseRenderer):
 | 
			
		|||
        return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JSONRenderer(BaseRenderer):
 | 
			
		||||
    """
 | 
			
		||||
    Renderer which serializes to JSON
 | 
			
		||||
    """
 | 
			
		||||
    media_type = 'application/json'
 | 
			
		||||
 | 
			
		||||
    def render(self, obj=None, media_type=None):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return ''
 | 
			
		||||
 | 
			
		||||
        indent = get_media_type_params(media_type).get('indent', None)
 | 
			
		||||
        if indent is not None:
 | 
			
		||||
            try:
 | 
			
		||||
                indent = int(indent)
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                indent = None
 | 
			
		||||
 | 
			
		||||
        sort_keys = indent and True or False
 | 
			
		||||
        return json.dumps(obj, indent=indent, sort_keys=sort_keys)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XMLRenderer(BaseRenderer):
 | 
			
		||||
    """
 | 
			
		||||
    Renderer which serializes to XML.
 | 
			
		||||
    """
 | 
			
		||||
    media_type = 'application/xml'
 | 
			
		||||
 | 
			
		||||
    def render(self, obj=None, media_type=None):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return ''
 | 
			
		||||
        return dict2xml(obj)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DocumentingHTMLRenderer(DocumentingTemplateRenderer):
 | 
			
		||||
    """
 | 
			
		||||
    Renderer which provides a browsable HTML interface for an API.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,14 +42,14 @@
 | 
			
		|||
{% endfor %}
 | 
			
		||||
{{ content|urlize_quoted_links }}</pre>{% endautoescape %}</div>
 | 
			
		||||
 | 
			
		||||
	{% if 'GET' in resource.allowed_methods %}
 | 
			
		||||
	{% if 'GET' in view.allowed_methods %}
 | 
			
		||||
			<form>
 | 
			
		||||
				<fieldset class='module aligned'>
 | 
			
		||||
				<h2>GET {{ name }}</h2>
 | 
			
		||||
				<div class='submit-row' style='margin: 0; border: 0'>
 | 
			
		||||
				<a href='{{ request.path }}' rel="nofollow" style='float: left'>GET</a>
 | 
			
		||||
				{% for media_type in resource.rendered_media_types %}
 | 
			
		||||
				  {% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %}
 | 
			
		||||
				{% for media_type in available_media_types %}
 | 
			
		||||
				  {% with ACCEPT_PARAM|add:"="|add:media_type as param %}
 | 
			
		||||
				    [<a href='{{ request.path|add_query_param:param }}' rel="nofollow">{{ media_type }}</a>]
 | 
			
		||||
				  {% endwith %}
 | 
			
		||||
				{% endfor %}
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +63,8 @@
 | 
			
		|||
	              *** (We could display only the POST form if method tunneling is disabled, but I think ***
 | 
			
		||||
	              ***  the user experience would be confusing, so we simply turn all forms off.         *** {% endcomment %}
 | 
			
		||||
	
 | 
			
		||||
	{% if resource.METHOD_PARAM and form %}
 | 
			
		||||
		{% if 'POST' in resource.allowed_methods %}
 | 
			
		||||
	{% if METHOD_PARAM and form %}
 | 
			
		||||
		{% if 'POST' in view.allowed_methods %}
 | 
			
		||||
				<form action="{{ request.path }}" method="post" {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
 | 
			
		||||
				<fieldset class='module aligned'>
 | 
			
		||||
					<h2>POST {{ name }}</h2>
 | 
			
		||||
| 
						 | 
				
			
			@ -85,11 +85,11 @@
 | 
			
		|||
				</form>
 | 
			
		||||
		{% endif %}
 | 
			
		||||
		
 | 
			
		||||
		{% if 'PUT' in resource.allowed_methods %}
 | 
			
		||||
		{% if 'PUT' in view.allowed_methods %}
 | 
			
		||||
				<form action="{{ request.path }}" method="post" {% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
 | 
			
		||||
				<fieldset class='module aligned'>
 | 
			
		||||
					<h2>PUT {{ name }}</h2>
 | 
			
		||||
					<input type="hidden" name="{{ resource.METHOD_PARAM }}" value="PUT" />
 | 
			
		||||
					<input type="hidden" name="{{ METHOD_PARAM }}" value="PUT" />
 | 
			
		||||
					{% csrf_token %}
 | 
			
		||||
					{{ form.non_field_errors }}
 | 
			
		||||
					{% for field in form %}
 | 
			
		||||
| 
						 | 
				
			
			@ -107,12 +107,12 @@
 | 
			
		|||
				</form>
 | 
			
		||||
		{% endif %}
 | 
			
		||||
		
 | 
			
		||||
		{% if 'DELETE' in resource.allowed_methods %}
 | 
			
		||||
		{% if 'DELETE' in view.allowed_methods %}
 | 
			
		||||
				<form action="{{ request.path }}" method="post">
 | 
			
		||||
				<fieldset class='module aligned'>			
 | 
			
		||||
					<h2>DELETE {{ name }}</h2>
 | 
			
		||||
				    {% csrf_token %}
 | 
			
		||||
					<input type="hidden" name="{{ resource.METHOD_PARAM }}" value="DELETE" />
 | 
			
		||||
					<input type="hidden" name="{{ METHOD_PARAM }}" value="DELETE" />
 | 
			
		||||
					<div class='submit-row' style='margin: 0; border: 0'>			
 | 
			
		||||
					  <input type="submit" value="DELETE" class="default" />
 | 
			
		||||
					</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,9 +40,9 @@ class UserAgentMungingTest(TestCase):
 | 
			
		|||
            self.assertEqual(resp['Content-Type'], 'text/html')
 | 
			
		||||
 | 
			
		||||
    def test_dont_rewrite_msie_accept_header(self):
 | 
			
		||||
        """Turn off REWRITE_IE_ACCEPT_HEADER, send MSIE user agent strings and ensure
 | 
			
		||||
        """Turn off _IGNORE_IE_ACCEPT_HEADER, send MSIE user agent strings and ensure
 | 
			
		||||
        that we get a JSON response if we set a */* accept header."""
 | 
			
		||||
        view = self.MockView.as_view(REWRITE_IE_ACCEPT_HEADER=False)
 | 
			
		||||
        view = self.MockView.as_view(_IGNORE_IE_ACCEPT_HEADER=False)
 | 
			
		||||
 | 
			
		||||
        for user_agent in (MSIE_9_USER_AGENT,
 | 
			
		||||
                           MSIE_8_USER_AGENT,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ from django.test import TestCase
 | 
			
		|||
from django import forms
 | 
			
		||||
from djangorestframework.compat import RequestFactory
 | 
			
		||||
from djangorestframework.views import BaseView
 | 
			
		||||
from djangorestframework.resource import FormResource
 | 
			
		||||
from djangorestframework.resources import FormResource
 | 
			
		||||
import StringIO
 | 
			
		||||
 | 
			
		||||
class UploadFilesTests(TestCase):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ from djangorestframework.compat import RequestFactory
 | 
			
		|||
from djangorestframework.validators import BaseValidator, FormValidator, ModelFormValidator
 | 
			
		||||
from djangorestframework.response import ErrorResponse
 | 
			
		||||
from djangorestframework.views import BaseView
 | 
			
		||||
from djangorestframework.resource import Resource
 | 
			
		||||
from djangorestframework.resources import Resource
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestValidatorMixinInterfaces(TestCase):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ from django.views.decorators.csrf import csrf_exempt
 | 
			
		|||
from djangorestframework.compat import View
 | 
			
		||||
from djangorestframework.response import Response, ErrorResponse
 | 
			
		||||
from djangorestframework.mixins import *
 | 
			
		||||
from djangorestframework import resource, renderers, parsers, authentication, permissions, validators, status
 | 
			
		||||
from djangorestframework import resources, renderers, parsers, authentication, permissions, status
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = (
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
 | 
			
		|||
    Performs request deserialization, response serialization, authentication and input validation."""
 | 
			
		||||
 | 
			
		||||
    # Use the base resource by default
 | 
			
		||||
    resource = resource.Resource
 | 
			
		||||
    resource = resources.Resource
 | 
			
		||||
 | 
			
		||||
    # List of renderers the resource can serialize the response with, ordered by preference.
 | 
			
		||||
    renderers = ( renderers.JSONRenderer,
 | 
			
		||||
| 
						 | 
				
			
			@ -36,9 +36,6 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
 | 
			
		|||
                parsers.FormParser,
 | 
			
		||||
                parsers.MultiPartParser )
 | 
			
		||||
 | 
			
		||||
    # List of validators to validate, cleanup and normalize the request content    
 | 
			
		||||
    validators = ( validators.FormValidator, )
 | 
			
		||||
 | 
			
		||||
    # List of all authenticating methods to attempt.
 | 
			
		||||
    authentication = ( authentication.UserLoggedInAuthenticaton,
 | 
			
		||||
                       authentication.BasicAuthenticaton )
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +51,9 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
 | 
			
		|||
 | 
			
		||||
    @property
 | 
			
		||||
    def allowed_methods(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return the list of allowed HTTP methods, uppercased.
 | 
			
		||||
        """
 | 
			
		||||
        return [method.upper() for method in self.http_method_names if hasattr(self, method)]
 | 
			
		||||
 | 
			
		||||
    def http_method_not_allowed(self, request, *args, **kwargs):
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +61,7 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
 | 
			
		|||
        Return an HTTP 405 error if an operation is called which does not have a handler method.
 | 
			
		||||
        """
 | 
			
		||||
        raise ErrorResponse(status.HTTP_405_METHOD_NOT_ALLOWED,
 | 
			
		||||
                                {'detail': 'Method \'%s\' not allowed on this resource.' % self.method})
 | 
			
		||||
                            {'detail': 'Method \'%s\' not allowed on this resource.' % self.method})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # Note: session based authentication is explicitly CSRF validated,
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
 | 
			
		|||
 | 
			
		||||
class ModelView(BaseView):
 | 
			
		||||
    """A RESTful view that maps to a model in the database."""
 | 
			
		||||
    validators = (validators.ModelFormValidator,)
 | 
			
		||||
    resource = resources.ModelResource
 | 
			
		||||
 | 
			
		||||
class InstanceModelView(ReadModelMixin, UpdateModelMixin, DeleteModelMixin, ModelView):
 | 
			
		||||
    """A view which provides default operations for read/update/delete against a model instance."""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user