3
=^`G                 @   s
  d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ ddlmZ ddlmZ ddlm Z  ddl!m"Z" ddl#m$Z$ dd Z%dddZ&dd Z'dd Z(G dd deZ)dS )zL
Provides an APIView class that is the base of all views in REST framework.
    )unicode_literals)settings)PermissionDenied)
connectionmodelstransaction)Http404)HttpResponseBase)cc_delim_repatch_vary_headers)
smart_text)csrf_exempt)View)
exceptionsstatus)Request)Response)DefaultSchema)api_settings)
formattingc             C   sb   t | dd}|dk	r|S | jj}tj|d}tj|d}tj|}t | dd}|r^|d| 7 }|S )z
    Given a view instance, return a textual name to represent the view.
    This name is used in the browsable API, and in OPTIONS responses.

    This function is the default for the `VIEW_NAME_FUNCTION` setting.
    nameNr   ZViewSetsuffix )getattr	__class____name__r   Zremove_trailing_stringZcamelcase_to_spaces)viewr   r    r   C/tmp/pip-build-8app2_gc/djangorestframework/rest_framework/views.pyget_view_name   s    
r   Fc             C   s@   t | dd}|dkr | jjpd}tjt|}|r<tj|S |S )z
    Given a view instance, return a textual description to represent the view.
    This name is used in the browsable API, and in OPTIONS responses.

    This function is the default for the `VIEW_DESCRIPTION_FUNCTION` setting.
    descriptionN )r   r   __doc__r   dedentr   Zmarkup_description)r   htmlr    r   r   r   get_view_description1   s    
r%   c              C   s&   t jjdd} | r"t jr"tjd d S )NZATOMIC_REQUESTSFT)r   Zsettings_dictgetZin_atomic_blockr   set_rollback)Zatomic_requestsr   r   r   r'   C   s    
r'   c             C   s   t | trtj } nt | tr&tj } t | tjri }t| ddrL| j|d< t| ddrfd| j |d< t | j	t
tfr~| j	}n
d| j	i}t  t|| j|dS dS )	a4  
    Returns the response that should be used for any given exception.

    By default we handle the REST framework `APIException`, and also
    Django's built-in `Http404` and `PermissionDenied` exceptions.

    Any unhandled exceptions may return `None`, which will cause a 500 error
    to be raised.
    auth_headerNzWWW-Authenticatewaitz%dzRetry-Afterdetail)r   headers)
isinstancer   r   ZNotFoundr   ZAPIExceptionr   r(   r)   r*   listdictr'   r   status_code)exccontextr+   datar   r   r   exception_handlerI   s     





r3   c                   sh  e Zd ZejZejZejZ	ej
ZejZejZejZejZeZe Ze fddZedd Zedd Zdd ZdEd
dZdd Zdd Zdd Z dd Z!dd Z"dd Z#dFddZ$dd Z%dd Z&dd  Z'd!d" Z(d#d$ Z)d%d& Z*d'd( Z+d)d* Z,dGd+d,Z-d-d. Z.d/d0 Z/d1d2 Z0d3d4 Z1d5d6 Z2d7d8 Z3d9d: Z4d;d< Z5d=d> Z6d?d@ Z7dAdB Z8dCdD Z9  Z:S )HAPIViewc                sL   t t| ddtjjr&dd }|| j_tt| j	f |}| |_
||_t|S )z
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        querysetNc               S   s   t dd S )NzDo not evaluate the `.queryset` attribute directly, as the result will be cached and reused between requests. Use `.all()` or call `.get_queryset()` instead.)RuntimeErrorr   r   r   r   force_evaluation   s    z)APIView.as_view.<locals>.force_evaluation)r,   r   r   queryZQuerySetr5   Z
_fetch_allsuperr4   as_viewcls
initkwargsr   )r;   r<   r7   r   )r   r   r   r:   {   s    zAPIView.as_viewc             C   s   | j  S )zZ
        Wrap Django's private `_allowed_methods` interface in a public property.
        )Z_allowed_methods)selfr   r   r   allowed_methods   s    zAPIView.allowed_methodsc             C   s*   ddj | ji}t| jdkr&d|d< |S )NZAllowz,    AcceptVary)joinr>   lenrenderer_classes)r=   r+   r   r   r   default_response_headers   s    z APIView.default_response_headersc             O   s   t j|jdS )z
        If `request.method` does not correspond to a handler method,
        determine what kind of exception to raise.
        N)r   ZMethodNotAllowedmethod)r=   requestargskwargsr   r   r   http_method_not_allowed   s    zAPIView.http_method_not_allowedNc             C   s&   |j r|j rtj tj|ddS )zY
        If request is not permitted, determine what kind of exception to raise.
        )r*   N)authenticatorsZsuccessful_authenticatorr   NotAuthenticatedr   )r=   rG   messager   r   r   permission_denied   s    zAPIView.permission_deniedc             C   s   t j|dS )zU
        If request is throttled, determine what kind of exception to raise.
        N)r   Z	Throttled)r=   rG   r)   r   r   r   	throttled   s    zAPIView.throttledc             C   s   | j  }|r|d j|S dS )z
        If a request is unauthenticated, determine the WWW-Authenticate
        header to use for 401 responses, if any.
        r   N)get_authenticatorsZauthenticate_header)r=   rG   rK   r   r   r   get_authenticate_header   s    zAPIView.get_authenticate_headerc             C   s   | t | df t | di dS )z|
        Returns a dict that is passed through to Parser.parse(),
        as the `parser_context` keyword argument.
        rH   rI   )r   rH   rI   )r   )r=   http_requestr   r   r   get_parser_context   s    
zAPIView.get_parser_contextc             C   s&   | t | df t | di t | dddS )z
        Returns a dict that is passed through to Renderer.render(),
        as the `renderer_context` keyword argument.
        rH   rI   rG   N)r   rH   rI   rG   )r   )r=   r   r   r   get_renderer_context   s    

zAPIView.get_renderer_contextc             C   s&   | t | df t | di t | dddS )zp
        Returns a dict that is passed through to EXCEPTION_HANDLER,
        as the `context` argument.
        rH   rI   rG   N)r   rH   rI   rG   )r   )r=   r   r   r   get_exception_handler_context   s    

z%APIView.get_exception_handler_contextc             C   s   | j j}|| S )zf
        Return the view name, as used in OPTIONS responses and in the
        browsable API.
        )r   ZVIEW_NAME_FUNCTION)r=   funcr   r   r   r      s    zAPIView.get_view_nameFc             C   s   | j j}|| |S )z{
        Return some descriptive text for the view, as used in OPTIONS responses
        and in the browsable API.
        )r   ZVIEW_DESCRIPTION_FUNCTION)r=   r$   rV   r   r   r   r%      s    zAPIView.get_view_descriptionc             K   s   | j jr|j| j jS dS )zQ
        Determine if the request includes a '.json' style format suffix
        N)r   ZFORMAT_SUFFIX_KWARGr&   )r=   rI   r   r   r   get_format_suffix   s    zAPIView.get_format_suffixc             C   s   dd | j D S )zX
        Instantiates and returns the list of renderers that this view can use.
        c             S   s   g | ]
}| qS r   r   ).0Zrendererr   r   r   
<listcomp>  s    z)APIView.get_renderers.<locals>.<listcomp>)rD   )r=   r   r   r   get_renderers  s    zAPIView.get_renderersc             C   s   dd | j D S )zV
        Instantiates and returns the list of parsers that this view can use.
        c             S   s   g | ]
}| qS r   r   )rX   parserr   r   r   rY     s    z'APIView.get_parsers.<locals>.<listcomp>)parser_classes)r=   r   r   r   get_parsers  s    zAPIView.get_parsersc             C   s   dd | j D S )z]
        Instantiates and returns the list of authenticators that this view can use.
        c             S   s   g | ]
}| qS r   r   )rX   authr   r   r   rY     s    z.APIView.get_authenticators.<locals>.<listcomp>)authentication_classes)r=   r   r   r   rP     s    zAPIView.get_authenticatorsc             C   s   dd | j D S )z[
        Instantiates and returns the list of permissions that this view requires.
        c             S   s   g | ]
}| qS r   r   )rX   
permissionr   r   r   rY     s    z+APIView.get_permissions.<locals>.<listcomp>)permission_classes)r=   r   r   r   get_permissions  s    zAPIView.get_permissionsc             C   s   dd | j D S )zU
        Instantiates and returns the list of throttles that this view uses.
        c             S   s   g | ]
}| qS r   r   )rX   throttler   r   r   rY     s    z)APIView.get_throttles.<locals>.<listcomp>)throttle_classes)r=   r   r   r   get_throttles  s    zAPIView.get_throttlesc             C   s   t | dds| j | _| jS )zN
        Instantiate and return the content negotiation class to use.
        _negotiatorN)r   content_negotiation_classrf   )r=   r   r   r   get_content_negotiator   s    
zAPIView.get_content_negotiatorc             C   s   | j jS )zD
        Returns the exception handler that this view uses.
        )r   ZEXCEPTION_HANDLER)r=   r   r   r   get_exception_handler(  s    zAPIView.get_exception_handlerc             C   sR   | j  }| j }y|j||| jS  tk
rL   |rF|d |d jfS  Y nX dS )zU
        Determine which renderer and media type to use render the response.
        r   N)rZ   rh   Zselect_rendererformat_kwarg	Exception
media_type)r=   rG   forceZ	renderersZconnegr   r   r   perform_content_negotiation0  s    z#APIView.perform_content_negotiationc             C   s
   |j  dS )a  
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        N)user)r=   rG   r   r   r   perform_authentication>  s    zAPIView.perform_authenticationc             C   s8   x2| j  D ]&}|j|| s
| j|t|ddd q
W dS )z
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        rM   N)rM   )rb   Zhas_permissionrN   r   )r=   rG   r`   r   r   r   check_permissionsH  s    zAPIView.check_permissionsc             C   s:   x4| j  D ](}|j|| |s
| j|t|ddd q
W dS )z
        Check if the request should be permitted for a given object.
        Raises an appropriate exception if the request is not permitted.
        rM   N)rM   )rb   Zhas_object_permissionrN   r   )r=   rG   objr`   r   r   r   check_object_permissionsS  s    z APIView.check_object_permissionsc             C   s2   x,| j  D ] }|j|| s
| j||j  q
W dS )z|
        Check if request should be throttled.
        Raises an appropriate exception if the request is throttled.
        N)re   Zallow_requestrO   r)   )r=   rG   rc   r   r   r   check_throttles^  s    zAPIView.check_throttlesc             O   s,   | j dkrdS | j  }|j|f|||fS )z
        If versioning is being used, then determine any API version for the
        incoming request. Returns a two-tuple of (version, versioning_scheme)
        N)NN)versioning_classdetermine_version)r=   rG   rH   rI   schemer   r   r   rv   g  s    
zAPIView.determine_versionc             O   s(   | j |}t|| j | j | j |dS )z5
        Returns the initial request object.
        )parsersrK   Z
negotiatorparser_context)rS   r   r]   rP   rh   )r=   rG   rH   rI   ry   r   r   r   initialize_requests  s    
zAPIView.initialize_requestc             O   sj   | j f || _| j|}|\|_|_| j|f||\}}|| |_|_| j| | j	| | j
| dS )zX
        Runs anything that needs to occur prior to calling the method handler.
        N)rW   rj   rn   accepted_rendereraccepted_media_typerv   versionZversioning_schemerp   rq   rt   )r=   rG   rH   rI   negr}   rw   r   r   r   initial  s    


zAPIView.initialc       	      O   s   t |tstdt| t |trdt|ddsJ| j|dd}|\|_|_|j|_|j|_| j	 |_
| jjdd}|dk	rt|tj| x| jj D ]\}}|||< qW |S )z4
        Returns the final response object.
        zrExpected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `%s`r{   NT)rm   rA   )r,   r	   AssertionErrortyper   r   rn   r{   r|   rT   Zrenderer_contextr+   popr   r
   splititems)	r=   rG   responserH   rI   r~   Zvary_headerskeyvaluer   r   r   finalize_response  s     

zAPIView.finalize_responsec             C   sh   t |tjtjfr2| j| j}|r*||_ntj|_	| j
 }| j }|||}|dkr^| j| d|_|S )zz
        Handle any exception that occurs, by returning an appropriate response,
        or re-raising the error.
        NT)r,   r   rL   ZAuthenticationFailedrQ   rG   r(   r   ZHTTP_403_FORBIDDENr/   ri   rU   raise_uncaught_exception	exception)r=   r0   r(   r3   r1   r   r   r   r   handle_exception  s    


zAPIView.handle_exceptionc             C   s0   t jr*| j}t|jd}|dk}|j|  d S )Nformatr$   apiadmin)r$   r   r   )r   DEBUGrG   r   r{   Zforce_plaintext_errors)r=   r0   rG   Zrenderer_formatZuse_plaintext_tracebackr   r   r   r     s    
z APIView.raise_uncaught_exceptionc             O   s   || _ || _| j|f||}|| _| j| _yR| j|f|| |jj | j	krft
| |jj | j}n| j}||f||}W n, tk
r } z| j|}W Y dd}~X nX | j||f||| _| jS )z
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        N)rH   rI   rz   rG   rE   r+   r   rF   lowerZhttp_method_namesr   rJ   rk   r   r   r   )r=   rG   rH   rI   handlerr   r0   r   r   r   dispatch  s     
zAPIView.dispatchc             O   s:   | j dkr| j|f||S | j  j|| }t|tjdS )z<
        Handler method for HTTP 'OPTIONS' request.
        N)r   )metadata_classrJ   Zdetermine_metadatar   r   ZHTTP_200_OK)r=   rG   rH   rI   r2   r   r   r   options  s    
zAPIView.options)N)F)F);r   
__module____qualname__r   ZDEFAULT_RENDERER_CLASSESrD   ZDEFAULT_PARSER_CLASSESr\   ZDEFAULT_AUTHENTICATION_CLASSESr_   ZDEFAULT_THROTTLE_CLASSESrd   ZDEFAULT_PERMISSION_CLASSESra   Z!DEFAULT_CONTENT_NEGOTIATION_CLASSrg   ZDEFAULT_METADATA_CLASSr   ZDEFAULT_VERSIONING_CLASSru   r   r   Zschemaclassmethodr:   propertyr>   rE   rJ   rN   rO   rQ   rS   rT   rU   r   r%   rW   rZ   r]   rP   rb   re   rh   ri   rn   rp   rq   rs   rt   rv   rz   r   r   r   r   r   r   __classcell__r   r   )r   r   r4   j   sV   	
	



	r4   N)F)*r"   
__future__r   Zdjango.confr   Zdjango.core.exceptionsr   Z	django.dbr   r   r   Zdjango.httpr   Zdjango.http.responser	   Zdjango.utils.cacher
   r   Zdjango.utils.encodingr   Zdjango.views.decorators.csrfr   Zdjango.views.genericr   Zrest_frameworkr   r   Zrest_framework.requestr   Zrest_framework.responser   Zrest_framework.schemasr   Zrest_framework.settingsr   Zrest_framework.utilsr   r   r%   r'   r3   r4   r   r   r   r   <module>   s*   
!