mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-11 04:07:39 +03:00
Most of the actual work so far has been markup really.
This commit is contained in:
parent
49d4e50342
commit
92c015e049
|
@ -4,7 +4,7 @@ The :mod:`authentication` module provides a set of pluggable authentication clas
|
|||
Authentication behavior is provided by mixing the :class:`mixins.AuthMixin` class into a :class:`View` class.
|
||||
|
||||
The set of authentication methods which are used is then specified by setting the
|
||||
:attr:`authentication` attribute on the :class:`View` class, and listing a set of authentication classes.
|
||||
:attr:`authentication` attribute on the :class:`View` class, and listing a set of :class:`authentication` classes.
|
||||
"""
|
||||
|
||||
from django.contrib.auth import authenticate
|
||||
|
@ -26,20 +26,19 @@ class BaseAuthenticaton(object):
|
|||
|
||||
def __init__(self, view):
|
||||
"""
|
||||
:param view: :class:`Authentication` classes are always passed the current view on creation.
|
||||
:class:`Authentication` classes are always passed the current view on creation.
|
||||
"""
|
||||
self.view = view
|
||||
|
||||
def authenticate(self, request):
|
||||
"""
|
||||
:param request: Request to be authenticated
|
||||
:rtype: :obj:`User` or None [*]_
|
||||
Authenticate the :obj:`request` and return a :obj:`User` instance or :const:`None`. [*]_
|
||||
|
||||
.. [*] The authentication context *will* typically be a :obj:`User`,
|
||||
.. [*] The authentication context *will* typically be a :obj:`User` object,
|
||||
but it need not be. It can be any user-like object so long as the
|
||||
permissions classes on the view can handle the object and use
|
||||
permissions classes (see the :mod:`permissions` module) on the view can handle the object and use
|
||||
it to determine if the request has the required permissions or not.
|
||||
|
||||
|
||||
This can be an important distinction if you're implementing some token
|
||||
based authentication mechanism, where the authentication context
|
||||
may be more involved than simply mapping to a :obj:`User`.
|
||||
|
@ -55,7 +54,7 @@ class BasicAuthenticaton(BaseAuthenticaton):
|
|||
def authenticate(self, request):
|
||||
"""
|
||||
Returns a :obj:`User` if a correct username and password have been supplied
|
||||
using HTTP Basic authentication. Otherwise returns `None`.
|
||||
using HTTP Basic authentication. Otherwise returns :const:`None`.
|
||||
"""
|
||||
from django.utils.encoding import smart_unicode, DjangoUnicodeDecodeError
|
||||
|
||||
|
@ -85,7 +84,7 @@ class UserLoggedInAuthenticaton(BaseAuthenticaton):
|
|||
|
||||
def authenticate(self, request):
|
||||
"""
|
||||
Returns a :obj:`User` if the request session currently has a logged in user, otherwise `None`.
|
||||
Returns a :obj:`User` object if the request session currently has a logged in user. Otherwise returns :const:`None`.
|
||||
"""
|
||||
# TODO: Switch this back to request.POST, and let FormParser/MultiPartParser deal with the consequences.
|
||||
if getattr(request, 'user', None) and request.user.is_active:
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
"""Compatability module to provide support for backwards compatability with older versions of django/python"""
|
||||
"""
|
||||
Compatability module to provide support for backwards compatability with older versions of django/python
|
||||
"""
|
||||
|
||||
# cStringIO only if it's available
|
||||
try:
|
||||
|
@ -27,24 +29,25 @@ except ImportError:
|
|||
# Lovely stuff
|
||||
class RequestFactory(Client):
|
||||
"""
|
||||
Class that lets you create mock Request objects for use in testing.
|
||||
Class that lets you create mock :obj:`Request` objects for use in testing.
|
||||
|
||||
Usage:
|
||||
Usage::
|
||||
|
||||
rf = RequestFactory()
|
||||
get_request = rf.get('/hello/')
|
||||
post_request = rf.post('/submit/', {'foo': 'bar'})
|
||||
rf = RequestFactory()
|
||||
get_request = rf.get('/hello/')
|
||||
post_request = rf.post('/submit/', {'foo': 'bar'})
|
||||
|
||||
This class re-uses the django.test.client.Client interface, docs here:
|
||||
http://www.djangoproject.com/documentation/testing/#the-test-client
|
||||
This class re-uses the :class:`django.test.client.Client` interface. Of which
|
||||
you can find the docs here__.
|
||||
|
||||
Once you have a request object you can pass it to any view function,
|
||||
just as if that view had been hooked up using a URLconf.
|
||||
__ http://www.djangoproject.com/documentation/testing/#the-test-client
|
||||
|
||||
Once you have a :obj:`request` object you can pass it to any :func:`view` function,
|
||||
just as if that :func:`view` had been hooked up using a URLconf.
|
||||
"""
|
||||
def request(self, **request):
|
||||
"""
|
||||
Similar to parent class, but returns the request object as soon as it
|
||||
Similar to parent class, but returns the :obj:`request` object as soon as it
|
||||
has created it.
|
||||
"""
|
||||
environ = {
|
||||
|
@ -148,9 +151,11 @@ try:
|
|||
import re
|
||||
|
||||
class CustomSetextHeaderProcessor(markdown.blockprocessors.BlockProcessor):
|
||||
"""Override markdown's SetextHeaderProcessor, so that ==== headers are <h2> and ---- headers are <h3>.
|
||||
"""
|
||||
Override `markdown`'s :class:`SetextHeaderProcessor`, so that ==== headers are <h2> and ---- headers are <h3>.
|
||||
|
||||
We use <h1> for the resource name."""
|
||||
We use <h1> for the resource name.
|
||||
"""
|
||||
|
||||
# Detect Setext-style header. Must be first 2 lines of block.
|
||||
RE = re.compile(r'^.*?\n[=-]{3,}', re.MULTILINE)
|
||||
|
@ -172,8 +177,11 @@ try:
|
|||
blocks.insert(0, '\n'.join(lines[2:]))
|
||||
|
||||
def apply_markdown(text):
|
||||
"""Simple wrapper around markdown.markdown to apply our CustomSetextHeaderProcessor,
|
||||
and also set the base level of '#' style headers to <h2>."""
|
||||
"""
|
||||
Simple wrapper around :func:`markdown.markdown` to apply our :class:`CustomSetextHeaderProcessor`,
|
||||
and also set the base level of '#' style headers to <h2>.
|
||||
"""
|
||||
|
||||
extensions = ['headerid(level=2)']
|
||||
safe_mode = False,
|
||||
output_format = markdown.DEFAULT_OUTPUT_FORMAT
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""
|
||||
The mixins module provides a set of reusable mixin classes that can be added to a ``View``.
|
||||
The :mod:`mixins` module provides a set of reusable `mixin`
|
||||
classes that can be added to a `View`.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
|
@ -41,7 +42,7 @@ __all__ = (
|
|||
|
||||
class RequestMixin(object):
|
||||
"""
|
||||
Mixin class to provide request parsing behavior.
|
||||
`Mixin` class to provide request parsing behavior.
|
||||
"""
|
||||
|
||||
_USE_FORM_OVERLOADING = True
|
||||
|
@ -52,7 +53,7 @@ class RequestMixin(object):
|
|||
"""
|
||||
The set of request parsers that the view can handle.
|
||||
|
||||
Should be a tuple/list of classes as described in the ``parsers`` module.
|
||||
Should be a tuple/list of classes as described in the :mod:`parsers` module.
|
||||
"""
|
||||
parsers = ()
|
||||
|
||||
|
@ -61,8 +62,8 @@ class RequestMixin(object):
|
|||
"""
|
||||
Returns the HTTP method.
|
||||
|
||||
This should be used instead of ``request.method``, as it allows the method
|
||||
to be overridden by using a hidden form field on a form POST request.
|
||||
This should be used instead of just reading :const:`request.method`, as it allows the `method`
|
||||
to be overridden by using a hidden `form` field on a form POST request.
|
||||
"""
|
||||
if not hasattr(self, '_method'):
|
||||
self._load_method_and_content_type()
|
||||
|
@ -100,7 +101,7 @@ class RequestMixin(object):
|
|||
def FILES(self):
|
||||
"""
|
||||
Parses the request body and returns the files.
|
||||
Similar to request.FILES, except that it handles arbitrary parsers,
|
||||
Similar to ``request.FILES``, except that it handles arbitrary parsers,
|
||||
and also works on methods other than POST (eg PUT).
|
||||
"""
|
||||
if not hasattr(self, '_files'):
|
||||
|
@ -215,10 +216,10 @@ class RequestMixin(object):
|
|||
|
||||
class ResponseMixin(object):
|
||||
"""
|
||||
Adds behavior for pluggable Renderers to a :class:`.BaseView` or Django :class:`View`. class.
|
||||
Adds behavior for pluggable `Renderers` to a :class:`views.BaseView` or Django :class:`View` class.
|
||||
|
||||
Default behavior is to use standard HTTP Accept header content negotiation.
|
||||
Also supports overriding the content type by specifying an _accept= parameter in the URL.
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -228,7 +229,7 @@ class ResponseMixin(object):
|
|||
"""
|
||||
The set of response renderers that the view can handle.
|
||||
|
||||
Should be a tuple/list of classes as described in the ``renderers`` module.
|
||||
Should be a tuple/list of classes as described in the :mod:`renderers` module.
|
||||
"""
|
||||
renderers = ()
|
||||
|
||||
|
@ -237,7 +238,7 @@ class ResponseMixin(object):
|
|||
# out of the box with existing Django classes that use render_to_response.
|
||||
def render(self, response):
|
||||
"""
|
||||
Takes a ``Response`` object and returns an ``HttpResponse``.
|
||||
Takes a :obj:`Response` object and returns an :obj:`HttpResponse`.
|
||||
"""
|
||||
self.response = response
|
||||
|
||||
|
@ -354,21 +355,21 @@ class ResponseMixin(object):
|
|||
|
||||
class AuthMixin(object):
|
||||
"""
|
||||
Simple mixin class to add authentication and permission checking to a ``View`` class.
|
||||
Simple :class:`mixin` class to add authentication and permission checking to a :class:`View` class.
|
||||
"""
|
||||
|
||||
"""
|
||||
The set of authentication types that this view can handle.
|
||||
|
||||
|
||||
Should be a tuple/list of classes as described in the ``authentication`` module.
|
||||
Should be a tuple/list of classes as described in the :mod:`authentication` module.
|
||||
"""
|
||||
authentication = ()
|
||||
|
||||
"""
|
||||
The set of permissions that will be enforced on this view.
|
||||
|
||||
Should be a tuple/list of classes as described in the ``permissions`` module.
|
||||
Should be a tuple/list of classes as described in the :mod:`permissions` module.
|
||||
"""
|
||||
permissions = ()
|
||||
|
||||
|
@ -376,8 +377,8 @@ class AuthMixin(object):
|
|||
@property
|
||||
def user(self):
|
||||
"""
|
||||
Returns the user for the current request, as determined by the set of
|
||||
authentication classes applied to the ``View``.
|
||||
Returns the :obj:`user` for the current request, as determined by the set of
|
||||
:class:`authentication` classes applied to the :class:`View`.
|
||||
"""
|
||||
if not hasattr(self, '_user'):
|
||||
self._user = self._authenticate()
|
||||
|
@ -413,12 +414,10 @@ class AuthMixin(object):
|
|||
class ResourceMixin(object):
|
||||
"""
|
||||
Provides request validation and response filtering behavior.
|
||||
"""
|
||||
|
||||
"""
|
||||
Should be a class as described in the ``resources`` module.
|
||||
Should be a class as described in the :mod:`resources` module.
|
||||
|
||||
The ``resource`` is an object that maps a view onto it's representation on the server.
|
||||
The :obj:`resource` is an object that maps a view onto it's representation on the server.
|
||||
|
||||
It provides validation on the content of incoming requests,
|
||||
and filters the object representation into a serializable object for the response.
|
||||
|
@ -436,8 +435,8 @@ class ResourceMixin(object):
|
|||
|
||||
def validate_request(self, data, files):
|
||||
"""
|
||||
Given the request data return the cleaned, validated content.
|
||||
Typically raises a ErrorResponse with status code 400 (Bad Request) on failure.
|
||||
Given the request *data* return the cleaned, validated content.
|
||||
Typically raises an :class:`response.ErrorResponse` with status code 400 (Bad Request) on failure.
|
||||
"""
|
||||
resource = self.resource(self)
|
||||
return resource.validate_request(data, files)
|
||||
|
@ -459,8 +458,8 @@ class ResourceMixin(object):
|
|||
|
||||
class InstanceMixin(object):
|
||||
"""
|
||||
Mixin class that is used to identify a view class as being the canonical identifier
|
||||
for the resources it is mapped too.
|
||||
`Mixin` class that is used to identify a `View` class as being the canonical identifier
|
||||
for the resources it is mapped to.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
|
@ -482,7 +481,7 @@ class InstanceMixin(object):
|
|||
|
||||
class ReadModelMixin(object):
|
||||
"""
|
||||
Behavior to read a model instance on GET requests
|
||||
Behavior to read a `model` instance on GET requests
|
||||
"""
|
||||
def get(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
|
@ -501,7 +500,7 @@ class ReadModelMixin(object):
|
|||
|
||||
class CreateModelMixin(object):
|
||||
"""
|
||||
Behavior to create a model instance on POST requests
|
||||
Behavior to create a `model` instance on POST requests
|
||||
"""
|
||||
def post(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
|
@ -525,7 +524,7 @@ class CreateModelMixin(object):
|
|||
|
||||
class UpdateModelMixin(object):
|
||||
"""
|
||||
Behavior to update a model instance on PUT requests
|
||||
Behavior to update a `model` instance on PUT requests
|
||||
"""
|
||||
def put(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
|
@ -550,7 +549,7 @@ class UpdateModelMixin(object):
|
|||
|
||||
class DeleteModelMixin(object):
|
||||
"""
|
||||
Behavior to delete a model instance on DELETE requests
|
||||
Behavior to delete a `model` instance on DELETE requests
|
||||
"""
|
||||
def delete(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
|
@ -570,7 +569,7 @@ class DeleteModelMixin(object):
|
|||
|
||||
class ListModelMixin(object):
|
||||
"""
|
||||
Behavior to list a set of model instances on GET requests
|
||||
Behavior to list a set of `model` instances on GET requests
|
||||
"""
|
||||
|
||||
# NB. Not obvious to me if it would be better to set this on the resource?
|
||||
|
|
|
@ -5,8 +5,9 @@ to general HTTP requests.
|
|||
|
||||
We need a method to be able to:
|
||||
|
||||
1) Determine the parsed content on a request for methods other than POST (eg typically also PUT)
|
||||
2) Determine the parsed content on a request for media types other than application/x-www-form-urlencoded
|
||||
1.) Determine the parsed content on a request for methods other than POST (eg typically also PUT)
|
||||
|
||||
2.) Determine the parsed content on a request for media types other than application/x-www-form-urlencoded
|
||||
and multipart/form-data. (eg also handle multipart/json)
|
||||
"""
|
||||
|
||||
|
@ -22,47 +23,51 @@ __all__ = (
|
|||
'BaseParser',
|
||||
'JSONParser',
|
||||
'PlainTextParser',
|
||||
'DataFlatener',
|
||||
'FormParser',
|
||||
'MultiPartParser'
|
||||
'MultiPartParser',
|
||||
)
|
||||
|
||||
|
||||
class BaseParser(object):
|
||||
"""
|
||||
All parsers should extend BaseParser, specifying a media_type attribute,
|
||||
and overriding the parse() method.
|
||||
All parsers should extend :class:`BaseParser`, specifying a :attr:`media_type` attribute,
|
||||
and overriding the :meth:`parse` method.
|
||||
"""
|
||||
media_type = None
|
||||
|
||||
def __init__(self, view):
|
||||
"""
|
||||
Initialize the parser with the ``View`` instance as state,
|
||||
in case the parser needs to access any metadata on the ``View`` object.
|
||||
in case the parser needs to access any metadata on the :obj:`View` object.
|
||||
"""
|
||||
self.view = view
|
||||
|
||||
def can_handle_request(self, content_type):
|
||||
"""
|
||||
Returns `True` if this parser is able to deal with the given media type.
|
||||
Returns :const:`True` if this parser is able to deal with the given *content_type*.
|
||||
|
||||
The default implementation for this function is to check the ``media_type``
|
||||
argument against the ``media_type`` attribute set on the class to see if
|
||||
The default implementation for this function is to check the *content_type*
|
||||
argument against the :attr:`media_type` attribute set on the class to see if
|
||||
they match.
|
||||
|
||||
This may be overridden to provide for other behavior, but typically you'll
|
||||
instead want to just set the ``media_type`` attribute on the class.
|
||||
instead want to just set the :attr:`media_type` attribute on the class.
|
||||
"""
|
||||
return media_type_matches(content_type, self.media_type)
|
||||
|
||||
def parse(self, stream):
|
||||
"""
|
||||
Given a stream to read from, return the deserialized output.
|
||||
Given a *stream* to read from, return the deserialized output.
|
||||
Should return a 2-tuple of (data, files).
|
||||
"""
|
||||
raise NotImplementedError("BaseParser.parse() Must be overridden to be implemented.")
|
||||
|
||||
|
||||
class JSONParser(BaseParser):
|
||||
"""
|
||||
Parses JSON-serialized data.
|
||||
"""
|
||||
media_type = 'application/json'
|
||||
|
||||
def parse(self, stream):
|
||||
|
@ -74,11 +79,14 @@ class JSONParser(BaseParser):
|
|||
|
||||
|
||||
class DataFlatener(object):
|
||||
"""Utility object for flattening dictionaries of lists. Useful for "urlencoded" decoded data."""
|
||||
|
||||
"""
|
||||
Utility object for flattening dictionaries of lists. Useful for "urlencoded" decoded data.
|
||||
"""
|
||||
# TODO: move me to utils ??
|
||||
|
||||
def flatten_data(self, data):
|
||||
"""Given a data dictionary {<key>: <value_list>}, returns a flattened dictionary
|
||||
with information provided by the method "is_a_list"."""
|
||||
"""Given a *data* dictionary ``{<key>: <value_list>}``, returns a flattened dictionary
|
||||
with information provided by the method :meth:`is_a_list`."""
|
||||
flatdata = dict()
|
||||
for key, val_list in data.items():
|
||||
if self.is_a_list(key, val_list):
|
||||
|
@ -93,15 +101,13 @@ class DataFlatener(object):
|
|||
return flatdata
|
||||
|
||||
def is_a_list(self, key, val_list):
|
||||
"""Returns True if the parameter with name *key* is expected to be a list, or False otherwise.
|
||||
"""Returns :const:`True` if the parameter with name *key* is expected to be a list, or :const:`False` otherwise.
|
||||
*val_list* which is the received value for parameter *key* can be used to guess the answer."""
|
||||
return False
|
||||
|
||||
|
||||
class PlainTextParser(BaseParser):
|
||||
"""
|
||||
Plain text parser.
|
||||
|
||||
Simply returns the content of the stream.
|
||||
"""
|
||||
media_type = 'text/plain'
|
||||
|
@ -113,10 +119,10 @@ class PlainTextParser(BaseParser):
|
|||
class FormParser(BaseParser, DataFlatener):
|
||||
"""
|
||||
The default parser for form data.
|
||||
Return a dict containing a single value for each non-reserved parameter.
|
||||
Returns a dict containing a single value for each non-reserved parameter.
|
||||
|
||||
In order to handle select multiple (and having possibly more than a single value for each parameter),
|
||||
you can customize the output by subclassing the method 'is_a_list'."""
|
||||
you can customize the output by subclassing the method :meth:`DataFlatener.is_a_list`."""
|
||||
|
||||
media_type = 'application/x-www-form-urlencoded'
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class BasePermission(object):
|
|||
|
||||
def check_permission(self, auth):
|
||||
"""
|
||||
Should simply return, or raise an ErrorResponse.
|
||||
Should simply return, or raise an :class:`response.ErrorResponse`.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
@ -59,7 +59,7 @@ class IsAuthenticated(BasePermission):
|
|||
if not user.is_authenticated():
|
||||
raise _403_FORBIDDEN_RESPONSE
|
||||
|
||||
class IsAdminUser():
|
||||
class IsAdminUser(BasePermission):
|
||||
"""
|
||||
Allows access only to admin users.
|
||||
"""
|
||||
|
@ -85,7 +85,7 @@ class PerUserThrottling(BasePermission):
|
|||
"""
|
||||
Rate throttling of requests on a per-user basis.
|
||||
|
||||
The rate is set by a 'throttle' attribute on the ``View`` class.
|
||||
The rate (requests / seconds) is set by a :attr:`throttle` attribute on the ``View`` class.
|
||||
The attribute is a two tuple of the form (number of requests, duration in seconds).
|
||||
|
||||
The user id will be used as a unique identifier if the user is authenticated.
|
||||
|
|
|
@ -36,8 +36,8 @@ __all__ = (
|
|||
|
||||
class BaseRenderer(object):
|
||||
"""
|
||||
All renderers must extend this class, set the media_type attribute,
|
||||
and override the render() function.
|
||||
All renderers must extend this class, set the :attr:`media_type` attribute,
|
||||
and override the :meth:`render` method.
|
||||
"""
|
||||
media_type = None
|
||||
|
||||
|
@ -51,7 +51,7 @@ class BaseRenderer(object):
|
|||
The requested media type is also passed to this method,
|
||||
as it may contain parameters relevant to how the parser
|
||||
should render the output.
|
||||
EG: 'application/json; indent=4'
|
||||
EG: ``application/json; indent=4``
|
||||
|
||||
By default render simply returns the output as-is.
|
||||
Override this method to provide for other behavior.
|
||||
|
@ -102,8 +102,8 @@ class TemplateRenderer(BaseRenderer):
|
|||
A Base class provided for convenience.
|
||||
|
||||
Render the object simply by using the given template.
|
||||
To create a template renderer, subclass this, and set
|
||||
the ``media_type`` and ``template`` attributes
|
||||
To create a template renderer, subclass this class, and set
|
||||
the :attr:`media_type` and `:attr:template` attributes.
|
||||
"""
|
||||
media_type = None
|
||||
template = None
|
||||
|
|
Loading…
Reference in New Issue
Block a user