Merge 'tomchristie/restframework2' into 'browsable-bootstrap'

This commit is contained in:
Alec Perkins 2012-09-09 13:23:07 -04:00
commit 4500103337
57 changed files with 938 additions and 289 deletions

View File

@ -4,6 +4,8 @@
**Author:** Tom Christie. [Follow me on Twitter][twitter]
[![Build Status](https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=restframework2)][travis]
# Overview
This branch is the redesign of Django REST framework. It is a work in progress.
@ -79,7 +81,7 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=restframework2
[twitter]: https://twitter.com/_tomchristie
[docs]: http://tomchristie.github.com/django-rest-framework/
[urlobject]: https://github.com/zacharyvoase/urlobject

View File

@ -103,4 +103,38 @@ class SessionAuthentication(BaseAuthentication):
return (user, None)
# TODO: TokenAuthentication, DigestAuthentication, OAuthAuthentication
class TokenAuthentication(BaseAuthentication):
"""
Use a token model for authentication.
A custom token model may be used here, but must have the following minimum
properties:
* key -- The string identifying the token
* user -- The user to which the token belongs
* revoked -- The status of the token
The token key should be passed in as a string to the "Authorization" HTTP
header. For example:
Authorization: 0123456789abcdef0123456789abcdef
"""
model = None
def authenticate(self, request):
key = request.META.get('HTTP_AUTHORIZATION', '').strip()
if self.model is None:
from djangorestframework.tokenauth.models import BasicToken
self.model = BasicToken
try:
token = self.model.objects.get(key=key)
except self.model.DoesNotExist:
return None
if token.user.is_active and not token.revoked:
return (token.user, token)
# TODO: DigestAuthentication, OAuthAuthentication

View File

@ -366,6 +366,59 @@ else:
return self._accept(request)
# timezone support is new in Django 1.4
try:
from django.utils import timezone
except ImportError:
timezone = None
# dateparse is ALSO new in Django 1.4
try:
from django.utils.dateparse import parse_date, parse_datetime
except ImportError:
import datetime
import re
date_re = re.compile(
r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})$'
)
datetime_re = re.compile(
r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})'
r'[T ](?P<hour>\d{1,2}):(?P<minute>\d{1,2})'
r'(?::(?P<second>\d{1,2})(?:\.(?P<microsecond>\d{1,6})\d{0,6})?)?'
r'(?P<tzinfo>Z|[+-]\d{1,2}:\d{1,2})?$'
)
time_re = re.compile(
r'(?P<hour>\d{1,2}):(?P<minute>\d{1,2})'
r'(?::(?P<second>\d{1,2})(?:\.(?P<microsecond>\d{1,6})\d{0,6})?)?'
)
def parse_date(value):
match = date_re.match(value)
if match:
kw = dict((k, int(v)) for k, v in match.groupdict().iteritems())
return datetime.date(**kw)
def parse_time(value):
match = time_re.match(value)
if match:
kw = match.groupdict()
if kw['microsecond']:
kw['microsecond'] = kw['microsecond'].ljust(6, '0')
kw = dict((k, int(v)) for k, v in kw.iteritems() if v is not None)
return datetime.time(**kw)
def parse_datetime(value):
"""Parse datetime, but w/o the timezone awareness in 1.4"""
match = datetime_re.match(value)
if match:
kw = match.groupdict()
if kw['microsecond']:
kw['microsecond'] = kw['microsecond'].ljust(6, '0')
kw = dict((k, int(v)) for k, v in kw.iteritems() if v is not None)
return datetime.datetime(**kw)
# Markdown is optional
try:

View File

@ -8,10 +8,10 @@ from django.core.exceptions import ValidationError
from django.conf import settings
from django.db import DEFAULT_DB_ALIAS
from django.db.models.related import RelatedObject
from django.utils import timezone
from django.utils.dateparse import parse_date, parse_datetime
from django.utils.encoding import is_protected_type, smart_unicode
from django.utils.translation import ugettext_lazy as _
from djangorestframework.compat import parse_date, parse_datetime
from djangorestframework.compat import timezone
def is_simple_callable(obj):
@ -317,7 +317,7 @@ class DateField(Field):
if value is None:
return value
if isinstance(value, datetime.datetime):
if settings.USE_TZ and timezone.is_aware(value):
if timezone and settings.USE_TZ and timezone.is_aware(value):
# Convert aware datetimes to the default time zone
# before casting them to dates (#17742).
default_timezone = timezone.get_default_timezone()

View File

@ -22,7 +22,7 @@ class CreateModelMixin(object):
self.object = serializer.object
self.object.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.error_data, status=status.HTTP_400_BAD_REQUEST)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class ListModelMixin(object):

View File

@ -16,6 +16,7 @@ from djangorestframework.utils import encoders
from djangorestframework.utils.breadcrumbs import get_breadcrumbs
from djangorestframework.utils.mediatypes import get_media_type_params, add_media_type_param, media_type_matches
from djangorestframework import VERSION
from djangorestframework.fields import FloatField, IntegerField, DateTimeField, DateField, EmailField, CharField, BooleanField
import string
@ -233,33 +234,31 @@ class DocumentingTemplateRenderer(BaseRenderer):
In the absence on of the Resource having an associated form then
provide a form that can be used to submit arbitrary content.
"""
if not hasattr(self.view, 'get_serializer'): # No serializer, no form.
return
# We need to map our Fields to Django's Fields.
field_mapping = dict([
[FloatField.__name__, forms.FloatField],
[IntegerField.__name__, forms.IntegerField],
[DateTimeField.__name__, forms.DateTimeField],
[DateField.__name__, forms.DateField],
[EmailField.__name__, forms.EmailField],
[CharField.__name__, forms.CharField],
[BooleanField.__name__, forms.BooleanField]
])
# Get the form instance if we have one bound to the input
form_instance = None
if method == getattr(view, 'method', view.request.method).lower():
form_instance = getattr(view, 'bound_form_instance', None)
if not form_instance and hasattr(view, 'get_bound_form'):
# Otherwise if we have a response that is valid against the form then use that
if view.response.has_content_body:
try:
form_instance = view.get_bound_form(view.response.cleaned_content, method=method)
if form_instance and not form_instance.is_valid():
form_instance = None
except Exception:
form_instance = None
# If we still don't have a form instance then try to get an unbound form
if not form_instance:
try:
form_instance = view.get_bound_form(method=method)
except Exception:
pass
# If we still don't have a form instance then try to get an unbound form which can tunnel arbitrary content types
if not form_instance:
form_instance = self._get_generic_content_form(view)
# Creating an on the fly form see: http://stackoverflow.com/questions/3915024/dynamically-creating-classes-python
fields = {}
object, data = None, None
if hasattr(self.view, 'object'):
object = self.view.object
serializer = self.view.get_serializer(instance=object)
for k, v in serializer.fields.items():
fields[k] = field_mapping[v.__class__.__name__]()
OnTheFlyForm = type("OnTheFlyForm", (forms.Form,), fields)
if object and not self.view.request.method == 'DELETE': # Don't fill in the form when the object is deleted
data = serializer.data
form_instance = OnTheFlyForm(data)
return form_instance
def _get_generic_content_form(self, view):

View File

@ -90,6 +90,7 @@ INSTALLED_APPS = (
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'djangorestframework',
'djangorestframework.tokenauth',
)
STATIC_URL = '/static/'

View File

@ -88,7 +88,10 @@ def import_from_string(val, setting):
module_path, class_name = '.'.join(parts[:-1]), parts[-1]
module = importlib.import_module(module_path)
return getattr(module, class_name)
except:
except Exception, e:
import traceback
tb = traceback.format_exc()
import pdb; pdb.set_trace()
msg = "Could not import '%s' for API setting '%s'" % (val, setting)
raise ImportError(msg)

View File

@ -8,6 +8,9 @@ from django.http import HttpResponse
from djangorestframework.views import APIView
from djangorestframework import permissions
from djangorestframework.tokenauth.models import BasicToken
from djangorestframework.authentication import TokenAuthentication
import base64
@ -20,6 +23,8 @@ class MockView(APIView):
def put(self, request):
return HttpResponse({'a': 1, 'b': 2, 'c': 3})
MockView.authentication += (TokenAuthentication,)
urlpatterns = patterns('',
(r'^$', MockView.as_view()),
)
@ -104,3 +109,45 @@ class SessionAuthTests(TestCase):
"""
response = self.csrf_client.post('/', {'example': 'example'})
self.assertEqual(response.status_code, 403)
class TokenAuthTests(TestCase):
"""Token authentication"""
urls = 'djangorestframework.tests.authentication'
def setUp(self):
self.csrf_client = Client(enforce_csrf_checks=True)
self.username = 'john'
self.email = 'lennon@thebeatles.com'
self.password = 'password'
self.user = User.objects.create_user(self.username, self.email, self.password)
self.key = 'abcd1234'
self.token = BasicToken.objects.create(key=self.key, user=self.user)
def test_post_form_passing_token_auth(self):
"""Ensure POSTing json over token auth with correct credentials passes and does not require CSRF"""
auth = self.key
response = self.csrf_client.post('/', {'example': 'example'}, HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 200)
def test_post_json_passing_token_auth(self):
"""Ensure POSTing form over token auth with correct credentials passes and does not require CSRF"""
auth = self.key
response = self.csrf_client.post('/', json.dumps({'example': 'example'}), 'application/json', HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 200)
def test_post_form_failing_token_auth(self):
"""Ensure POSTing form over token auth without correct credentials fails"""
response = self.csrf_client.post('/', {'example': 'example'})
self.assertEqual(response.status_code, 403)
def test_post_json_failing_token_auth(self):
"""Ensure POSTing json over token auth without correct credentials fails"""
response = self.csrf_client.post('/', json.dumps({'example': 'example'}), 'application/json')
self.assertEqual(response.status_code, 403)
def test_token_has_auto_assigned_key_if_none_provided(self):
"""Ensure creating a token with no key will auto-assign a key"""
token = BasicToken.objects.create(user=self.user)
self.assertEqual(len(token.key), 32)

View File

@ -55,27 +55,27 @@ class MockView(APIView):
def get(self, request, **kwargs):
response = Response(DUMMYCONTENT, status=DUMMYSTATUS)
return self.render(response)
return response
class MockGETView(APIView):
def get(self, request, **kwargs):
return {'foo': ['bar', 'baz']}
return Response({'foo': ['bar', 'baz']})
class HTMLView(APIView):
renderers = (DocumentingHTMLRenderer, )
def get(self, request, **kwargs):
return 'text'
return Response('text')
class HTMLView1(APIView):
renderers = (DocumentingHTMLRenderer, JSONRenderer)
def get(self, request, **kwargs):
return 'text'
return Response('text')
urlpatterns = patterns('',
url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderers=[RendererA, RendererB])),
@ -88,7 +88,7 @@ urlpatterns = patterns('',
)
class RendererIntegrationTests(TestCase):
class RendererEndToEndTests(TestCase):
"""
End-to-end testing of renderers using an RendererMixin on a generic view.
"""
@ -216,18 +216,6 @@ class JSONRendererTests(TestCase):
self.assertEquals(strip_trailing_whitespace(content), _indented_repr)
class MockGETView(APIView):
def get(self, request, *args, **kwargs):
return Response({'foo': ['bar', 'baz']})
urlpatterns = patterns('',
url(r'^jsonp/jsonrenderer$', MockGETView.as_view(renderers=[JSONRenderer, JSONPRenderer])),
url(r'^jsonp/nojsonrenderer$', MockGETView.as_view(renderers=[JSONPRenderer])),
)
class JSONPRendererTests(TestCase):
"""
Tests specific to the JSONP Renderer

View File

@ -94,7 +94,16 @@ class TestContentParsing(TestCase):
"""
data = {'qwerty': 'uiop'}
parsers = (FormParser, MultiPartParser)
request = factory.put('/', data, parsers=parsers)
from django import VERSION
if VERSION >= (1, 5):
from django.test.client import MULTIPART_CONTENT, BOUNDARY, encode_multipart
request = factory.put('/', encode_multipart(BOUNDARY, data), parsers=parsers,
content_type=MULTIPART_CONTENT)
else:
request = factory.put('/', data, parsers=parsers)
self.assertEqual(request.DATA.items(), data.items())
def test_standard_behaviour_determines_non_form_content_PUT(self):

View File

@ -0,0 +1,15 @@
import uuid
from django.db import models
class BasicToken(models.Model):
"""
The default authorization token model class.
"""
key = models.CharField(max_length=32, primary_key=True, blank=True)
user = models.ForeignKey('auth.User')
revoked = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if not self.key:
self.key = uuid.uuid4().hex
return super(BasicToken, self).save(*args, **kwargs)

View File

View File

@ -3,8 +3,8 @@ Helper classes for parsers.
"""
import datetime
import decimal
from django.utils import timezone
from django.utils import simplejson as json
from djangorestframework.compat import timezone
class JSONEncoder(json.JSONEncoder):
@ -25,7 +25,7 @@ class JSONEncoder(json.JSONEncoder):
elif isinstance(o, datetime.date):
return o.isoformat()
elif isinstance(o, datetime.time):
if timezone.is_aware(o):
if timezone and timezone.is_aware(o):
raise ValueError("JSON can't represent timezone-aware times.")
r = o.isoformat()
if o.microsecond:

View File

@ -1,3 +1,5 @@
<a class="github" href="authentication.py"></a>
# Authentication
Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The [permission] and [throttling] policies can then use those credentials to determine if the request should be permitted.
@ -8,7 +10,7 @@ Authentication will run the first time either the `request.user` or `request.aut
The `request.user` property will typically be set to an instance of the `contrib.auth` package's `User` class.
The `request.auth` property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.
The `request.auth` property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.
## How authentication is determined
@ -36,7 +38,7 @@ You can also set the authentication policy on a per-view basis, using the `APIVi
def get(self, request, format=None):
content = {
'user': unicode(request.user), # `django.contrib.auth.User` instance.
'user': unicode(request.user), # `django.contrib.auth.User` instance.
'auth': unicode(request.auth), # None
}
return Response(content)
@ -49,7 +51,7 @@ Or, if you're using the `@api_view` decorator with function based views.
)
def example_view(request, format=None):
content = {
'user': unicode(request.user), # `django.contrib.auth.User` instance.
'user': unicode(request.user), # `django.contrib.auth.User` instance.
'auth': unicode(request.auth), # None
}
return Response(content)
@ -65,16 +67,20 @@ If successfully authenticated, `UserBasicAuthentication` provides the following
* `request.user` will be a `django.contrib.auth.models.User` instance.
* `request.auth` will be `None`.
## TokenBasicAuthentication
## TokenAuthentication
This policy uses [HTTP Basic Authentication][basicauth], signed against a token key and secret. Token basic authentication is appropriate for client-server setups, such as native desktop and mobile clients.
This policy uses [HTTP Authentication][basicauth] with no authentication scheme. Token basic authentication is appropriate for client-server setups, such as native desktop and mobile clients. The token key should be passed in as a string to the "Authorization" HTTP header. For example:
**Note:** If you run `TokenBasicAuthentication` in production your API must be `https` only, or it will be completely insecure.
curl http://my.api.org/ -X POST -H "Authorization: 0123456789abcdef0123456789abcdef"
If successfully authenticated, `TokenBasicAuthentication` provides the following credentials.
**Note:** If you run `TokenAuthentication` in production your API must be `https` only, or it will be completely insecure.
If successfully authenticated, `TokenAuthentication` provides the following credentials.
* `request.user` will be a `django.contrib.auth.models.User` instance.
* `request.auth` will be a `djangorestframework.models.BasicToken` instance.
* `request.auth` will be a `djangorestframework.tokenauth.models.BasicToken` instance.
To use the `TokenAuthentication` policy, you must have a token model. Django REST Framework comes with a minimal default token model. To use it, include `djangorestframework.tokenauth` in your installed applications and sync your database. To use your own token model, subclass the `djangorestframework.tokenauth.TokenAuthentication` class and specify a `model` attribute that references your custom token model. The token model must provide `user`, `key`, and `revoked` attributes. Refer to the `djangorestframework.tokenauth.models.BasicToken` model as an example.
## OAuthAuthentication

View File

@ -1,3 +1,5 @@
<a class="github" href="exceptions.py"></a>
# Exceptions

View File

@ -1,3 +1,5 @@
<a class="github" href="parsers.py"></a>
# Parsers
## .parse(request)

View File

@ -1 +1,3 @@
<a class="github" href="permissions.py"></a>
# Permissions

View File

@ -1,3 +1,5 @@
<a class="github" href="renderers.py"></a>
# Renderers
## .render(response)

View File

@ -1,3 +1,5 @@
<a class="github" href="request.py"></a>
# Requests
> If you're doing REST-based web service stuff ... you should ignore request.POST.

View File

@ -1,3 +1,5 @@
<a class="github" href="response.py"></a>
# Responses
> Unlike basic HttpResponse objects, TemplateResponse objects retain the details of the context that was provided by the view to compute the response. The final output of the response is not computed until it is needed, later in the response process.

View File

@ -1,3 +1,5 @@
<a class="github" href="reverse.py"></a>
# Returning URIs from your Web APIs
> The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components.

View File

@ -1,3 +1,5 @@
<a class="github" href="serializers.py"></a>
# Serializers
> Expanding the usefulness of the serializers is something that we would

View File

@ -1,3 +1,5 @@
<a class="github" href="settings.py"></a>
# Settings
Configuration for REST framework is all namespaced inside the `API_SETTINGS` setting.

View File

@ -1,3 +1,5 @@
<a class="github" href="status.py"></a>
# Status Codes
> 418 I'm a teapot - Any attempt to brew coffee with a teapot should result in the error code "418 I'm a teapot". The resulting entity body MAY be short and stout.

View File

@ -1 +1,3 @@
<a class="github" href="throttling.py"></a>
# Throttling

View File

@ -1,9 +1,11 @@
<a class="github" href="views.py"></a>
# Views
> Django's class based views are a welcome departure from the old-style views.
>
> &mdash; [Reinout van Rees][cite]
# Views
REST framework provides a simple `APIView` class, built on Django's `django.generics.views.View`. The `APIView` class ensures five main things:
1. Any requests inside the view will become `Request` instances.

View File

@ -1,3 +1,6 @@
<iframe src="http://ghbtns.com/github-btn.html?user=tomchristie&amp;repo=django-rest-framework&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
[![Build Status](https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=restframework2)][travis]
# Django REST framework
**A toolkit for building well-connected, self-describing Web APIs.**
@ -131,6 +134,7 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=restframework2
[urlobject]: https://github.com/zacharyvoase/urlobject
[markdown]: http://pypi.python.org/pypi/Markdown/
[yaml]: http://pypi.python.org/pypi/PyYAML

View File

@ -1,5 +1,5 @@
/*!
* Bootstrap Responsive v2.1.0
* Bootstrap Responsive v2.1.1
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
@ -107,6 +107,7 @@
}
[class*="span"] {
float: left;
min-height: 1px;
margin-left: 30px;
}
.container,
@ -453,6 +454,7 @@
}
[class*="span"] {
float: left;
min-height: 1px;
margin-left: 20px;
}
.container,
@ -780,7 +782,8 @@
padding-left: 20px;
}
.navbar-fixed-top,
.navbar-fixed-bottom {
.navbar-fixed-bottom,
.navbar-static-top {
margin-right: -20px;
margin-left: -20px;
}
@ -814,8 +817,11 @@
.row-fluid [class*="span"] {
display: block;
float: none;
width: auto;
width: 100%;
margin-left: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.span12,
.row-fluid .span12 {
@ -845,6 +851,9 @@
display: inline-block;
width: auto;
}
.controls-row [class*="span"] + [class*="span"] {
margin-left: 0;
}
.modal {
position: fixed;
top: 20px;
@ -870,7 +879,7 @@
input[type="radio"] {
border: 1px solid #ccc;
}
.form-horizontal .control-group > label {
.form-horizontal .control-label {
float: none;
width: auto;
padding-top: 0;
@ -944,14 +953,14 @@
display: none;
}
.nav-collapse .nav .nav-header {
color: #555555;
color: #777777;
text-shadow: none;
}
.nav-collapse .nav > li > a,
.nav-collapse .dropdown-menu a {
padding: 9px 15px;
font-weight: bold;
color: #555555;
color: #777777;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
@ -1003,6 +1012,10 @@
.nav-collapse .dropdown-menu .divider {
display: none;
}
.nav-collapse .nav > li > .dropdown-menu:before,
.nav-collapse .nav > li > .dropdown-menu:after {
display: none;
}
.nav-collapse .navbar-form,
.nav-collapse .navbar-search {
float: none;
@ -1014,6 +1027,11 @@
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
}
.navbar-inverse .nav-collapse .navbar-form,
.navbar-inverse .nav-collapse .navbar-search {
border-top-color: #111111;
border-bottom-color: #111111;
}
.navbar .nav-collapse .nav.pull-right {
float: none;
margin-left: 0;

View File

@ -1,5 +1,5 @@
/*!
* Bootstrap v2.1.0
* Bootstrap v2.1.1
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
@ -67,6 +67,7 @@ sub {
}
img {
width: auto\9;
height: auto;
max-width: 100%;
vertical-align: middle;
@ -215,6 +216,7 @@ a:hover {
[class*="span"] {
float: left;
min-height: 1px;
margin-left: 20px;
}
@ -583,7 +585,7 @@ p {
.lead {
margin-bottom: 20px;
font-size: 20px;
font-size: 21px;
font-weight: 200;
line-height: 30px;
}
@ -608,6 +610,22 @@ cite {
color: #999999;
}
.text-warning {
color: #c09853;
}
.text-error {
color: #b94a48;
}
.text-info {
color: #3a87ad;
}
.text-success {
color: #468847;
}
h1,
h2,
h3,
@ -725,9 +743,24 @@ dd {
margin-left: 10px;
}
.dl-horizontal {
*zoom: 1;
}
.dl-horizontal:before,
.dl-horizontal:after {
display: table;
line-height: 0;
content: "";
}
.dl-horizontal:after {
clear: both;
}
.dl-horizontal dt {
float: left;
width: 120px;
width: 160px;
overflow: hidden;
clear: left;
text-align: right;
@ -736,7 +769,7 @@ dd {
}
.dl-horizontal dd {
margin-left: 130px;
margin-left: 180px;
}
hr {
@ -945,8 +978,9 @@ input[type="color"],
}
input,
textarea {
width: 210px;
textarea,
.uneditable-input {
width: 206px;
}
textarea {
@ -1039,7 +1073,7 @@ input[type="file"] {
select {
width: 220px;
background-color: #ffffff;
border: 1px solid #bbb;
border: 1px solid #cccccc;
}
select[multiple],
@ -1301,14 +1335,17 @@ input[type="checkbox"][readonly] {
.control-group.warning select,
.control-group.warning textarea {
color: #c09853;
}
.control-group.warning input,
.control-group.warning select,
.control-group.warning textarea {
border-color: #c09853;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.control-group.warning .checkbox:focus,
.control-group.warning .radio:focus,
.control-group.warning input:focus,
.control-group.warning select:focus,
.control-group.warning textarea:focus {
@ -1337,14 +1374,17 @@ input[type="checkbox"][readonly] {
.control-group.error select,
.control-group.error textarea {
color: #b94a48;
}
.control-group.error input,
.control-group.error select,
.control-group.error textarea {
border-color: #b94a48;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.control-group.error .checkbox:focus,
.control-group.error .radio:focus,
.control-group.error input:focus,
.control-group.error select:focus,
.control-group.error textarea:focus {
@ -1373,14 +1413,17 @@ input[type="checkbox"][readonly] {
.control-group.success select,
.control-group.success textarea {
color: #468847;
}
.control-group.success input,
.control-group.success select,
.control-group.success textarea {
border-color: #468847;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.control-group.success .checkbox:focus,
.control-group.success .radio:focus,
.control-group.success input:focus,
.control-group.success select:focus,
.control-group.success textarea:focus {
@ -1397,6 +1440,45 @@ input[type="checkbox"][readonly] {
border-color: #468847;
}
.control-group.info > label,
.control-group.info .help-block,
.control-group.info .help-inline {
color: #3a87ad;
}
.control-group.info .checkbox,
.control-group.info .radio,
.control-group.info input,
.control-group.info select,
.control-group.info textarea {
color: #3a87ad;
}
.control-group.info input,
.control-group.info select,
.control-group.info textarea {
border-color: #3a87ad;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.control-group.info input:focus,
.control-group.info select:focus,
.control-group.info textarea:focus {
border-color: #2d6987;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
}
.control-group.info .input-prepend .add-on,
.control-group.info .input-append .add-on {
color: #3a87ad;
background-color: #d9edf7;
border-color: #3a87ad;
}
input:focus:required:invalid,
textarea:focus:required:invalid,
select:focus:required:invalid {
@ -1503,7 +1585,6 @@ select:focus:required:invalid:focus {
.input-prepend .add-on,
.input-append .btn,
.input-prepend .btn {
margin-left: -1px;
vertical-align: top;
-webkit-border-radius: 0;
-moz-border-radius: 0;
@ -1536,6 +1617,11 @@ select:focus:required:invalid:focus {
border-radius: 3px 0 0 3px;
}
.input-append .add-on,
.input-append .btn {
margin-left: -1px;
}
.input-append .add-on:last-child,
.input-append .btn:last-child {
-webkit-border-radius: 0 3px 3px 0;
@ -1706,7 +1792,7 @@ legend + .control-group {
.form-horizontal .control-label {
float: left;
width: 140px;
width: 160px;
padding-top: 5px;
text-align: right;
}
@ -1714,21 +1800,26 @@ legend + .control-group {
.form-horizontal .controls {
*display: inline-block;
*padding-left: 20px;
margin-left: 160px;
margin-left: 180px;
*margin-left: 0;
}
.form-horizontal .controls:first-child {
*padding-left: 160px;
*padding-left: 180px;
}
.form-horizontal .help-block {
margin-top: 10px;
margin-bottom: 0;
}
.form-horizontal input + .help-block,
.form-horizontal select + .help-block,
.form-horizontal textarea + .help-block {
margin-top: 10px;
}
.form-horizontal .form-actions {
padding-left: 160px;
padding-left: 180px;
}
table {
@ -1853,7 +1944,7 @@ table {
.table-bordered colgroup + tbody tr:first-child td:last-child {
-webkit-border-top-right-radius: 4px;
border-top-right-radius: 4px;
-moz-border-right-topleft: 4px;
-moz-border-radius-topleft: 4px;
}
.table-striped tbody tr:nth-child(odd) td,
@ -1873,145 +1964,145 @@ table [class*=span],
margin-left: 0;
}
table .span1 {
.table .span1 {
float: none;
width: 44px;
margin-left: 0;
}
table .span2 {
.table .span2 {
float: none;
width: 124px;
margin-left: 0;
}
table .span3 {
.table .span3 {
float: none;
width: 204px;
margin-left: 0;
}
table .span4 {
.table .span4 {
float: none;
width: 284px;
margin-left: 0;
}
table .span5 {
.table .span5 {
float: none;
width: 364px;
margin-left: 0;
}
table .span6 {
.table .span6 {
float: none;
width: 444px;
margin-left: 0;
}
table .span7 {
.table .span7 {
float: none;
width: 524px;
margin-left: 0;
}
table .span8 {
.table .span8 {
float: none;
width: 604px;
margin-left: 0;
}
table .span9 {
.table .span9 {
float: none;
width: 684px;
margin-left: 0;
}
table .span10 {
.table .span10 {
float: none;
width: 764px;
margin-left: 0;
}
table .span11 {
.table .span11 {
float: none;
width: 844px;
margin-left: 0;
}
table .span12 {
.table .span12 {
float: none;
width: 924px;
margin-left: 0;
}
table .span13 {
.table .span13 {
float: none;
width: 1004px;
margin-left: 0;
}
table .span14 {
.table .span14 {
float: none;
width: 1084px;
margin-left: 0;
}
table .span15 {
.table .span15 {
float: none;
width: 1164px;
margin-left: 0;
}
table .span16 {
.table .span16 {
float: none;
width: 1244px;
margin-left: 0;
}
table .span17 {
.table .span17 {
float: none;
width: 1324px;
margin-left: 0;
}
table .span18 {
.table .span18 {
float: none;
width: 1404px;
margin-left: 0;
}
table .span19 {
.table .span19 {
float: none;
width: 1484px;
margin-left: 0;
}
table .span20 {
.table .span20 {
float: none;
width: 1564px;
margin-left: 0;
}
table .span21 {
.table .span21 {
float: none;
width: 1644px;
margin-left: 0;
}
table .span22 {
.table .span22 {
float: none;
width: 1724px;
margin-left: 0;
}
table .span23 {
.table .span23 {
float: none;
width: 1804px;
margin-left: 0;
}
table .span24 {
.table .span24 {
float: none;
width: 1884px;
margin-left: 0;
@ -2025,10 +2116,30 @@ table .span24 {
background-color: #f2dede;
}
.table tbody tr.warning td {
background-color: #fcf8e3;
}
.table tbody tr.info td {
background-color: #d9edf7;
}
.table-hover tbody tr.success:hover td {
background-color: #d0e9c6;
}
.table-hover tbody tr.error:hover td {
background-color: #ebcccc;
}
.table-hover tbody tr.warning:hover td {
background-color: #faf2cc;
}
.table-hover tbody tr.info:hover td {
background-color: #c4e3f3;
}
[class^="icon-"],
[class*=" icon-"] {
display: inline-block;
@ -2046,8 +2157,14 @@ table .span24 {
/* White icons with optional class, or on hover/active states of certain elements */
.icon-white,
.nav > .active > a > [class^="icon-"],
.nav > .active > a > [class*=" icon-"],
.nav-tabs > .active > a > [class^="icon-"],
.nav-tabs > .active > a > [class*=" icon-"],
.nav-pills > .active > a > [class^="icon-"],
.nav-pills > .active > a > [class*=" icon-"],
.nav-list > .active > a > [class^="icon-"],
.nav-list > .active > a > [class*=" icon-"],
.navbar-inverse .nav > .active > a > [class^="icon-"],
.navbar-inverse .nav > .active > a > [class*=" icon-"],
.dropdown-menu > li > a:hover > [class^="icon-"],
.dropdown-menu > li > a:hover > [class*=" icon-"],
.dropdown-menu > .active > a > [class^="icon-"],
@ -2759,7 +2876,7 @@ table .span24 {
.navbar-fixed-bottom .dropdown .caret {
border-top: 0;
border-bottom: 4px solid #000000;
content: "\2191";
content: "";
}
.dropup .dropdown-menu,
@ -2783,7 +2900,7 @@ table .span24 {
border-radius: 0 6px 6px 6px;
}
.dropdown-submenu:hover .dropdown-menu {
.dropdown-submenu:hover > .dropdown-menu {
display: block;
}
@ -2866,7 +2983,6 @@ table .span24 {
position: relative;
height: 0;
overflow: hidden;
overflow: visible \9;
-webkit-transition: height 0.35s ease;
-moz-transition: height 0.35s ease;
-o-transition: height 0.35s ease;
@ -3030,7 +3146,7 @@ button.close {
.btn-mini {
padding: 2px 6px;
font-size: 11px;
line-height: 16px;
line-height: 17px;
}
.btn-block {
@ -3047,6 +3163,12 @@ button.close {
margin-top: 5px;
}
input[type="submit"].btn-block,
input[type="reset"].btn-block,
input[type="button"].btn-block {
width: 100%;
}
.btn-primary.active,
.btn-warning.active,
.btn-danger.active,
@ -3284,7 +3406,8 @@ input[type="submit"].btn.btn-mini {
}
.btn-link,
.btn-link:active {
.btn-link:active,
.btn-link[disabled] {
background-color: transparent;
background-image: none;
-webkit-box-shadow: none;
@ -3307,11 +3430,17 @@ input[type="submit"].btn.btn-mini {
background-color: transparent;
}
.btn-link[disabled]:hover {
color: #333333;
text-decoration: none;
}
.btn-group {
position: relative;
*margin-left: .3em;
font-size: 0;
white-space: nowrap;
vertical-align: middle;
}
.btn-group:first-child {
@ -4018,7 +4147,7 @@ input[type="submit"].btn.btn-mini {
*z-index: 2;
margin-bottom: 20px;
overflow: visible;
color: #555555;
color: #777777;
}
.navbar-inner {
@ -4037,11 +4166,23 @@ input[type="submit"].btn.btn-mini {
-moz-border-radius: 4px;
border-radius: 4px;
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
*zoom: 1;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
}
.navbar-inner:before,
.navbar-inner:after {
display: table;
line-height: 0;
content: "";
}
.navbar-inner:after {
clear: both;
}
.navbar .container {
width: auto;
}
@ -4057,7 +4198,7 @@ input[type="submit"].btn.btn-mini {
margin-left: -20px;
font-size: 20px;
font-weight: 200;
color: #555555;
color: #777777;
text-shadow: 0 1px 0 #ffffff;
}
@ -4071,7 +4212,7 @@ input[type="submit"].btn.btn-mini {
}
.navbar-link {
color: #555555;
color: #777777;
}
.navbar-link:hover {
@ -4087,11 +4228,13 @@ input[type="submit"].btn.btn-mini {
.navbar .btn,
.navbar .btn-group {
margin-top: 6px;
margin-top: 5px;
}
.navbar .btn-group .btn {
margin: 0;
.navbar .btn-group .btn,
.navbar .input-prepend .btn,
.navbar .input-append .btn {
margin-top: 0;
}
.navbar-form {
@ -4182,9 +4325,12 @@ input[type="submit"].btn.btn-mini {
}
.navbar-fixed-top .navbar-inner,
.navbar-fixed-bottom .navbar-inner,
.navbar-static-top .navbar-inner {
border: 0;
border-width: 0 0 1px;
}
.navbar-fixed-bottom .navbar-inner {
border-width: 1px 0 0;
}
.navbar-fixed-top .navbar-inner,
@ -4233,6 +4379,7 @@ input[type="submit"].btn.btn-mini {
.navbar .nav.pull-right {
float: right;
margin-right: 0;
}
.navbar .nav > li {
@ -4242,7 +4389,7 @@ input[type="submit"].btn.btn-mini {
.navbar .nav > li > a {
float: none;
padding: 10px 15px 10px;
color: #555555;
color: #777777;
text-decoration: none;
text-shadow: 0 1px 0 #ffffff;
}
@ -4372,8 +4519,8 @@ input[type="submit"].btn.btn-mini {
}
.navbar .nav li.dropdown > .dropdown-toggle .caret {
border-top-color: #555555;
border-bottom-color: #555555;
border-top-color: #777777;
border-bottom-color: #777777;
}
.navbar .nav li.dropdown.open > .dropdown-toggle .caret,
@ -4599,12 +4746,12 @@ input[type="submit"].btn.btn-mini {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.pagination li {
.pagination ul > li {
display: inline;
}
.pagination a,
.pagination span {
.pagination ul > li > a,
.pagination ul > li > span {
float: left;
padding: 0 14px;
line-height: 38px;
@ -4614,36 +4761,36 @@ input[type="submit"].btn.btn-mini {
border-left-width: 0;
}
.pagination a:hover,
.pagination .active a,
.pagination .active span {
.pagination ul > li > a:hover,
.pagination ul > .active > a,
.pagination ul > .active > span {
background-color: #f5f5f5;
}
.pagination .active a,
.pagination .active span {
.pagination ul > .active > a,
.pagination ul > .active > span {
color: #999999;
cursor: default;
}
.pagination .disabled span,
.pagination .disabled a,
.pagination .disabled a:hover {
.pagination ul > .disabled > span,
.pagination ul > .disabled > a,
.pagination ul > .disabled > a:hover {
color: #999999;
cursor: default;
background-color: transparent;
}
.pagination li:first-child a,
.pagination li:first-child span {
.pagination ul > li:first-child > a,
.pagination ul > li:first-child > span {
border-left-width: 1px;
-webkit-border-radius: 3px 0 0 3px;
-moz-border-radius: 3px 0 0 3px;
border-radius: 3px 0 0 3px;
}
.pagination li:last-child a,
.pagination li:last-child span {
.pagination ul > li:last-child > a,
.pagination ul > li:last-child > span {
-webkit-border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
border-radius: 0 3px 3px 0;
@ -4679,7 +4826,8 @@ input[type="submit"].btn.btn-mini {
display: inline;
}
.pager a {
.pager a,
.pager span {
display: inline-block;
padding: 5px 14px;
background-color: #fff;
@ -4694,7 +4842,8 @@ input[type="submit"].btn.btn-mini {
background-color: #f5f5f5;
}
.pager .next a {
.pager .next a,
.pager .next span {
float: right;
}
@ -4703,25 +4852,26 @@ input[type="submit"].btn.btn-mini {
}
.pager .disabled a,
.pager .disabled a:hover {
.pager .disabled a:hover,
.pager .disabled span {
color: #999999;
cursor: default;
background-color: #fff;
}
.modal-open .dropdown-menu {
.modal-open .modal .dropdown-menu {
z-index: 2050;
}
.modal-open .dropdown.open {
.modal-open .modal .dropdown.open {
*z-index: 2050;
}
.modal-open .popover {
.modal-open .modal .popover {
z-index: 2060;
}
.modal-open .tooltip {
.modal-open .modal .tooltip {
z-index: 2080;
}

126
docs/static/css/drf-styles.css vendored Normal file
View File

@ -0,0 +1,126 @@
/* Set the body padding-top when above 980px to push the content down from
below the navbar, which is fixed at >980px screen widths. */
@media (min-width: 980px) {
body {
padding-top: 71px;
}
}
body {
padding-bottom: 40px;
}
pre {
font-size: 12px;
}
a.github {
float: right;
margin-top: -12px;
}
a.github:hover {
text-decoration: none;
}
.dropdown .dropdown-menu {
display: none;
}
.dropdown.open .dropdown-menu {
display: block;
}
body.index #main-content iframe {
float: right;
}
body.index #main-content iframe {
float: right;
margin-right: -15px;
}
body.index #main-content p:first-of-type {
float: right;
margin-right: 8px;
margin-top: -1px;
}
#table-of-contents {
overflow: hidden;
}
pre {
overflow: auto;
word-wrap: normal;
white-space: pre;
}
/* Preserve the spacing of the navbar across different screen sizes. */
.navbar-inner {
padding: 5px 0;
}
@media (max-width: 979px) {
.navbar .brand {
margin-left: 0;
padding-left: 0;
}
.navbar-inner .container-fluid {
padding-left: 15px;
}
}
.nav-list li.main {
font-weight: bold;
}
/* Set the table of contents to static so it flows back into the content when
viewed on tablets and smaller. */
@media (max-width: 767px) {
#table-of-contents {
position: static;
}
}
/* When the page is in two-column layout, give the main content some room
to breath on the left. */
@media (min-width: 768px) {
#main-content {
padding-left: 1em;
}
}
blockquote {
font-family: Georgia, serif;
font-size: 18px;
font-style: italic;
margin: 0.25em 0;
padding: 0.25em 40px;
line-height: 1.45;
position: relative;
color: #383838;
border-left: none;
}
blockquote:before {
display: block;
content: "\201C";
font-size: 80px;
position: absolute;
left: -10px;
top: -20px;
color: #7a7a7a;
}
blockquote p:last-child {
color: #999999;
font-size: 14px;
display: block;
margin-top: 5px;
}

30
docs/static/css/prettify.css vendored Normal file
View File

@ -0,0 +1,30 @@
.com { color: #93a1a1; }
.lit { color: #195f91; }
.pun, .opn, .clo { color: #93a1a1; }
.fun { color: #dc322f; }
.str, .atv { color: #D14; }
.kwd, .prettyprint .tag { color: #1e347b; }
.typ, .atn, .dec, .var { color: teal; }
.pln { color: #48484c; }
.prettyprint {
padding: 8px;
background-color: #f7f7f9;
border: 1px solid #e1e1e8;
}
.prettyprint.linenums {
-webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
-moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
}
/* Specify class=linenums on a pre to get line numbering */
ol.linenums {
margin: 0 0 0 33px; /* IE indents via margin-left */
}
ol.linenums li {
padding-left: 12px;
color: #bebec5;
line-height: 20px;
text-shadow: 0 1px 0 #fff;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
docs/static/img/glyphicons-halflings.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

104
docs/static/js/bootstrap-affix.js vendored Executable file
View File

@ -0,0 +1,104 @@
/* ==========================================================
* bootstrap-affix.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#affix
* ==========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */
!function ($) {
"use strict"; // jshint ;_;
/* AFFIX CLASS DEFINITION
* ====================== */
var Affix = function (element, options) {
this.options = $.extend({}, $.fn.affix.defaults, options)
this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
this.$element = $(element)
this.checkPosition()
}
Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return
var scrollHeight = $(document).height()
, scrollTop = this.$window.scrollTop()
, position = this.$element.offset()
, offset = this.options.offset
, offsetBottom = offset.bottom
, offsetTop = offset.top
, reset = 'affix affix-top affix-bottom'
, affix
if (typeof offset != 'object') offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function') offsetTop = offset.top()
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
'bottom' : offsetTop != null && scrollTop <= offsetTop ?
'top' : false
if (this.affixed === affix) return
this.affixed = affix
this.unpin = affix == 'bottom' ? position.top - scrollTop : null
this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
}
/* AFFIX PLUGIN DEFINITION
* ======================= */
$.fn.affix = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('affix')
, options = typeof option == 'object' && option
if (!data) $this.data('affix', (data = new Affix(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.affix.Constructor = Affix
$.fn.affix.defaults = {
offset: 0
}
/* AFFIX DATA-API
* ============== */
$(window).on('load', function () {
$('[data-spy="affix"]').each(function () {
var $spy = $(this)
, data = $spy.data()
data.offset = data.offset || {}
data.offsetBottom && (data.offset.bottom = data.offsetBottom)
data.offsetTop && (data.offset.top = data.offsetTop)
$spy.affix(data)
})
})
}(window.jQuery);

2
docs/static/js/bootstrap-alert.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ==========================================================
* bootstrap-alert.js v2.1.0
* bootstrap-alert.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#alerts
* ==========================================================
* Copyright 2012 Twitter, Inc.

4
docs/static/js/bootstrap-button.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ============================================================
* bootstrap-button.js v2.1.0
* bootstrap-button.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#buttons
* ============================================================
* Copyright 2012 Twitter, Inc.
@ -51,7 +51,7 @@
}
Button.prototype.toggle = function () {
var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
$parent && $parent
.find('.active')

2
docs/static/js/bootstrap-carousel.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ==========================================================
* bootstrap-carousel.js v2.1.0
* bootstrap-carousel.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#carousel
* ==========================================================
* Copyright 2012 Twitter, Inc.

2
docs/static/js/bootstrap-collapse.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* =============================================================
* bootstrap-collapse.js v2.1.0
* bootstrap-collapse.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#collapse
* =============================================================
* Copyright 2012 Twitter, Inc.

6
docs/static/js/bootstrap-dropdown.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ============================================================
* bootstrap-dropdown.js v2.1.0
* bootstrap-dropdown.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#dropdowns
* ============================================================
* Copyright 2012 Twitter, Inc.
@ -110,7 +110,7 @@
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
}
$parent = $(selector)
@ -142,7 +142,7 @@
$('html')
.on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus)
$('body')
.on('click.dropdown touchstart.dropdown.data-api', '.dropdown', function (e) { e.stopPropagation() })
.on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
.on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
})

2
docs/static/js/bootstrap-modal.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* =========================================================
* bootstrap-modal.js v2.1.0
* bootstrap-modal.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#modals
* =========================================================
* Copyright 2012 Twitter, Inc.

2
docs/static/js/bootstrap-popover.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ===========================================================
* bootstrap-popover.js v2.1.0
* bootstrap-popover.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#popovers
* ===========================================================
* Copyright 2012 Twitter, Inc.

2
docs/static/js/bootstrap-scrollspy.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* =============================================================
* bootstrap-scrollspy.js v2.1.0
* bootstrap-scrollspy.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#scrollspy
* =============================================================
* Copyright 2012 Twitter, Inc.

2
docs/static/js/bootstrap-tab.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ========================================================
* bootstrap-tab.js v2.1.0
* bootstrap-tab.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#tabs
* ========================================================
* Copyright 2012 Twitter, Inc.

2
docs/static/js/bootstrap-tooltip.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ===========================================================
* bootstrap-tooltip.js v2.1.0
* bootstrap-tooltip.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#tooltips
* Inspired by the original jQuery.tipsy by Jason Frame
* ===========================================================

2
docs/static/js/bootstrap-transition.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* ===================================================
* bootstrap-transition.js v2.1.0
* bootstrap-transition.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#transitions
* ===================================================
* Copyright 2012 Twitter, Inc.

4
docs/static/js/bootstrap-typeahead.js vendored Normal file → Executable file
View File

@ -1,5 +1,5 @@
/* =============================================================
* bootstrap-typeahead.js v2.1.0
* bootstrap-typeahead.js v2.1.1
* http://twitter.github.com/bootstrap/javascript.html#typeahead
* =============================================================
* Copyright 2012 Twitter, Inc.
@ -174,7 +174,7 @@
.on('keypress', $.proxy(this.keypress, this))
.on('keyup', $.proxy(this.keyup, this))
if ($.browser.webkit || $.browser.msie) {
if ($.browser.chrome || $.browser.webkit || $.browser.msie) {
this.$element.on('keydown', $.proxy(this.keydown, this))
}

2
docs/static/js/jquery-1.8.1-min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

28
docs/static/js/prettify.js vendored Normal file
View File

@ -0,0 +1,28 @@
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

View File

@ -7,54 +7,16 @@
<meta name="author" content="">
<!-- Le styles -->
<link href="{{ base_url }}/css/prettify.css" rel="stylesheet">
<link href="{{ base_url }}/css/bootstrap.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
.sidebar-nav {
padding: 9px 0;
}
.nav-list li.main {
font-weight: bold;
}
blockquote {
font-family: Georgia, serif;
font-size: 18px;
font-style: italic;
margin: 0.25em 0;
padding: 0.25em 40px;
line-height: 1.45;
position: relative;
color: #383838;
border-left: none;
}
blockquote:before {
display: block;
content: "\201C";
font-size: 80px;
position: absolute;
left: -10px;
top: -20px;
color: #7a7a7a;
}
blockquote p:last-child {
color: #999999;
font-size: 14px;
display: block;
margin-top: 5px;
}
</style>
<link href="{{ base_url }}/css/bootstrap-responsive.css" rel="stylesheet">
<link href="{{ base_url }}/css/drf-styles.css" rel="stylesheet">
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<body>
<body onload="prettyPrint()" class="{{ page_id }}">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
@ -108,14 +70,14 @@ margin-top: 5px;
</li>
</ul>
<ul class="nav pull-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Version: 2.0.0 <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Trunk</a></li>
<li><a href="#">2.0.0</a></li>
</ul>
</li>
</ul>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Version: 2.0.0 <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Trunk</a></li>
<li><a href="#">2.0.0</a></li>
</ul>
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
@ -123,16 +85,16 @@ margin-top: 5px;
<div class="container-fluid">
<div class="row-fluid">
<div class="span3">
<div class="well affix span3">
<ul class="nav nav-list side-nav">
{{ toc }}
</ul>
</div>
<div class="span3">
<div id="table-of-contents" class="well affix span3">
<ul class="nav nav-list side-nav">
{{ toc }}
</ul>
</div>
</div>
<div class="span9">
{{ content }}
<div id="main-content" class="span9">
{{ content }}
</div><!--/span-->
</div><!--/row-->
</div><!--/.fluid-container-->
@ -140,13 +102,15 @@ margin-top: 5px;
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="{{ base_url }}/js/jquery.js"></script>
<script src="{{ base_url }}/js/jquery-1.8.1-min.js"></script>
<script src="{{ base_url }}/js/prettify.js"></script>
<script src="{{ base_url }}/js/bootstrap-dropdown.js"></script>
<script src="{{ base_url }}/js/bootstrap-scrollspy.js"></script>
<script src="{{ base_url }}/js/bootstrap-collapse.js"></script>
<script>
//$('.side-nav').scrollspy()
var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
//$('.side-nav').scrollspy()
var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
</script>
</body></html>

View File

@ -2,43 +2,44 @@
The following people have helped make REST framework great.
* Tom Christie <tomchristie>
* Marko Tibold <markotibold>
* Paul Bagwell <pbgwl>
* Sébastien Piquemal <sebpiq>
* Carmen Wick <cwick>
* Alex Ehlke <aehlke>
* Alen Mujezinovic <flashingpumpkin>
* Carles Barrobés <txels>
* Michael Fötsch <mfoetsch>
* David Larlet <david>
* Andrew Straw <astraw>
* Zeth <zeth>
* Fernando Zunino <fzunino>
* Jens Alm <ulmus>
* Craig Blaszczyk <jakul>
* Garcia Solero <garciasolero>
* Tom Drummond <devioustree>
* Danilo Bargen <gwrtheyrn>
* Andrew McCloud <amccloud>
* Thomas Steinacher <thomasst>
* Meurig Freeman <meurig>
* Anthony Nemitz <anemitz>
* Ewoud Kohl van Wijngaarden <ekohl>
* Michael Ding <yandy>
* Mjumbe Poe <mjumbewu>
* Natim <natim>
* Sebastian Żurek <sebzur>
* Benoit C <dzen>
* Chris Pickett <bunchesofdonald>
* Ben Timby <btimby>
* Michele Lazzeri <michelelazzeri-nextage>
* Camille Harang <mammique>
* Paul Oswald <poswald>
* Sean C. Farley <scfarley>
* Daniel Izquierdo <izquierdo>
* Can Yavuz <tschan>
* Shawn Lewis <shawnlewis>
* Tom Christie - [tomchristie]
* Marko Tibold - [markotibold]
* Paul Bagwell - [pbgwl]
* Sébastien Piquemal - [sebpiq]
* Carmen Wick - [cwick]
* Alex Ehlke - [aehlke]
* Alen Mujezinovic - [flashingpumpkin]
* Carles Barrobés - [txels]
* Michael Fötsch - [mfoetsch]
* David Larlet - [david]
* Andrew Straw - [astraw]
* Zeth - [zeth]
* Fernando Zunino - [fzunino]
* Jens Alm - [ulmus]
* Craig Blaszczyk - [jakul]
* Garcia Solero - [garciasolero]
* Tom Drummond - [devioustree]
* Danilo Bargen - [gwrtheyrn]
* Andrew McCloud - [amccloud]
* Thomas Steinacher - [thomasst]
* Meurig Freeman - [meurig]
* Anthony Nemitz - [anemitz]
* Ewoud Kohl van Wijngaarden - [ekohl]
* Michael Ding - [yandy]
* Mjumbe Poe - [mjumbewu]
* Natim - [natim]
* Sebastian Żurek - [sebzur]
* Benoit C - [dzen]
* Chris Pickett - [bunchesofdonald]
* Ben Timby - [btimby]
* Michele Lazzeri - [michelelazzeri-nextage]
* Camille Harang - [mammique]
* Paul Oswald - [poswald]
* Sean C. Farley - [scfarley]
* Daniel Izquierdo - [izquierdo]
* Can Yavuz - [tschan]
* Shawn Lewis - [shawnlewis]
* Alec Perkins - [alecperkins]
Many thanks to everyone who's contributed to the project.
@ -55,11 +56,49 @@ Continuous integration testing is managed with [Travis CI][travis-ci].
To contact the author directly:
* twitter: [@_tomchristie][twitter]
* mail: [tom@tomchristie.com][email]
* email: [tom@tomchristie.com][email]
[email]: mailto:tom@tomchristie.com
[twitter]: http://twitter.com/_tomchristie
[bootstrap]: http://twitter.github.com/bootstrap/
[markdown]: http://daringfireball.net/projects/markdown/
[github]: github.com/tomchristie/django-rest-framework
[travis-ci]: https://secure.travis-ci.org/tomchristie/django-rest-framework
[travis-ci]: https://secure.travis-ci.org/tomchristie/django-rest-framework
[tomchristie]: https://github.com/tomchristie
[markotibold]: https://github.com/markotibold
[pbgwl]: https://github.com/pbgwl
[sebpiq]: https://github.com/sebpiq
[cwick]: https://github.com/cwick
[aehlke]: https://github.com/aehlke
[flashingpumpkin]: https://github.com/flashingpumpkin
[txels]: https://github.com/txels
[mfoetsch]: https://github.com/mfoetsch
[david]: https://github.com/david
[astraw]: https://github.com/astraw
[zeth]: https://github.com/zeth
[fzunino]: https://github.com/fzunino
[ulmus]: https://github.com/ulmus
[jakul]: https://github.com/jakul
[garciasolero]: https://github.com/garciasolero
[devioustree]: https://github.com/devioustree
[gwrtheyrn]: https://github.com/gwrtheyrn
[amccloud]: https://github.com/amccloud
[thomasst]: https://github.com/thomasst
[meurig]: https://github.com/meurig
[anemitz]: https://github.com/anemitz
[ekohl]: https://github.com/ekohl
[yandy]: https://github.com/yandy
[mjumbewu]: https://github.com/mjumbewu
[natim]: https://github.com/natim
[sebzur]: https://github.com/sebzur
[dzen]: https://github.com/dzen
[bunchesofdonald]: https://github.com/bunchesofdonald
[btimby]: https://github.com/btimby
[michelelazzeri-nextage]: https://github.com/michelelazzeri-nextage
[mammique]: https://github.com/mammique
[poswald]: https://github.com/poswald
[scfarley]: https://github.com/scfarley
[izquierdo]: https://github.com/izquierdo
[tschan]: https://github.com/tschan
[shawnlewis]: https://github.com/shawnlewis
[alecperkins]: https://github.com/alecperkins

View File

@ -8,6 +8,7 @@ This tutorial will walk you through the building blocks that make up REST framew
Before we do anything else we'll create a new virtual environment, using [virtualenv]. This will make sure our package configuration is keep nicely isolated from any other projects we're working on.
:::bash
mkdir ~/env
virtualenv --no-site-packages ~/env/tutorial
source ~/env/tutorial/bin/activate

View File

@ -7,30 +7,31 @@ We can also write our API views using class based views, rather than function ba
We'll start by rewriting the root view as a class based view. All this involves is a little bit of refactoring.
from blog.models import Comment
from blog.serializers import ComentSerializer
from blog.serializers import CommentSerializer
from django.http import Http404
from djangorestframework.views import APIView
from djangorestframework.response import Response
from djangorestframework.status import status
from djangorestframework import status
class CommentRoot(APIView):
"""
List all comments, or create a new comment.
"""
"""
def get(self, request, format=None):
comments = Comment.objects.all()
serializer = ComentSerializer(instance=comments)
serializer = CommentSerializer(instance=comments)
return Response(serializer.data)
def post(self, request, format=None)
serializer = ComentSerializer(request.DATA)
def post(self, request, format=None):
serializer = CommentSerializer(request.DATA)
if serializer.is_valid():
comment = serializer.object
comment.save()
return Response(serializer.serialized, status=HTTP_201_CREATED)
return Response(serializer.serialized_errors, status=HTTP_400_BAD_REQUEST)
return Response(serializer.serialized, status=status.HTTP_201_CREATED)
return Response(serializer.serialized_errors, status=status.HTTP_400_BAD_REQUEST)
comment_root = CommentRoot.as_view()
comment_root = CommentRoot.as_view()
So far, so good. It looks pretty similar to the previous case, but we've got better seperation between the different HTTP methods. We'll also need to update the instance view.
@ -38,18 +39,18 @@ So far, so good. It looks pretty similar to the previous case, but we've got be
"""
Retrieve, update or delete a comment instance.
"""
def get_object(self, pk):
try:
return Comment.objects.get(pk=pk)
except Comment.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
comment = self.get_object(pk)
serializer = CommentSerializer(instance=comment)
return Response(serializer.data)
def put(self, request, pk, format=None):
comment = self.get_object(pk)
serializer = CommentSerializer(request.DATA, instance=comment)
@ -64,7 +65,7 @@ So far, so good. It looks pretty similar to the previous case, but we've got be
comment.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
comment_instance = CommentInstance.as_view()
comment_instance = CommentInstance.as_view()
That's looking good. Again, it's still pretty similar to the function based view right now.
Okay, we're done. If you run the development server everything should be working just as before.

View File

@ -44,6 +44,6 @@ We've reached the end of our tutorial. If you want to get more involved in the
* Contribute on GitHub by reviewing issues, and submitting issues or pull requests.
* Join the REST framework group, and help build the community.
* Follow me on Twitter and say hi.
* Follow me [on Twitter](https://twitter.com/_tomchristie) and say hi.
Now go build something great.

View File

@ -24,11 +24,12 @@ else:
main_header = '<li class="main"><a href="#{{ anchor }}">{{ title }}</a></li>'
sub_header = '<li><a href="#{{ anchor }}">{{ title }}</a></li>'
code_label = r'<a class="github" href="https://github.com/tomchristie/django-rest-framework/blob/restframework2/djangorestframework/\1"><span class="label label-info">\1</span></a>'
page = open(os.path.join(docs_dir, 'template.html'), 'r').read()
# Copy static files
for static in ['css', 'js']:
for static in ['css', 'js', 'img']:
source = os.path.join(docs_dir, 'static', static)
target = os.path.join(html_dir, static)
if os.path.exists(target):
@ -65,5 +66,9 @@ for (dirpath, dirnames, filenames) in os.walk(docs_dir):
if not os.path.exists(build_dir):
os.makedirs(build_dir)
output = page.replace('{{ content }}', content).replace('{{ toc }}', toc).replace('{{ base_url }}', base_url).replace('{{ suffix }}', suffix).replace('{{ index }}', index)
output = output.replace('{{ page_id }}', filename[:-3])
output = re.sub(r'a href="([^"]*)\.md"', r'a href="\1%s"' % suffix, output)
output = re.sub(r'<pre><code>:::bash', r'<pre class="prettyprint lang-bsh">', output)
output = re.sub(r'<pre>', r'<pre class="prettyprint lang-py">', output)
output = re.sub(r'<a class="github" href="([^"]*)"></a>', code_label, output)
open(build_file, 'w').write(output.encode('utf-8'))