mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-10 19:56:59 +03:00
Mostly improving documentation
This commit is contained in:
parent
b0ce3f92c6
commit
9979903272
|
@ -3,5 +3,8 @@ syntax: glob
|
|||
*.pyc
|
||||
*.db
|
||||
env
|
||||
cache
|
||||
html
|
||||
.project
|
||||
.pydevproject
|
||||
.settings
|
||||
|
|
|
@ -11,3 +11,7 @@ source ./env/bin/activate
|
|||
pip install -r ./requirements.txt
|
||||
python ./src/manage.py test
|
||||
|
||||
# To build the documentation...
|
||||
|
||||
sphinx-build -c docs -b html -d cache docs html
|
||||
|
||||
|
|
220
docs/conf.py
Normal file
220
docs/conf.py
Normal file
|
@ -0,0 +1,220 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Asset Platform documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Nov 19 20:24:09 2010.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'src'))
|
||||
import settings
|
||||
from django.core.management import setup_environ
|
||||
setup_environ(settings)
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = []
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'FlyWheel'
|
||||
copyright = u'2011, Tom Christie'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'restfulloggingdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'restfullogging.tex', u'restful logging Documentation',
|
||||
u'tom c', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'restfullogging', u'restful logging Documentation',
|
||||
[u'tom c'], 1)
|
||||
]
|
12
docs/index.rst
Normal file
12
docs/index.rst
Normal file
|
@ -0,0 +1,12 @@
|
|||
FlyWheel Documentation
|
||||
======================
|
||||
|
||||
This is the online documentation for FlyWheel - A REST framework for Django.
|
||||
|
||||
Indices and tables
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
|
@ -12,10 +12,38 @@ import re
|
|||
|
||||
|
||||
class ModelResource(Resource):
|
||||
"""A specialized type of Resource, for RESTful resources that map directly to a Django Model.
|
||||
Useful things this provides:
|
||||
|
||||
0. Default input validation based on ModelForms.
|
||||
1. Nice serialization of returned Models and QuerySets.
|
||||
2. A default set of create/read/update/delete operations."""
|
||||
|
||||
# The model attribute refers to the Django Model which this Resource maps to.
|
||||
# (The Model's class, rather than an instance of the Model)
|
||||
model = None
|
||||
|
||||
# By default the set of returned fields will be the set of:
|
||||
#
|
||||
# 0. All the fields on the model, excluding 'id'.
|
||||
# 1. All the properties on the model.
|
||||
# 2. The absolute_url of the model, if a get_absolute_url method exists for the model.
|
||||
#
|
||||
# If you wish to override this behaviour,
|
||||
# you should explicitly set the fields attribute on your class.
|
||||
fields = None
|
||||
|
||||
# By default the form used with be a ModelForm for self.model
|
||||
# If you wish to override this behaviour or provide a sub-classed ModelForm
|
||||
# you should explicitly set the form attribute on your class.
|
||||
form = None
|
||||
|
||||
# By default the set of input fields will be the same as the set of output fields
|
||||
# If you wish to override this behaviour you should explicitly set the
|
||||
# form_fields attribute on your class.
|
||||
form_fields = None
|
||||
|
||||
|
||||
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"""
|
||||
if self.form:
|
||||
|
@ -25,7 +53,7 @@ class ModelResource(Resource):
|
|||
class NewModelForm(ModelForm):
|
||||
class Meta:
|
||||
model = self.model
|
||||
fields = self.form_fields if self.form_fields else None #self.fields
|
||||
fields = self.form_fields if self.form_fields else None
|
||||
|
||||
if data and not is_response:
|
||||
return NewModelForm(data)
|
||||
|
@ -36,7 +64,27 @@ class ModelResource(Resource):
|
|||
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def cleanup_request(self, data, form_instance):
|
||||
"""Override cleanup_request to drop read-only fields from the input prior to validation.
|
||||
This ensures that we don't error out with 'non-existent field' when these fields are supplied,
|
||||
and allows for a pragmatic approach to resources which include read-only elements.
|
||||
|
||||
I would actually like to be strict and verify the value of correctness of the values in these fields,
|
||||
although that gets tricky as it involves validating at the point that we get the model instance.
|
||||
|
||||
See here for another example of this approach:
|
||||
http://fedoraproject.org/wiki/Cloud_APIs_REST_Style_Guide
|
||||
https://www.redhat.com/archives/rest-practices/2010-April/thread.html#00041"""
|
||||
read_only_fields = set(self.fields) - set(self.form_instance.fields)
|
||||
input_fields = set(data.keys())
|
||||
|
||||
clean_data = {}
|
||||
for key in input_fields - read_only_fields:
|
||||
clean_data[key] = data[key]
|
||||
|
||||
return super(ModelResource, self).cleanup_request(clean_data, form_instance)
|
||||
|
||||
|
||||
def cleanup_response(self, data):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import json
|
||||
from rest.status import ResourceException, Status
|
||||
|
||||
class BaseParser(object):
|
||||
def __init__(self, resource):
|
||||
|
@ -10,7 +11,10 @@ class BaseParser(object):
|
|||
|
||||
class JSONParser(BaseParser):
|
||||
def parse(self, input):
|
||||
return json.loads(input)
|
||||
try:
|
||||
return json.loads(input)
|
||||
except ValueError, exc:
|
||||
raise ResourceException(Status.HTTP_400_BAD_REQUEST, {'detail': 'JSON parse error - %s' % str(exc)})
|
||||
|
||||
class XMLParser(BaseParser):
|
||||
pass
|
||||
|
|
|
@ -1,39 +1,29 @@
|
|||
from django.http import HttpResponse
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.handlers.wsgi import STATUS_CODE_TEXT
|
||||
from django.http import HttpResponse
|
||||
from rest import emitters, parsers
|
||||
from rest.status import Status, ResourceException
|
||||
from decimal import Decimal
|
||||
import re
|
||||
|
||||
# TODO: Authentication
|
||||
# TODO: Display user login in top panel: http://stackoverflow.com/questions/806835/django-redirect-to-previous-page-after-login
|
||||
# TODO: Return basic object, not tuple
|
||||
# TODO: Return basic object, not tuple of status code, content, headers
|
||||
# TODO: Take request, not headers
|
||||
# TODO: Remove self.blah munging (Add a ResponseContext object)
|
||||
# TODO: Erroring on non-existent fields
|
||||
# TODO: Standard exception classes and module for status codes
|
||||
# TODO: Standard exception classes
|
||||
# TODO: Figure how out references and named urls need to work nicely
|
||||
# TODO: POST on existing 404 URL, PUT on existing 404 URL
|
||||
# TODO: Authentication
|
||||
#
|
||||
# NEXT: Generic content form
|
||||
# NEXT: Remove self.blah munging (Add a ResponseContext object?)
|
||||
# NEXT: Caching cleverness
|
||||
# NEXT: Test non-existent fields on ModelResources
|
||||
#
|
||||
# FUTURE: Erroring on read-only fields
|
||||
|
||||
# Documentation, Release
|
||||
|
||||
#
|
||||
STATUS_400_BAD_REQUEST = 400
|
||||
STATUS_405_METHOD_NOT_ALLOWED = 405
|
||||
STATUS_406_NOT_ACCEPTABLE = 406
|
||||
STATUS_415_UNSUPPORTED_MEDIA_TYPE = 415
|
||||
STATUS_500_INTERNAL_SERVER_ERROR = 500
|
||||
STATUS_501_NOT_IMPLEMENTED = 501
|
||||
|
||||
|
||||
class ResourceException(Exception):
|
||||
def __init__(self, status, content='', headers={}):
|
||||
self.status = status
|
||||
self.content = content
|
||||
self.headers = headers
|
||||
|
||||
|
||||
class Resource(object):
|
||||
|
@ -110,13 +100,16 @@ class Resource(object):
|
|||
|
||||
def reverse(self, view, *args, **kwargs):
|
||||
"""Return a fully qualified URI for a given view or resource.
|
||||
Use the Sites framework if possible, otherwise fallback to using the current request."""
|
||||
Add the domain using the Sites framework if possible, otherwise fallback to using the current request."""
|
||||
return self.add_domain(reverse(view, *args, **kwargs))
|
||||
|
||||
|
||||
def add_domain(self, path):
|
||||
"""Given a path, return an fully qualified URI.
|
||||
Use the Sites framework if possible, otherwise fallback to using the domain from the current request."""
|
||||
|
||||
# Note that out-of-the-box the Sites framework uses the reserved domain 'example.com'
|
||||
# See RFC 2606 - http://www.faqs.org/rfcs/rfc2606.html
|
||||
try:
|
||||
site = Site.objects.get_current()
|
||||
if site.domain and site.domain != 'example.com':
|
||||
|
@ -150,7 +143,7 @@ class Resource(object):
|
|||
def not_implemented(self, operation):
|
||||
"""Return an HTTP 500 server error if an operation is called which has been allowed by
|
||||
allowed_operations, but which has not been implemented."""
|
||||
raise ResourceException(STATUS_500_INTERNAL_SERVER_ERROR,
|
||||
raise ResourceException(Status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
{'detail': '%s operation on this resource has not been implemented' % (operation, )})
|
||||
|
||||
|
||||
|
@ -172,18 +165,18 @@ class Resource(object):
|
|||
# if anon_user and not anon_allowed_operations raise PermissionDenied
|
||||
# return
|
||||
|
||||
|
||||
def check_method_allowed(self, method):
|
||||
"""Ensure the request method is acceptable for this resource."""
|
||||
if not method in self.CALLMAP.keys():
|
||||
raise ResourceException(STATUS_501_NOT_IMPLEMENTED,
|
||||
raise ResourceException(Status.HTTP_501_NOT_IMPLEMENTED,
|
||||
{'detail': 'Unknown or unsupported method \'%s\'' % method})
|
||||
|
||||
if not self.CALLMAP[method] in self.allowed_operations:
|
||||
raise ResourceException(STATUS_405_METHOD_NOT_ALLOWED,
|
||||
raise ResourceException(Status.HTTP_405_METHOD_NOT_ALLOWED,
|
||||
{'detail': 'Method \'%s\' not allowed on this resource.' % method})
|
||||
|
||||
|
||||
|
||||
def get_bound_form(self, data=None, is_response=False):
|
||||
"""Optionally return a Django Form instance, which may be used for validation
|
||||
and/or rendered by an HTML/XHTML emitter.
|
||||
|
@ -207,16 +200,31 @@ class Resource(object):
|
|||
By default this uses form validation to filter the basic input into the required types."""
|
||||
if form_instance is None:
|
||||
return data
|
||||
|
||||
# Default form validation does not check for additional invalid fields
|
||||
non_existent_fields = []
|
||||
for key in set(data.keys()) - set(form_instance.fields.keys()):
|
||||
non_existent_fields.append(key)
|
||||
|
||||
if not form_instance.is_valid():
|
||||
if not form_instance.errors:
|
||||
if not form_instance.is_valid() or non_existent_fields:
|
||||
if not form_instance.errors and not non_existent_fields:
|
||||
# If no data was supplied the errors property will be None
|
||||
details = 'No content was supplied'
|
||||
|
||||
else:
|
||||
# Add standard field errors
|
||||
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()
|
||||
|
||||
raise ResourceException(STATUS_400_BAD_REQUEST, {'detail': details})
|
||||
# Add any non-field errors
|
||||
if form_instance.non_field_errors():
|
||||
details['errors'] = self.form.non_field_errors()
|
||||
|
||||
# Add any non-existent field errors
|
||||
for key in non_existent_fields:
|
||||
details[key] = ['This field does not exist']
|
||||
|
||||
# Bail. Note that we will still serialize this response with the appropriate content type
|
||||
raise ResourceException(Status.HTTP_400_BAD_REQUEST, {'detail': details})
|
||||
|
||||
return form_instance.cleaned_data
|
||||
|
||||
|
@ -241,7 +249,7 @@ class Resource(object):
|
|||
try:
|
||||
return self.parsers[content_type]
|
||||
except KeyError:
|
||||
raise ResourceException(STATUS_415_UNSUPPORTED_MEDIA_TYPE,
|
||||
raise ResourceException(Status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
|
||||
{'detail': 'Unsupported media type \'%s\'' % content_type})
|
||||
|
||||
|
||||
|
@ -295,14 +303,13 @@ class Resource(object):
|
|||
(accept_mimetype == mimetype)):
|
||||
return (mimetype, emitter)
|
||||
|
||||
raise ResourceException(STATUS_406_NOT_ACCEPTABLE,
|
||||
raise ResourceException(Status.HTTP_406_NOT_ACCEPTABLE,
|
||||
{'detail': 'Could not statisfy the client\'s accepted content type',
|
||||
'accepted_types': [item[0] for item in self.emitters]})
|
||||
|
||||
|
||||
def _handle_request(self, request, *args, **kwargs):
|
||||
"""
|
||||
|
||||
Broadly this consists of the following procedure:
|
||||
|
||||
0. ensure the operation is permitted
|
||||
|
@ -347,9 +354,14 @@ class Resource(object):
|
|||
|
||||
|
||||
except ResourceException, exc:
|
||||
# On exceptions we still serialize the response appropriately
|
||||
(self.resp_status, ret, self.resp_headers) = (exc.status, exc.content, exc.headers)
|
||||
|
||||
# Fall back to the default emitter if we failed to perform content negotiation
|
||||
if emitter is None:
|
||||
mimetype, emitter = self.emitters[0]
|
||||
mimetype, emitter = self.emitters[0]
|
||||
|
||||
# Provide an empty bound form if we do not have an existing form and if one is required
|
||||
if self.form_instance is None and emitter.uses_forms:
|
||||
self.form_instance = self.get_bound_form()
|
||||
|
||||
|
|
50
src/rest/status.py
Normal file
50
src/rest/status.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
|
||||
class Status(object):
|
||||
"""Descriptive HTTP status codes, for code readability."""
|
||||
HTTP_200_OK = 200
|
||||
HTTP_201_CREATED = 201
|
||||
HTTP_202_ACCEPTED = 202
|
||||
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
|
||||
HTTP_204_NO_CONTENT = 204
|
||||
HTTP_205_RESET_CONTENT = 205
|
||||
HTTP_206_PARTIAL_CONTENT = 206
|
||||
HTTP_400_BAD_REQUEST = 400
|
||||
HTTP_401_UNAUTHORIZED = 401
|
||||
HTTP_402_PAYMENT_REQUIRED = 402
|
||||
HTTP_403_FORBIDDEN = 403
|
||||
HTTP_404_NOT_FOUND = 404
|
||||
HTTP_405_METHOD_NOT_ALLOWED = 405
|
||||
HTTP_406_NOT_ACCEPTABLE = 406
|
||||
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
|
||||
HTTP_408_REQUEST_TIMEOUT = 408
|
||||
HTTP_409_CONFLICT = 409
|
||||
HTTP_410_GONE = 410
|
||||
HTTP_411_LENGTH_REQUIRED = 411
|
||||
HTTP_412_PRECONDITION_FAILED = 412
|
||||
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
|
||||
HTTP_414_REQUEST_URI_TOO_LONG = 414
|
||||
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
|
||||
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
|
||||
HTTP_417_EXPECTATION_FAILED = 417
|
||||
HTTP_100_CONTINUE = 100
|
||||
HTTP_101_SWITCHING_PROTOCOLS = 101
|
||||
HTTP_300_MULTIPLE_CHOICES = 300
|
||||
HTTP_301_MOVED_PERMANENTLY = 301
|
||||
HTTP_302_FOUND = 302
|
||||
HTTP_303_SEE_OTHER = 303
|
||||
HTTP_304_NOT_MODIFIED = 304
|
||||
HTTP_305_USE_PROXY = 305
|
||||
HTTP_306_RESERVED = 306
|
||||
HTTP_307_TEMPORARY_REDIRECT = 307
|
||||
HTTP_500_INTERNAL_SERVER_ERROR = 500
|
||||
HTTP_501_NOT_IMPLEMENTED = 501
|
||||
HTTP_502_BAD_GATEWAY = 502
|
||||
HTTP_503_SERVICE_UNAVAILABLE = 503
|
||||
HTTP_504_GATEWAY_TIMEOUT = 504
|
||||
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
|
||||
|
||||
class ResourceException(Exception):
|
||||
def __init__(self, status, content='', headers={}):
|
||||
self.status = status
|
||||
self.content = content
|
||||
self.headers = headers
|
|
@ -4,7 +4,7 @@
|
|||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from testapp import views
|
||||
import json
|
||||
#import json
|
||||
#from rest.utils import xml2dict, dict2xml
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user