diff --git a/.gitignore b/.gitignore index ae73f8379..2bdf8f7eb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ *~ .* -html/ +site/ htmlcov/ coverage/ build/ diff --git a/.travis.yml b/.travis.yml index a5b6d7d91..6191e7e26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,41 @@ language: python -python: 2.7 +sudo: false env: - - TOX_ENV=flake8 - - TOX_ENV=py3.4-django1.7 - - TOX_ENV=py3.3-django1.7 - - TOX_ENV=py3.2-django1.7 - - TOX_ENV=py2.7-django1.7 - - TOX_ENV=py3.4-django1.6 - - TOX_ENV=py3.3-django1.6 - - TOX_ENV=py3.2-django1.6 - - TOX_ENV=py2.7-django1.6 - - TOX_ENV=py2.6-django1.6 - - TOX_ENV=py3.4-django1.5 - - TOX_ENV=py3.3-django1.5 - - TOX_ENV=py3.2-django1.5 - - TOX_ENV=py2.7-django1.5 - - TOX_ENV=py2.6-django1.5 - - TOX_ENV=py2.7-django1.4 - - TOX_ENV=py2.6-django1.4 + - TOX_ENV=py27-flake8 + - TOX_ENV=py27-docs + - TOX_ENV=py34-django17 + - TOX_ENV=py33-django17 + - TOX_ENV=py32-django17 + - TOX_ENV=py27-django17 + - TOX_ENV=py34-django16 + - TOX_ENV=py33-django16 + - TOX_ENV=py32-django16 + - TOX_ENV=py27-django16 + - TOX_ENV=py26-django16 + - TOX_ENV=py34-django15 + - TOX_ENV=py33-django15 + - TOX_ENV=py32-django15 + - TOX_ENV=py27-django15 + - TOX_ENV=py26-django15 + - TOX_ENV=py27-django14 + - TOX_ENV=py26-django14 + - TOX_ENV=py34-djangomaster + - TOX_ENV=py33-djangomaster + - TOX_ENV=py32-djangomaster + - TOX_ENV=py27-djangomaster + +matrix: + fast_finish: true + allow_failures: + - env: TOX_ENV=py34-djangomaster + - env: TOX_ENV=py33-djangomaster + - env: TOX_ENV=py32-djangomaster + - env: TOX_ENV=py27-djangomaster install: - - "pip install tox --download-cache $HOME/.pip-cache" + - pip install tox script: - tox -e $TOX_ENV diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6dd05a0e..698029959 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,7 +75,7 @@ You can also use the excellent [`tox`][tox] testing tool to run the tests agains It's a good idea to make pull requests early on. A pull request represents the start of a discussion, and doesn't necessarily need to be the final, finished submission. -It's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another seperate issue without interfering with an ongoing pull requests. +It's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another separate issue without interfering with an ongoing pull requests. It's also useful to remember that if you have an outstanding pull request then pushing new commits to your GitHub repo will also automatically update the pull requests. @@ -101,15 +101,15 @@ There are many great markdown editors that make working with the documentation r ## Building the documentation -To build the documentation, simply run the `mkdocs.py` script. +To build the documentation, install MkDocs with `pip install mkdocs` and then run the following command. - ./mkdocs.py + mkdocs build This will build the html output into the `html` directory. -You can build the documentation and open a preview in a browser window by using the `-p` flag. +You can build the documentation and open a preview in a browser window by using the `serve` command. - ./mkdocs.py -p + mkdocs serve ## Language style diff --git a/MANIFEST.in b/MANIFEST.in index d407865fb..d202c86ea 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -recursive-include rest_framework/static *.js *.css *.png +recursive-include rest_framework/static *.js *.css *.png *.eot *.svg *.ttf *.woff recursive-include rest_framework/templates *.html recursive-exclude * __pycache__ recursive-exclude * *.py[co] diff --git a/README.md b/README.md index 428fb8e9d..c86bb65ff 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,17 @@ # Django REST framework [![build-status-image]][travis] +[![pypi-version]][pypi] **Awesome web-browseable Web APIs.** -**Note**: Full documentation for the project is available at [http://www.django-rest-framework.org][docs]. +Full documentation for the project is available at [http://www.django-rest-framework.org][docs]. + +--- + +**Note**: The incoming 3.0 version has now been merged to the `master` branch on GitHub. For the source of the currently available PyPI version, please see the `2.4.4` tag. + +--- # Overview @@ -27,7 +34,7 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements * Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.4.2+, 1.5, 1.6, 1.7) +* Django (1.4.11+, 1.5.5+, 1.6, 1.7) # Installation @@ -175,6 +182,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [build-status-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master [travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master +[pypi-version]: https://pypip.in/version/djangorestframework/badge.svg +[pypi]: https://pypi.python.org/pypi/djangorestframework [twitter]: https://twitter.com/_tomchristie [group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework [0.4]: https://github.com/tomchristie/django-rest-framework/tree/0.4.X diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 000000000..4e3328996 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +www.django-rest-framework.org diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index 0ec5bad10..b04858e39 100755 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -1,4 +1,4 @@ - +source: authentication.py # Authentication @@ -168,12 +168,13 @@ The `curl` command line tool may be useful for testing token authenticated APIs. If you want every user to have an automatically generated Token, you can simply catch the User's `post_save` signal. + from django.conf import settings from django.contrib.auth import get_user_model from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token - @receiver(post_save, sender=get_user_model()) + @receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance) @@ -397,7 +398,7 @@ HTTP digest authentication is a widely implemented scheme that was intended to r ## Django OAuth Toolkit -The [Django OAuth Toolkit][django-oauth-toolkit] package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+. The package is maintained by [Evonove][evonove] and uses the excelllent [OAuthLib][oauthlib]. The package is well documented, and comes as a recommended alternative for OAuth 2.0 support. +The [Django OAuth Toolkit][django-oauth-toolkit] package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+. The package is maintained by [Evonove][evonove] and uses the excellent [OAuthLib][oauthlib]. The package is well documented, and comes as a recommended alternative for OAuth 2.0 support. ## Django OAuth2 Consumer @@ -415,6 +416,10 @@ The [HawkREST][hawkrest] library builds on the [Mohawk][mohawk] library to let y HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a way to achieve origin authentication and message integrity for HTTP messages. Similar to [Amazon's HTTP Signature scheme][amazon-http-signature], used by many of its services, it permits stateless, per-request authentication. [Elvio Toccalino][etoccalino] maintains the [djangorestframework-httpsignature][djangorestframework-httpsignature] package which provides an easy to use HTTP Signature Authentication mechanism. +## Djoser + +[Djoser][djoser] library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and it uses token based authentication. This is a ready to use REST implementation of Django authentication system. + [cite]: http://jacobian.org/writing/rest-worst-practices/ [http401]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2 [http403]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4 @@ -449,3 +454,4 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a [hawk]: https://github.com/hueniverse/hawk [mohawk]: http://mohawk.readthedocs.org/en/latest/ [mac]: http://tools.ietf.org/html/draft-hammer-oauth-v2-mac-token-05 +[djoser]: https://github.com/sunscrapers/djoser diff --git a/docs/api-guide/content-negotiation.md b/docs/api-guide/content-negotiation.md index 94dd59cac..bc3b09fb7 100644 --- a/docs/api-guide/content-negotiation.md +++ b/docs/api-guide/content-negotiation.md @@ -1,4 +1,4 @@ - +source: negotiation.py # Content negotiation @@ -29,7 +29,7 @@ The priorities for each of the given media types would be: If the requested view was only configured with renderers for `YAML` and `HTML`, then REST framework would select whichever renderer was listed first in the `renderer_classes` list or `DEFAULT_RENDERER_CLASSES` setting. -For more information on the `HTTP Accept` header, see [RFC 2616][accept-header] +For more information on the `HTTP Accept` header, see [RFC 2616][accept-header] --- @@ -62,7 +62,7 @@ request when selecting the appropriate parser or renderer. Select the first parser in the `.parser_classes` list. """ return parsers[0] - + def select_renderer(self, request, renderers, format_suffix): """ Select the first renderer in the `.renderer_classes` list. diff --git a/docs/api-guide/exceptions.md b/docs/api-guide/exceptions.md index e61dcfa90..8e0b1958e 100644 --- a/docs/api-guide/exceptions.md +++ b/docs/api-guide/exceptions.md @@ -1,4 +1,4 @@ - +source: exceptions.py # Exceptions diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index bfbff2adb..354ec9662 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -1,4 +1,4 @@ - +source: fields.py # Serializer fields @@ -62,7 +62,7 @@ A dictionary of error codes to error messages. ### `widget` Used only if rendering the field to HTML. -This argument sets the widget that should be used to render the field. For more details, and a list of available widgets, see [the Django documentation on form widgets][django-widgets]. +This argument sets the widget that should be used to render the field. For more details, and a list of available widgets, see [the Django documentation on form widgets][django-widgets]. ### `label` @@ -274,7 +274,27 @@ Corresponds to `django.db.models.fields.FloatField`. ## DecimalField -A decimal representation. +A decimal representation, represented in Python by a Decimal instance. + +Has two required arguments: + +- `max_digits` The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places. + +- `decimal_places` The number of decimal places to store with the number. + +For example, to validate numbers up to 999 with a resolution of 2 decimal places, you would use: + + serializers.DecimalField(max_digits=5, decimal_places=2) + +And to validate numbers up to anything less than one billion with a resolution of 10 decimal places: + + serializers.DecimalField(max_digits=19, decimal_places=10) + +This field also takes an optional argument, `coerce_to_string`. If set to `True` the representation will be output as a string. If set to `False` the representation will be left as a `Decimal` instance and the final representation will be determined by the renderer. + +If unset, this will default to the same value as the `COERCE_DECIMAL_TO_STRING` setting, which is `True` unless set otherwise. + +**Signature:** `DecimalField(max_digits, decimal_places, coerce_to_string=None)` Corresponds to `django.db.models.fields.DecimalField`. diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index cfeb43349..83977048f 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -1,4 +1,4 @@ - +source: filters.py # Filtering @@ -26,7 +26,7 @@ For example: class PurchaseList(generics.ListAPIView): serializer_class = PurchaseSerializer - + def get_queryset(self): """ This view should return a list of all the purchases @@ -38,7 +38,7 @@ For example: ## Filtering against the URL -Another style of filtering might involve restricting the queryset based on some part of the URL. +Another style of filtering might involve restricting the queryset based on some part of the URL. For example if your URL config contained an entry like this: @@ -48,7 +48,7 @@ You could then write a view that returned a purchase queryset filtered by the us class PurchaseList(generics.ListAPIView): serializer_class = PurchaseSerializer - + def get_queryset(self): """ This view should return a list of all the purchases for @@ -57,7 +57,7 @@ You could then write a view that returned a purchase queryset filtered by the us username = self.kwargs['username'] return Purchase.objects.filter(purchaser__username=username) -## Filtering against query parameters +## Filtering against query parameters A final example of filtering the initial queryset would be to determine the initial queryset based on query parameters in the url. @@ -65,7 +65,7 @@ We can override `.get_queryset()` to deal with URLs such as `http://example.com/ class PurchaseList(generics.ListAPIView): serializer_class = PurchaseSerializer - + def get_queryset(self): """ Optionally restricts the returned purchases to a given user, @@ -113,7 +113,7 @@ For instance, given the previous example, and a product with an id of `4675`, th http://example.com/api/products/4675/?category=clothing&max_price=10.00 ## Overriding the initial queryset - + Note that you can use both an overridden `.get_queryset()` and generic filtering together, and everything will work as expected. For example, if `Product` had a many-to-many relationship with `User`, named `purchase`, you might want to write a view like this: class PurchasedProductsList(generics.ListAPIView): @@ -124,7 +124,7 @@ Note that you can use both an overridden `.get_queryset()` and generic filtering model = Product serializer_class = ProductSerializer filter_class = ProductFilter - + def get_queryset(self): user = self.request.user return user.purchase_set.all() @@ -135,7 +135,7 @@ Note that you can use both an overridden `.get_queryset()` and generic filtering ## DjangoFilterBackend -The `DjangoFilterBackend` class supports highly customizable field filtering, using the [django-filter package][django-filter]. +The `DjangoFilterBackend` class supports highly customizable field filtering, using the [django-filter package][django-filter]. To use REST framework's `DjangoFilterBackend`, first install `django-filter`. @@ -216,7 +216,7 @@ This is nice, but it exposes the Django's double underscore convention as part o And now you can execute: http://example.com/api/products?manufacturer=foo - + For more details on using filter sets see the [django-filter documentation][django-filter-docs]. --- @@ -224,7 +224,7 @@ For more details on using filter sets see the [django-filter documentation][djan **Hints & Tips** * By default filtering is not enabled. If you want to use `DjangoFilterBackend` remember to make sure it is installed by using the `'DEFAULT_FILTER_BACKENDS'` setting. -* When using boolean fields, you should use the values `True` and `False` in the URL query parameters, rather than `0`, `1`, `true` or `false`. (The allowed boolean values are currently hardwired in Django's [NullBooleanSelect implementation][nullbooleanselect].) +* When using boolean fields, you should use the values `True` and `False` in the URL query parameters, rather than `0`, `1`, `true` or `false`. (The allowed boolean values are currently hardwired in Django's [NullBooleanSelect implementation][nullbooleanselect].) * `django-filter` supports filtering across relationships, using Django's double-underscore syntax. * For Django 1.3 support, make sure to install `django-filter` version 0.5.4, as later versions drop support for 1.3. @@ -316,7 +316,7 @@ Typically you'd instead control this by setting `order_by` on the initial querys queryset = User.objects.all() serializer_class = UserSerializer filter_backends = (filters.OrderingFilter,) - ordering = ('username',) + ordering = ('username',) The `ordering` attribute may be either a string or a list/tuple of strings. diff --git a/docs/api-guide/format-suffixes.md b/docs/api-guide/format-suffixes.md index 76a3367b0..20c1e9952 100644 --- a/docs/api-guide/format-suffixes.md +++ b/docs/api-guide/format-suffixes.md @@ -1,4 +1,4 @@ - +source: urlpatterns.py # Format suffixes @@ -7,7 +7,7 @@ used all the time. > > — Roy Fielding, [REST discuss mailing list][cite] -A common pattern for Web APIs is to use filename extensions on URLs to provide an endpoint for a given media type. For example, 'http://example.com/api/users.json' to serve a JSON representation. +A common pattern for Web APIs is to use filename extensions on URLs to provide an endpoint for a given media type. For example, 'http://example.com/api/users.json' to serve a JSON representation. Adding format-suffix patterns to each individual entry in the URLconf for your API is error-prone and non-DRY, so REST framework provides a shortcut to adding these patterns to your URLConf. @@ -21,7 +21,7 @@ Arguments: * **urlpatterns**: Required. A URL pattern list. * **suffix_required**: Optional. A boolean indicating if suffixes in the URLs should be optional or mandatory. Defaults to `False`, meaning that suffixes are optional by default. -* **allowed**: Optional. A list or tuple of valid format suffixes. If not provided, a wildcard format suffix pattern will be used. +* **allowed**: Optional. A list or tuple of valid format suffixes. If not provided, a wildcard format suffix pattern will be used. Example: @@ -33,7 +33,7 @@ Example: url(r'^comments/$', views.comment_list), url(r'^comments/(?P[0-9]+)/$', views.comment_detail) ] - + urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html']) When using `format_suffix_patterns`, you must make sure to add the `'format'` keyword argument to the corresponding views. For example: @@ -56,12 +56,12 @@ The name of the kwarg used may be modified by using the `FORMAT_SUFFIX_KWARG` se Also note that `format_suffix_patterns` does not support descending into `include` URL patterns. --- - + ## Accept headers vs. format suffixes There seems to be a view among some of the Web community that filename extensions are not a RESTful pattern, and that `HTTP Accept` headers should always be used instead. -It is actually a misconception. For example, take the following quote from Roy Fielding discussing the relative merits of query parameter media-type indicators vs. file extension media-type indicators: +It is actually a misconception. For example, take the following quote from Roy Fielding discussing the relative merits of query parameter media-type indicators vs. file extension media-type indicators: “That's why I always prefer extensions. Neither choice has anything to do with REST.” — Roy Fielding, [REST discuss mailing list][cite2] diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index b1c4e65ad..648ece827 100755 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -1,5 +1,5 @@ - - +source: mixins.py + generics.py # Generic views @@ -19,8 +19,8 @@ Typically when using the generic views, you'll override the view, and set severa from django.contrib.auth.models import User from myapp.serializers import UserSerializer - from rest_framework import generics - from rest_framework.permissions import IsAdminUser + from rest_framework import generics + from rest_framework.permissions import IsAdminUser class UserList(generics.ListCreateAPIView): queryset = User.objects.all() @@ -212,8 +212,6 @@ Provides a `.list(request, *args, **kwargs)` method, that implements listing a q If the queryset is populated, this returns a `200 OK` response, with a serialized representation of the queryset as the body of the response. The response data may optionally be paginated. -If the queryset is empty this returns a `200 OK` response, unless the `.allow_empty` attribute on the view is set to `False`, in which case it will return a `404 Not Found`. - ## CreateModelMixin Provides a `.create(request, *args, **kwargs)` method, that implements creating and saving a new model instance. @@ -370,6 +368,20 @@ If you are using a mixin across multiple views, you can take this a step further Using custom base classes is a good option if you have custom behavior that consistently needs to be repeated across a large number of views throughout your project. +--- + +# PUT as create + +Prior to version 3.0 the REST framework mixins treated `PUT` as either an update or a create operation, depending on if the object already existed or not. + +Allowing `PUT` as create operations is problematic, as it necessarily exposes information about the existence or non-existence of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning `404` responses. + +Both styles "`PUT` as 404" and "`PUT` as create" can be valid in different circumstances, but from version 3.0 onwards we now use 404 behavior as the default, due to it being simpler and more obvious. + +If you need to generic PUT-as-create behavior you may want to include something like [this `AllowPUTAsCreateMixin` class](https://gist.github.com/tomchristie/a2ace4577eff2c603b1b) as a mixin to your views. + +--- + # Third party packages The following third party packages provide additional generic view implementations. diff --git a/docs/api-guide/metadata.md b/docs/api-guide/metadata.md new file mode 100644 index 000000000..c3f036b75 --- /dev/null +++ b/docs/api-guide/metadata.md @@ -0,0 +1,103 @@ + + +# Metadata + +> [The `OPTIONS`] method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval. +> +> — [RFC7231, Section 4.3.7.][cite] + +REST framework includes a configurable mechanism for determining how your API should respond to `OPTIONS` requests. This allows you to return API schema or other resource information. + +There are not currently any widely adopted conventions for exactly what style of response should be returned for HTTP `OPTIONS` requests, so we provide an ad-hoc style that returns some useful information. + +Here's an example response that demonstrates the information that is returned by default. + + HTTP 200 OK + Allow: GET, POST, HEAD, OPTIONS + Content-Type: application/json + + { + "name": "To Do List", + "description": "List existing 'To Do' items, or create a new item.", + "renders": [ + "application/json", + "text/html" + ], + "parses": [ + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" + ], + "actions": { + "POST": { + "note": { + "type": "string", + "required": false, + "read_only": false, + "label": "title", + "max_length": 100 + } + } + } + } + +## Setting the metadata scheme + +You can set the metadata class globally using the `'DEFAULT_METADATA_CLASS'` settings key: + + REST_FRAMEWORK = { + 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata' + } + +Or you can set the metadata class individually for a view: + + class APIRoot(APIView): + metadata_class = APIRootMetadata + + def get(self, request, format=None): + return Response({ + ... + }) + +The REST framework package only includes a single metadata class implementation, named `SimpleMetadata`. If you want to use an alternative style you'll need to implement a custom metadata class. + +## Creating schema endpoints + +If you have specific requirements for creating schema endpoints that are accessed with regular `GET` requests, you might consider re-using the metadata API for doing so. + +For example, the following additional route could be used on a viewset to provide a linkable schema endpoint. + + @list_route(methods=['GET']) + def schema(self, request): + meta = self.metadata_class() + data = meta.determine_metadata(request, self) + return Response(data) + +There are a couple of reasons that you might choose to take this approach, including that `OPTIONS` responses [are not cacheable][no-options]. + +--- + +# Custom metadata classes + +If you want to provide a custom metadata class you should override `BaseMetadata` and implement the `determine_metadata(self, request, view)` method. + +Useful things that you might want to do could include returning schema information, using a format such as [JSON schema][json-schema], or returning debug information to admin users. + +## Example + +The following class could be used to limit the information that is returned to `OPTIONS` requests. + + class MinimalMetadata(BaseMetadata): + """ + Don't include field and other information for `OPTIONS` requests. + Just return the name and description. + """ + def determine_metadata(self, request, view): + return { + 'name': view.get_view_name(), + 'description': view.get_view_description() + } + +[cite]: http://tools.ietf.org/html/rfc7231#section-4.3.7 +[no-options]: https://www.mnot.net/blog/2012/10/29/NO_OPTIONS +[json-schema]: http://json-schema.org/ diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index e57aed1a9..9b7086c54 100644 --- a/docs/api-guide/pagination.md +++ b/docs/api-guide/pagination.md @@ -1,4 +1,4 @@ - +source: pagination.py # Pagination @@ -6,7 +6,7 @@ > > — [Django documentation][cite] -REST framework includes a `PaginationSerializer` class that makes it easy to return paginated data in a way that can then be rendered to arbitrary media types. +REST framework includes a `PaginationSerializer` class that makes it easy to return paginated data in a way that can then be rendered to arbitrary media types. ## Paginating basic data @@ -33,7 +33,7 @@ The `context` argument of the `PaginationSerializer` class may optionally includ request = RequestFactory().get('/foobar') serializer = PaginationSerializer(instance=page, context={'request': request}) serializer.data - # {'count': 4, 'next': 'http://testserver/foobar?page=2', 'previous': None, 'results': [u'john', u'paul']} + # {'count': 4, 'next': 'http://testserver/foobar?page=2', 'previous': None, 'results': [u'john', u'paul']} We could now return that data in a `Response` object, and it would be rendered into the correct media type. diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md index 72a4af643..42d77b223 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -1,4 +1,4 @@ - +source: parsers.py # Parsers @@ -161,7 +161,7 @@ By default this will include the following keys: `view`, `request`, `args`, `kwa ## Example -The following is an example plaintext parser that will populate the `request.DATA` property with a string representing the body of the request. +The following is an example plaintext parser that will populate the `request.DATA` property with a string representing the body of the request. class PlainTextParser(BaseParser): """ @@ -197,4 +197,4 @@ The following third party packages are also available. [juanriaza]: https://github.com/juanriaza [vbabiy]: https://github.com/vbabiy [djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack -[djangorestframework-camel-case]: https://github.com/vbabiy/djangorestframework-camel-case \ No newline at end of file +[djangorestframework-camel-case]: https://github.com/vbabiy/djangorestframework-camel-case diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index e867a4569..f068f0f72 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -1,4 +1,4 @@ - +source: permissions.py # Permissions @@ -12,7 +12,7 @@ Permission checks are always run at the very start of the view, before any other ## How permissions are determined -Permissions in REST framework are always defined as a list of permission classes. +Permissions in REST framework are always defined as a list of permission classes. Before running the main body of the view each permission in the list is checked. If any permission check fails an `exceptions.PermissionDenied` exception will be raised, and the main body of the view will not run. @@ -146,7 +146,13 @@ As with `DjangoModelPermissions`, this permission must only be applied to views Note that `DjangoObjectPermissions` **does not** require the `django-guardian` package, and should support other object-level backends equally well. -As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoModelPermissions` and setting the `.perms_map` property. Refer to the source code for details. Note that if you add a custom `view` permission for `GET`, `HEAD` and `OPTIONS` requests, you'll probably also want to consider adding the `DjangoObjectPermissionsFilter` class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions. +As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoModelPermissions` and setting the `.perms_map` property. Refer to the source code for details. + +--- + +**Note**: If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests, you'll want to consider also adding the `DjangoObjectPermissionsFilter` class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions. + +--- ## TokenHasReadWriteScope @@ -183,11 +189,7 @@ If you need to test if a request is a read operation or a write operation, you s --- -**Note**: In versions 2.0 and 2.1, the signature for the permission checks always included an optional `obj` parameter, like so: `.has_permission(self, request, view, obj=None)`. The method would be called twice, first for the global permission checks, with no object supplied, and second for the object-level check when required. - -As of version 2.2 this signature has now been replaced with two separate method calls, which is more explicit and obvious. The old style signature continues to work, but its use will result in a `PendingDeprecationWarning`, which is silent by default. In 2.3 this will be escalated to a `DeprecationWarning`, and in 2.4 the old-style signature will be removed. - -For more details see the [2.2 release announcement][2.2-announcement]. +**Note**: The instance-level `has_object_permission` method will only be called if the view-level `has_permission` checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call `.check_object_permissions(request, obj)`. If you are using the generic views then this will be handled for you by default. --- @@ -218,9 +220,9 @@ As well as global permissions, that are run against all incoming requests, you c def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests. - if request.method in permissions.SAFE_METHODS: + if request.method in permissions.SAFE_METHODS: return True - + # Instance must have an attribute named `owner`. return obj.owner == request.user diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md index cc4f55851..ad981b2bb 100644 --- a/docs/api-guide/relations.md +++ b/docs/api-guide/relations.md @@ -1,4 +1,4 @@ - +source: relations.py # Serializer relations @@ -33,7 +33,7 @@ In order to explain the various types of relational fields, we'll use a couple o class Meta: unique_together = ('album', 'order') order_by = 'order' - + def __unicode__(self): return '%d: %s' % (self.order, self.title) @@ -42,10 +42,10 @@ In order to explain the various types of relational fields, we'll use a couple o `RelatedField` may be used to represent the target of the relationship using its `__unicode__` method. For example, the following serializer. - + class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.RelatedField(many=True) - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -74,10 +74,10 @@ This field is read only. `PrimaryKeyRelatedField` may be used to represent the target of the relationship using its primary key. For example, the following serializer: - + class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True) - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -108,11 +108,11 @@ By default this field is read-write, although you can change this behavior using `HyperlinkedRelatedField` may be used to represent the target of the relationship using a hyperlink. For example, the following serializer: - + class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='track-detail') - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -146,11 +146,11 @@ By default this field is read-write, although you can change this behavior using `SlugRelatedField` may be used to represent the target of the relationship using a field on the target. For example, the following serializer: - + class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.SlugRelatedField(many=True, read_only=True, slug_field='title') - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -202,7 +202,7 @@ This field is always read-only. **Arguments**: -* `view_name` - The view name that should be used as the target of the relationship. If you're using [the standard router classes][routers] this wil be a string with the format `-detail`. **required**. +* `view_name` - The view name that should be used as the target of the relationship. If you're using [the standard router classes][routers] this will be a string with the format `-detail`. **required**. * `lookup_field` - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is `'pk'`. * `format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument. @@ -222,10 +222,10 @@ For example, the following serializer: class Meta: model = Track fields = ('order', 'title') - + class AlbumSerializer(serializers.ModelSerializer): tracks = TrackSerializer(many=True) - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -262,7 +262,7 @@ For, example, we could define a relational field, to serialize a track to a cust class AlbumSerializer(serializers.ModelSerializer): tracks = TrackListingField(many=True) - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -302,7 +302,7 @@ If you have not set a related name for the reverse relationship, you'll need to class AlbumSerializer(serializers.ModelSerializer): class Meta: - fields = ('track_set', ...) + fields = ('track_set', ...) See the Django documentation on [reverse relationships][reverse-relationships] for more details. @@ -315,14 +315,14 @@ For example, given the following model for a tag, which has a generic relationsh class TaggedItem(models.Model): """ Tags arbitrary model instances using a generic relation. - + See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ """ tag_name = models.SlugField() content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() tagged_object = GenericForeignKey('content_type', 'object_id') - + def __unicode__(self): return self.tag @@ -353,7 +353,7 @@ We could define a custom field that could be used to serialize tagged instances, def to_native(self, value): """ Serialize tagged objects to a simple textual representation. - """ + """ if isinstance(value, Bookmark): return 'Bookmark: ' + value.url elif isinstance(value, Note): @@ -366,7 +366,7 @@ If you need the target of the relationship to have a nested representation, you """ Serialize bookmark instances using a bookmark serializer, and note instances using a note serializer. - """ + """ if isinstance(value, Bookmark): serializer = BookmarkSerializer(value) elif isinstance(value, Note): @@ -391,7 +391,7 @@ to ``True``. ## Advanced Hyperlinked fields -If you have very specific requirements for the style of your hyperlinked relationships you can override `HyperlinkedRelatedField`. +If you have very specific requirements for the style of your hyperlinked relationships you can override `HyperlinkedRelatedField`. There are two methods you'll need to override. @@ -411,7 +411,7 @@ May raise an `ObjectDoesNotExist` exception. ### Example -For example, if all your object URLs used both a account and a slug in the the URL to reference the object, you might create a custom field like this: +For example, if all your object URLs used both a account and a slug in the the URL to reference the object, you might create a custom field like this: class CustomHyperlinkedField(serializers.HyperlinkedRelatedField): def get_url(self, obj, view_name, request, format): diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 20eed70d6..035ec1d27 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -1,4 +1,4 @@ - +source: renderers.py # Renderers @@ -74,37 +74,18 @@ If your API includes views that can serve both regular webpages and API response Renders the request data into `JSON`, using utf-8 encoding. -Note that non-ascii characters will be rendered using JSON's `\uXXXX` character escape. For example: +Note that the default style is to include unicode characters, and render the response using a compact style with no unnecessary whitespace: - {"unicode black star": "\u2605"} + {"unicode black star":"★","value":999} The client may additionally include an `'indent'` media type parameter, in which case the returned `JSON` will be indented. For example `Accept: application/json; indent=4`. { - "unicode black star": "\u2605" + "unicode black star": "★", + "value": 999 } -**.media_type**: `application/json` - -**.format**: `'.json'` - -**.charset**: `None` - -## UnicodeJSONRenderer - -Renders the request data into `JSON`, using utf-8 encoding. - -Note that non-ascii characters will not be character escaped. For example: - - {"unicode black star": "★"} - -The client may additionally include an `'indent'` media type parameter, in which case the returned `JSON` will be indented. For example `Accept: application/json; indent=4`. - - { - "unicode black star": "★" - } - -Both the `JSONRenderer` and `UnicodeJSONRenderer` styles conform to [RFC 4627][rfc4627], and are syntactically valid JSON. +The default JSON encoding style can be altered using the `UNICODE_JSON` and `COMPACT_JSON` settings keys. **.media_type**: `application/json` @@ -134,7 +115,7 @@ The `jsonp` approach is essentially a browser hack, and is [only appropriate for ## YAMLRenderer -Renders the request data into `YAML`. +Renders the request data into `YAML`. Requires the `pyyaml` package to be installed. @@ -150,7 +131,7 @@ Note that non-ascii characters will be rendered using `\uXXXX` character escape. ## UnicodeYAMLRenderer -Renders the request data into `YAML`. +Renders the request data into `YAML`. Requires the `pyyaml` package to be installed. @@ -203,7 +184,7 @@ An example of a view that uses `TemplateHTMLRenderer`: def get(self, request, *args, **kwargs): self.object = self.get_object() return Response({'user': self.object}, template_name='user_detail.html') - + You can use `TemplateHTMLRenderer` either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint. If you're building websites that use `TemplateHTMLRenderer` along with other renderer classes, you should consider listing `TemplateHTMLRenderer` as the first class in the `renderer_classes` list, so that it will be prioritised first even for browsers that send poorly formed `ACCEPT:` headers. @@ -224,7 +205,7 @@ An example of a view that uses `TemplateHTMLRenderer`: @api_view(('GET',)) @renderer_classes((StaticHTMLRenderer,)) - def simple_html_view(request): + def simple_html_view(request): data = '

Hello, world

' return Response(data) @@ -319,7 +300,7 @@ The following is an example plaintext renderer that will return a response with class PlainTextRenderer(renderers.BaseRenderer): media_type = 'text/plain' format = 'txt' - + def render(self, data, media_type=None, renderer_context=None): return data.encode(self.charset) @@ -359,7 +340,7 @@ You can do some pretty flexible things using REST framework's renderers. Some e * Provide either flat or nested representations from the same endpoint, depending on the requested media type. * Serve both regular HTML webpages, and JSON based API responses from the same endpoints. * Specify multiple types of HTML representation for API clients to use. -* Underspecify a renderer's media type, such as using `media_type = 'image/*'`, and use the `Accept` header to vary the encoding of the response. +* Underspecify a renderer's media type, such as using `media_type = 'image/*'`, and use the `Accept` header to vary the encoding of the response. ## Varying behaviour by media type diff --git a/docs/api-guide/requests.md b/docs/api-guide/requests.md index 0696fedf6..8713fa2a6 100644 --- a/docs/api-guide/requests.md +++ b/docs/api-guide/requests.md @@ -1,4 +1,4 @@ - +source: request.py # Requests @@ -49,6 +49,20 @@ If a client sends a request with a content-type that cannot be parsed then a `Un --- +# Content negotiation + +The request exposes some properties that allow you to determine the result of the content negotiation stage. This allows you to implement behaviour such as selecting a different serialisation schemes for different media types. + +## .accepted_renderer + +The renderer instance what was selected by the content negotiation stage. + +## .accepted_media_type + +A string representing the media type that was accepted by the content negotiation stage. + +--- + # Authentication REST framework provides flexible, per-request authentication, that gives you the ability to: @@ -91,7 +105,7 @@ REST framework supports a few browser enhancements such as browser-based `PUT`, Browser-based `PUT`, `PATCH` and `DELETE` forms are transparently supported. -For more information see the [browser enhancements documentation]. +For more information see the [browser enhancements documentation]. ## .content_type @@ -101,7 +115,7 @@ You won't typically need to directly access the request's content type, as you'l If you do need to access the content type of the request you should use the `.content_type` property in preference to using `request.META.get('HTTP_CONTENT_TYPE')`, as it provides transparent support for browser-based non-form content. -For more information see the [browser enhancements documentation]. +For more information see the [browser enhancements documentation]. ## .stream @@ -111,7 +125,7 @@ You won't typically need to directly access the request's content, as you'll nor If you do need to access the raw content directly, you should use the `.stream` property in preference to using `request.content`, as it provides transparent support for browser-based non-form content. -For more information see the [browser enhancements documentation]. +For more information see the [browser enhancements documentation]. --- diff --git a/docs/api-guide/responses.md b/docs/api-guide/responses.md index 5a42aa923..97f312710 100644 --- a/docs/api-guide/responses.md +++ b/docs/api-guide/responses.md @@ -1,4 +1,4 @@ - +source: response.py # Responses @@ -90,6 +90,6 @@ The `Response` class extends `SimpleTemplateResponse`, and all the usual attribu As with any other `TemplateResponse`, this method is called to render the serialized data of the response into the final response content. When `.render()` is called, the response content will be set to the result of calling the `.render(data, accepted_media_type, renderer_context)` method on the `accepted_renderer` instance. You won't typically need to call `.render()` yourself, as it's handled by Django's standard response cycle. - + [cite]: https://docs.djangoproject.com/en/dev/ref/template-response/ [statuscodes]: status-codes.md diff --git a/docs/api-guide/reverse.md b/docs/api-guide/reverse.md index 383eca4ce..71fb83f9e 100644 --- a/docs/api-guide/reverse.md +++ b/docs/api-guide/reverse.md @@ -1,4 +1,4 @@ - +source: reverse.py # Returning URLs @@ -30,7 +30,7 @@ You should **include the request as a keyword argument** to the function, for ex from rest_framework.reverse import reverse from rest_framework.views import APIView from django.utils.timezone import now - + class APIRootView(APIView): def get(self, request): year = now().year diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 61a476b8b..080230faf 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -1,4 +1,4 @@ - +source: routers.py # Routers @@ -56,10 +56,10 @@ For example, given a method like this on the `UserViewSet` class: from myapp.permissions import IsAdminOrIsSelf from rest_framework.decorators import detail_route - + class UserViewSet(ModelViewSet): ... - + @detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf]) def set_password(self, request, pk=None): ... @@ -228,7 +228,7 @@ For another example of setting the `.routes` attribute, see the source code for ## Advanced custom routers -If you want to provide totally custom behavior, you can override `BaseRouter` and override the `get_urls(self)` method. The method should inspect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the `self.registry` attribute. +If you want to provide totally custom behavior, you can override `BaseRouter` and override the `get_urls(self)` method. The method should inspect the registered viewsets and return a list of URL patterns. The registered prefix, viewset and basename tuples may be inspected by accessing the `self.registry` attribute. You may also want to override the `get_default_base_name(self, viewset)` method, or else always explicitly set the `base_name` argument when registering your viewsets with the router. diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index a3694510e..2d0ff79a4 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -1,4 +1,4 @@ - +source: serializers.py # Serializers @@ -21,7 +21,7 @@ Let's start by creating a simple object we can use for example purposes: self.email = email self.content = content self.created = created or datetime.datetime.now() - + comment = Comment(email='leila@example.com', content='foo bar') We'll declare a serializer that we can use to serialize and deserialize `Comment` objects. @@ -45,7 +45,7 @@ Declaring a serializer looks very similar to declaring a form: instance.content = attrs.get('content', instance.content) instance.created = attrs.get('created', instance.created) return instance - return Comment(**attrs) + return Comment(**attrs) The first part of serializer class defines the fields that get serialized/deserialized. The `restore_object` method defines how fully fledged instances get created when deserializing data. @@ -83,8 +83,8 @@ If you need to customize the serialized value of a particular field, you can do These methods are essentially the reverse of `validate_` (see *Validation* below.) ## Deserializing objects - -Deserialization is similar. First we parse a stream into Python native datatypes... + +Deserialization is similar. First we parse a stream into Python native datatypes... from StringIO import StringIO from rest_framework.parsers import JSONParser @@ -174,7 +174,7 @@ To save the deserialized objects created by a serializer, call the `.save()` met The default behavior of the method is to simply call `.save()` on the deserialized object instance. You can override the default save behaviour by overriding the `.save_object(obj)` method on the serializer class. -The generic views provided by REST framework call the `.save()` method when updating or creating entities. +The generic views provided by REST framework call the `.save()` method when updating or creating entities. ## Dealing with nested objects @@ -288,12 +288,12 @@ By default the serializer class will use the `id` key on the incoming data to de slug = serializers.CharField(max_length=100) created = serializers.DateTimeField() ... # Various other fields - + def get_identity(self, data): """ This hook is required for bulk update. We need to override the default, to use the slug as the identity. - + Note that the data has not yet been validated at this point, so we need to deal gracefully with incorrect datatypes. """ @@ -361,7 +361,7 @@ The `depth` option should be set to an integer value that indicates the depth of If you want to customize the way the serialization is done (e.g. using `allow_add_remove`) you'll need to define the field yourself. -## Specifying which fields should be read-only +## Specifying which fields should be read-only You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the `read_only=True` attribute, you may use the `read_only_fields` Meta option, like so: @@ -371,9 +371,9 @@ You may wish to specify multiple fields as read-only. Instead of adding each fi fields = ('id', 'account_name', 'users', 'created') read_only_fields = ('account_name',) -Model fields which have `editable=False` set, and `AutoField` fields will be set to read-only by default, and do not need to be added to the `read_only_fields` option. +Model fields which have `editable=False` set, and `AutoField` fields will be set to read-only by default, and do not need to be added to the `read_only_fields` option. -## Specifying which fields should be write-only +## Specifying which fields should be write-only You may wish to specify multiple fields as write-only. Instead of adding each field explicitly with the `write_only=True` attribute, you may use the `write_only_fields` Meta option, like so: @@ -387,12 +387,12 @@ You may wish to specify multiple fields as write-only. Instead of adding each f """ Instantiate a new User instance. """ - assert instance is None, 'Cannot update users with CreateUserSerializer' + assert instance is None, 'Cannot update users with CreateUserSerializer' user = User(email=attrs['email'], username=attrs['username']) user.set_password(attrs['password']) return user - -## Specifying fields explicitly + +## Specifying fields explicitly You can add extra fields to a `ModelSerializer` or override the default fields by declaring fields on the class, just as you would for a `Serializer` class. @@ -413,6 +413,16 @@ Alternative representations include serializing using hyperlinks, serializing co For full details see the [serializer relations][relations] documentation. +## Inheritance of the 'Meta' class + +The inner `Meta` class on serializers is not inherited from parent classes by default. This is the same behaviour as with Django's `Model` and `ModelForm` classes. If you want the `Meta` class to inherit from a parent class you must do so explicitly. For example: + + class AccountSerializer(MyBaseSerializer): + class Meta(MyBaseSerializer.Meta): + model = Account + +Typically we would recommend *not* using inheritance on inner Meta classes, but instead declaring all options explicitly. + --- # HyperlinkedModelSerializer @@ -514,10 +524,10 @@ For example, if you wanted to be able to set which fields should be used by a se def __init__(self, *args, **kwargs): # Don't pass the 'fields' arg up to the superclass fields = kwargs.pop('fields', None) - + # Instantiate the superclass normally super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - + if fields: # Drop any fields that are not specified in the `fields` argument. allowed = set(fields) @@ -540,7 +550,7 @@ This would then allow you to do the following: ## Customising the default fields -The `field_mapping` attribute is a dictionary that maps model classes to serializer classes. Overriding the attribute will let you set a different set of default serializer classes. +The `field_mapping` attribute is a dictionary that maps model classes to serializer classes. Overriding the attribute will let you set a different set of default serializer classes. For more advanced customization than simply changing the default serializer class you can override various `get__field` methods. Doing so will allow you to customize the arguments that each serializer field is initialized with. Each of these methods may either return a field or serializer instance, or `None`. diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index 27a091633..0aa4b6a97 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -1,4 +1,4 @@ - +source: settings.py # Settings @@ -74,7 +74,7 @@ Default: #### DEFAULT_PERMISSION_CLASSES -A list or tuple of permission classes, that determines the default set of permissions checked at the start of a view. +A list or tuple of permission classes, that determines the default set of permissions checked at the start of a view. Permission must be granted by every class in the list. Default: @@ -154,13 +154,13 @@ Default: `None` ### SEARCH_PARAM -The name of a query paramater, which can be used to specify the search term used by `SearchFilter`. +The name of a query parameter, which can be used to specify the search term used by `SearchFilter`. Default: `search` #### ORDERING_PARAM -The name of a query paramater, which can be used to specify the ordering of results returned by `OrderingFilter`. +The name of a query parameter, which can be used to specify the ordering of results returned by `OrderingFilter`. Default: `ordering` @@ -265,7 +265,7 @@ A format string that should be used by default for rendering the output of `Date May be any of `None`, `'iso-8601'` or a Python [strftime format][strftime] string. -Default: `None` +Default: `'iso-8601'` #### DATETIME_INPUT_FORMATS @@ -281,7 +281,7 @@ A format string that should be used by default for rendering the output of `Date May be any of `None`, `'iso-8601'` or a Python [strftime format][strftime] string. -Default: `None` +Default: `'iso-8601'` #### DATE_INPUT_FORMATS @@ -297,7 +297,7 @@ A format string that should be used by default for rendering the output of `Time May be any of `None`, `'iso-8601'` or a Python [strftime format][strftime] string. -Default: `None` +Default: `'iso-8601'` #### TIME_INPUT_FORMATS @@ -309,6 +309,46 @@ Default: `['iso-8601']` --- +## Encodings + +#### UNICODE_JSON + +When set to `True`, JSON responses will allow unicode characters in responses. For example: + + {"unicode black star":"★"} + +When set to `False`, JSON responses will escape non-ascii characters, like so: + + {"unicode black star":"\u2605"} + +Both styles conform to [RFC 4627][rfc4627], and are syntactically valid JSON. The unicode style is preferred as being more user-friendly when inspecting API responses. + +Default: `True` + +#### COMPACT_JSON + +When set to `True`, JSON responses will return compact representations, with no spacing after `':'` and `','` characters. For example: + + {"is_admin":false,"email":"jane@example"} + +When set to `False`, JSON responses will return slightly more verbose representations, like so: + + {"is_admin": false, "email": "jane@example"} + +The default style is to return minified responses, in line with [Heroku's API design guidelines][heroku-minified-json]. + +Default: `True` + +#### COERCE_DECIMAL_TO_STRING + +When returning decimal objects in API representations that do not support a native decimal type, it is normally best to return the value as a string. This avoids the loss of precision that occurs with binary floating point implementations. + +When set to `True`, the serializer `DecimalField` class will return strings instead of `Decimal` objects. When set to `False`, serializers will return `Decimal` objects, which the default JSON encoder will return as floats. + +Default: `True` + +--- + ## View names and descriptions **The following settings are used to generate the view names and descriptions, as used in responses to `OPTIONS` requests, and as used in the browsable API.** @@ -359,6 +399,12 @@ This should be a function with the following signature: Default: `'rest_framework.views.exception_handler'` +#### NON_FIELD_ERRORS_KEY + +A string representing the key that should be used for serializer errors that do not refer to a specific field, but are instead general errors. + +Default: `'non_field_errors'` + #### URL_FIELD_NAME A string representing the key that should be used for the URL fields generated by `HyperlinkedModelSerializer`. @@ -378,4 +424,6 @@ An integer of 0 or more, that may be used to specify the number of application p Default: `None` [cite]: http://www.python.org/dev/peps/pep-0020/ +[rfc4627]: http://www.ietf.org/rfc/rfc4627.txt +[heroku-minified-json]: https://github.com/interagent/http-api-design#keep-json-minified-in-all-responses [strftime]: http://docs.python.org/2/library/time.html#time.strftime diff --git a/docs/api-guide/status-codes.md b/docs/api-guide/status-codes.md index 64c464349..d81e092c5 100644 --- a/docs/api-guide/status-codes.md +++ b/docs/api-guide/status-codes.md @@ -1,4 +1,4 @@ - +source: status.py # Status Codes @@ -27,7 +27,7 @@ The module also includes a set of helper functions for testing if a status code url = reverse('index') response = self.client.get(url) self.assertTrue(status.is_success(response.status_code)) - + For more information on proper usage of HTTP status codes see [RFC 2616][rfc2616] and [RFC 6585][rfc6585]. @@ -51,7 +51,7 @@ This class of status code indicates that the client's request was successfully r HTTP_205_RESET_CONTENT HTTP_206_PARTIAL_CONTENT -## Redirection - 3xx +## Redirection - 3xx This class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md index 72c339613..d059fdab5 100644 --- a/docs/api-guide/testing.md +++ b/docs/api-guide/testing.md @@ -1,4 +1,4 @@ - +source: test.py # Testing @@ -170,7 +170,7 @@ This can be a useful shortcut if you're testing the API but don't want to have t To unauthenticate subsequent requests, call `force_authenticate` setting the user and/or token to `None`. - client.force_authenticate(user=None) + client.force_authenticate(user=None) ## CSRF validation @@ -197,7 +197,7 @@ You can use any of REST framework's test case classes as you would for the regul from django.core.urlresolvers import reverse from rest_framework import status - from rest_framework.test import APITestCase + from rest_framework.test import APITestCase class AccountTests(APITestCase): def test_create_account(self): diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md index 832304f15..3f668867c 100644 --- a/docs/api-guide/throttling.md +++ b/docs/api-guide/throttling.md @@ -1,4 +1,4 @@ - +source: throttling.py # Throttling @@ -74,7 +74,7 @@ If you need to strictly identify unique client IP addresses, you'll need to firs It is important to understand that if you configure the `NUM_PROXIES` setting, then all clients behind a unique [NAT'd](http://en.wikipedia.org/wiki/Network_address_translation) gateway will be treated as a single client. -Further context on how the `X-Forwarded-For` header works, and identifing a remote client IP can be [found here][identifing-clients]. +Further context on how the `X-Forwarded-For` header works, and identifying a remote client IP can be [found here][identifing-clients]. ## Setting up the cache @@ -83,9 +83,9 @@ The throttle classes provided by REST framework use Django's cache backend. You If you need to use a cache other than `'default'`, you can do so by creating a custom throttle class and setting the `cache` attribute. For example: class CustomAnonRateThrottle(AnonRateThrottle): - cache = get_cache('alternate') + cache = get_cache('alternate') -You'll need to rememeber to also set your custom throttle class in the `'DEFAULT_THROTTLE_CLASSES'` settings key, or using the `throttle_classes` view attribute. +You'll need to remember to also set your custom throttle class in the `'DEFAULT_THROTTLE_CLASSES'` settings key, or using the `throttle_classes` view attribute. --- @@ -147,15 +147,15 @@ For example, given the following views... class ContactListView(APIView): throttle_scope = 'contacts' ... - + class ContactDetailView(ApiView): throttle_scope = 'contacts' ... - class UploadView(APIView): + class UploadView(APIView): throttle_scope = 'uploads' ... - + ...and the following settings. REST_FRAMEWORK = { @@ -178,6 +178,8 @@ To create a custom throttle, override `BaseThrottle` and implement `.allow_reque Optionally you may also override the `.wait()` method. If implemented, `.wait()` should return a recommended number of seconds to wait before attempting the next request, or `None`. The `.wait()` method will only be called if `.allow_request()` has previously returned `False`. +If the `.wait()` method is implemented and the request is throttled, then a `Retry-After` header will be included in the response. + ## Example The following is an example of a rate throttle, that will randomly throttle 1 in every 10 requests. diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md new file mode 100644 index 000000000..ac2f32485 --- /dev/null +++ b/docs/api-guide/validators.md @@ -0,0 +1,225 @@ + + +# Validators + +> Validators can be useful for re-using validation logic between different types of fields. +> +> — [Django documentation][cite] + +Most of the time you're dealing with validation in REST framework you'll simply be relying on the default field validation, or writing explicit validation methods on serializer or field classes. + +However, sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes. + +## Validation in REST framework + +Validation in Django REST framework serializers is handled a little differently to how validation works in Django's `ModelForm` class. + +With `ModelForm` the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons: + +* It introduces a proper separation of concerns, making your code behavior more obvious. +* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behavior being used for `ModelSerializer` is simple to replicate. +* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance. + +When you're using `ModelSerializer` all of this is handled automatically for you. If you want to drop down to using a `Serializer` classes instead, then you need to define the validation rules explicitly. + +#### Example + +As an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint. + + class CustomerReportRecord(models.Model): + time_raised = models.DateTimeField(default=timezone.now, editable=False) + reference = models.CharField(unique=True, max_length=20) + description = models.TextField() + +Here's a basic `ModelSerializer` that we can use for creating or updating instances of `CustomerReportRecord`: + + class CustomerReportSerializer(serializers.ModelSerializer): + class Meta: + model = CustomerReportRecord + +If we open up the Django shell using `manage.py shell` we can now + + >>> from project.example.serializers import CustomerReportSerializer + >>> serializer = CustomerReportSerializer() + >>> print(repr(serializer)) + CustomerReportSerializer(): + id = IntegerField(label='ID', read_only=True) + time_raised = DateTimeField(read_only=True) + reference = CharField(max_length=20, validators=[]) + description = CharField(style={'type': 'textarea'}) + +The interesting bit here is the `reference` field. We can see that the uniqueness constraint is being explicitly enforced by a validator on the serializer field. + +Because of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below. + +--- + +## UniqueValidator + +This validator can be used to enforce the `unique=True` constraint on model fields. +It takes a single required argument, and an optional `messages` argument: + +* `queryset` *required* - This is the queryset against which uniqueness should be enforced. +* `message` - The error message that should be used when validation fails. + +This validator should be applied to *serializer fields*, like so: + + slug = SlugField( + max_length=100, + validators=[UniqueValidator(queryset=BlogPost.objects.all())] + ) + +## UniqueTogetherValidator + +This validator can be used to enforce `unique_together` constraints on model instances. +It has two required arguments, and a single optional `messages` argument: + +* `queryset` *required* - This is the queryset against which uniqueness should be enforced. +* `fields` *required* - A list or tuple of field names which should make a unique set. These must exist as fields on the serializer class. +* `message` - The error message that should be used when validation fails. + +The validator should be applied to *serializer classes*, like so: + + class ExampleSerializer(serializers.Serializer): + # ... + class Meta: + # ToDo items belong to a parent list, and have an ordering defined + # by the 'position' field. No two items in a given list may share + # the same position. + validators = [ + UniqueTogetherValidator( + queryset=ToDoItem.objects.all(), + fields=('list', 'position') + ) + ] + +--- + +**Note**: The `UniqueTogetherValidation` class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input. + +--- + +## UniqueForDateValidator + +## UniqueForMonthValidator + +## UniqueForYearValidator + +These validators can be used to enforce the `unique_for_date`, `unique_for_month` and `unique_for_year` constraints on model instances. They take the following arguments: + +* `queryset` *required* - This is the queryset against which uniqueness should be enforced. +* `field` *required* - A field name against which uniqueness in the given date range will be validated. This must exist as a field on the serializer class. +* `date_field` *required* - A field name which will be used to determine date range for the uniqueness constrain. This must exist as a field on the serializer class. +* `message` - The error message that should be used when validation fails. + +The validator should be applied to *serializer classes*, like so: + + class ExampleSerializer(serializers.Serializer): + # ... + class Meta: + # Blog posts should have a slug that is unique for the current year. + validators = [ + UniqueForYearValidator( + queryset=BlogPostItem.objects.all(), + field='slug', + date_field='published' + ) + ] + +The date field that is used for the validation is always required to be present on the serializer class. You can't simply rely on a model class `default=...`, because the value being used for the default wouldn't be generated until after the validation has run. + +There are a couple of styles you may want to use for this depending on how you want your API to behave. If you're using `ModelSerializer` you'll probably simply rely on the defaults that REST framework generates for you, but if you are using `Serializer` or simply want more explicit control, use on of the styles demonstrated below. + +#### Using with a writable date field. + +If you want the date field to be writable the only thing worth noting is that you should ensure that it is always available in the input data, either by setting a `default` argument, or by setting `required=True`. + + published = serializers.DateTimeField(required=True) + +#### Using with a read-only date field. + +If you want the date field to be visible, but not editable by the user, then set `read_only=True` and additionally set a `default=...` argument. + + published = serializers.DateTimeField(read_only=True, default=timezone.now) + +The field will not be writable to the user, but the default value will still be passed through to the `validated_data`. + +#### Using with a hidden date field. + +If you want the date field to be entirely hidden from the user, then use `HiddenField`. This field type does not accept user input, but instead always returns it's default value to the `validated_data` in the serializer. + + published = serializers.HiddenField(default=timezone.now) + +--- + +**Note**: The `UniqueForValidation` classes always imposes an implicit constraint that the fields they are applied to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input. + +--- + +# Advanced 'default' argument usage + +Validators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that *is* available as input to the validator. + +Two patterns that you may want to use for this sort of validation include: + +* Using `HiddenField`. This field will be present in `validated_data` but *will not* be used in the serializer output representation. +* Using a standard field with `read_only=True`, but that also includes a `default=…` argument. This field *will* be used in the serializer output representation, but cannot be set directly by the user. + +REST framework includes a couple of defaults that may be useful in this context. + +#### CurrentUserDefault + +A default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer. + + owner = serializers.HiddenField( + default=CurrentUserDefault() + ) + +#### CreateOnlyDefault + +A default class that can be used to *only set a default argument during create operations*. During updates the field is omitted. + +It takes a single argument, which is the default value or callable that should be used during create operations. + + created_at = serializers.DateTimeField( + read_only=True, + default=CreateOnlyDefault(timezone.now) + ) + +--- + +# Writing custom validators + +You can use any of Django's existing validators, or write your own custom validators. + +## Function based + +A validator may be any callable that raises a `serializers.ValidationError` on failure. + + def even_number(value): + if value % 2 != 0: + raise serializers.ValidationError('This field must be an even number.') + +## Class based + +To write a class based validator, use the `__call__` method. Class based validators are useful as they allow you to parameterize and reuse behavior. + + class MultipleOf: + def __init__(self, base): + self.base = base + + def __call__(self, value): + if value % self.base != 0 + message = 'This field must be a multiple of %d.' % self.base + raise serializers.ValidationError(message) + +#### Using `set_context()` + +In some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a `set_context` method on a class based validator. + + def set_context(self, serializer_field): + # Determine if this is an update or a create operation. + # In `__call__` we can then use that information to modify the validation behavior. + self.is_update = serializer_field.parent.instance is not None + +[cite]: https://docs.djangoproject.com/en/dev/ref/validators/ diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md index 194a7a6b3..31c62682f 100644 --- a/docs/api-guide/views.md +++ b/docs/api-guide/views.md @@ -1,4 +1,5 @@ - +source: decorators.py + views.py # Class Based Views @@ -26,7 +27,7 @@ For example: class ListUsers(APIView): """ View to list all users in the system. - + * Requires token authentication. * Only admin users are able to access this view. """ @@ -54,7 +55,7 @@ The following attributes control the pluggable aspects of API views. ### .permission_classes -### .content_negotiation_class +### .content_negotiation_class ## API policy instantiation methods diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 9030e3ee0..9249d8756 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -1,4 +1,4 @@ - +source: viewsets.py # ViewSets diff --git a/docs/css/default.css b/docs/css/default.css index 7f3acfed2..8c9cd5363 100644 --- a/docs/css/default.css +++ b/docs/css/default.css @@ -181,7 +181,7 @@ body{ } .navbar .navbar-inner .nav li, .navbar .navbar-inner .nav li a, .navbar .navbar-inner .brand{ - color: white; + color: white; } .nav-list > .active > a, .navbar .navbar-inner .nav li a:hover { @@ -190,8 +190,20 @@ body{ } .navbar .navbar-inner .dropdown-menu li a, .navbar .navbar-inner .dropdown-menu li{ - color: #A30000; + color: #A30000; } + +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + background-image: none; +} + +.navbar-inverse .nav .dropdown .active > a, +.navbar-inverse .nav .dropdown .active > a:hover, +.navbar-inverse .nav .dropdown .active > a:focus { + background-color: #eeeeee; +} + .navbar .navbar-inner .dropdown-menu li a:hover{ background: #eeeeee; color: #c20000; diff --git a/docs/index.md b/docs/index.md index b18b71d20..9312bb2fd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,6 +9,10 @@ --- +**Note**: The incoming 3.0 version has now been merged to the `master` branch on GitHub. For the source of the currently available PyPI version, please see the `2.4.4` tag. + +--- +

- Django REST framework is a powerful and flexible toolkit that makes it easy to build Web APIs. @@ -43,14 +44,12 @@ Some reasons you might want to use REST framework: **Above**: *Screenshot from the browsable API* ----- - ## Requirements REST framework requires the following: * Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.4.2+, 1.5, 1.6, 1.7) +* Django (1.4.11+, 1.5.5+, 1.6, 1.7) The following packages are optional: @@ -173,6 +172,7 @@ The API guide is your complete reference manual to all the functionality provide * [Serializers][serializers] * [Serializer fields][fields] * [Serializer relations][relations] + * [Authentication][authentication] * [Permissions][permissions] * [Throttling][throttling] @@ -294,6 +294,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [serializers]: api-guide/serializers.md [fields]: api-guide/fields.md [relations]: api-guide/relations.md +[validation]: api-guide/validation.md [authentication]: api-guide/authentication.md [permissions]: api-guide/permissions.md [throttling]: api-guide/throttling.md diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index a91fb9785..000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -markdown>=2.1.0 diff --git a/docs/template.html b/docs/template.html deleted file mode 100644 index bb3ae221a..000000000 --- a/docs/template.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - {{ title }} - - - - - - - - - - - - - - - - - - - - -
- - - -
-
- - - - -
- -
- -
- - -
-
- -
- {{ content }} -
-
-
-
- -
-
- - - - - - - - - - - diff --git a/docs/topics/2.2-announcement.md b/docs/topics/2.2-announcement.md index a997c7829..1df52cff2 100644 --- a/docs/topics/2.2-announcement.md +++ b/docs/topics/2.2-announcement.md @@ -42,7 +42,7 @@ The 2.2 release makes a few changes to the API, in order to make it more consist The `ManyRelatedField()` style is being deprecated in favor of a new `RelatedField(many=True)` syntax. -For example, if a user is associated with multiple questions, which we want to represent using a primary key relationship, we might use something like the following: +For example, if a user is associated with multiple questions, which we want to represent using a primary key relationship, we might use something like the following: class UserSerializer(serializers.HyperlinkedModelSerializer): questions = serializers.PrimaryKeyRelatedField(many=True) @@ -58,10 +58,10 @@ The change also applies to serializers. If you have a nested serializer, you sh class Meta: model = Track fields = ('name', 'duration') - + class AlbumSerializer(serializer.ModelSerializer): tracks = TrackSerializer(many=True) - + class Meta: model = Album fields = ('album_name', 'artist', 'tracks') @@ -87,7 +87,7 @@ For example, is a user account has an optional foreign key to a company, that yo This is in line both with the rest of the serializer fields API, and with Django's `Form` and `ModelForm` API. -Using `required` throughout the serializers API means you won't need to consider if a particular field should take `blank` or `null` arguments instead of `required`, and also means there will be more consistent behavior for how fields are treated when they are not present in the incoming data. +Using `required` throughout the serializers API means you won't need to consider if a particular field should take `blank` or `null` arguments instead of `required`, and also means there will be more consistent behavior for how fields are treated when they are not present in the incoming data. The `null=True` argument will continue to function, and will imply `required=False`, but will raise a `PendingDeprecationWarning`. diff --git a/docs/topics/2.3-announcement.md b/docs/topics/2.3-announcement.md index 7c800afa0..9c9f3e9f6 100644 --- a/docs/topics/2.3-announcement.md +++ b/docs/topics/2.3-announcement.md @@ -27,7 +27,7 @@ As an example of just how simple REST framework APIs can now be, here's an API w class GroupViewSet(viewsets.ModelViewSet): model = Group - + # Routers provide an easy way of automatically determining the URL conf router = routers.DefaultRouter() router.register(r'users', UserViewSet) @@ -197,13 +197,13 @@ Usage of the old-style attributes continues to be supported, but will raise a `P For most cases APIs using model fields will behave as previously, however if you are using a custom renderer, not provided by REST framework, then you may now need to add support for rendering `Decimal` instances to your renderer implementation. -## ModelSerializers and reverse relationships +## ModelSerializers and reverse relationships The support for adding reverse relationships to the `fields` option on a `ModelSerializer` class means that the `get_related_field` and `get_nested_field` method signatures have now changed. In the unlikely event that you're providing a custom serializer class, and implementing these methods you should note the new call signature for both methods is now `(self, model_field, related_model, to_many)`. For reverse relationships `model_field` will be `None`. -The old-style signature will continue to function but will raise a `PendingDeprecationWarning`. +The old-style signature will continue to function but will raise a `PendingDeprecationWarning`. ## View names and descriptions @@ -211,7 +211,7 @@ The mechanics of how the names and descriptions used in the browseable API are g If you've been customizing this behavior, for example perhaps to use `rst` markup for the browseable API, then you'll need to take a look at the implementation to see what updates you need to make. -Note that the relevant methods have always been private APIs, and the docstrings called them out as intended to be deprecated. +Note that the relevant methods have always been private APIs, and the docstrings called them out as intended to be deprecated. --- diff --git a/docs/topics/2.4-announcement.md b/docs/topics/2.4-announcement.md index 8e4f3bb23..f38c743c0 100644 --- a/docs/topics/2.4-announcement.md +++ b/docs/topics/2.4-announcement.md @@ -23,7 +23,7 @@ The documentation has previously stated that usage of the more explicit style is Doing so will mean that there are cases of API code where you'll now need to include a serializer class where you previously were just using the `.model` shortcut. However we firmly believe that it is the right trade-off to make. -Removing the shortcut takes away an unneccessary layer of abstraction, and makes your codebase more explicit without any significant extra complexity. It also results in better consistency, as there's now only one way to set the serializer class and queryset attributes for the view, instead of two. +Removing the shortcut takes away an unnecessary layer of abstraction, and makes your codebase more explicit without any significant extra complexity. It also results in better consistency, as there's now only one way to set the serializer class and queryset attributes for the view, instead of two. The `DEFAULT_MODEL_SERIALIZER_CLASS` API setting is now also deprecated. diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md new file mode 100644 index 000000000..6a662326b --- /dev/null +++ b/docs/topics/3.0-announcement.md @@ -0,0 +1,890 @@ +## Pre-release notes: + +The 3.0 release is now in beta and ready for final testing. You can install the development version directly from GitHub like so: + + pip install https://github.com/tomchristie/django-rest-framework/archive/3.0-beta.zip + +Currently the only known remaining blockers are documentation issues and tickets. Any critical bugs raised in the next week or two will be resolved for the 3.0 release, but otherwise consider this as code-complete. + +Please work through this document throughly in order to understand the API differences that exist between 2.4 and 3.0. + +**Your feedback on the upgrade process and 3.0 changes is hugely important!** + +Please do get in touch via twitter, IRC, a GitHub ticket, or the discussion group. + +--- + +# REST framework 3.0 + +The 3.0 release of Django REST framework is the result of almost four years of iteration and refinement. It comprehensively addresses some of the previous remaining design issues in serializers, fields and the generic views. + +This release is incremental in nature. There *are* some breaking API changes, and upgrading *will* require you to read the release notes carefully, but the migration path should otherwise be relatively straightforward. + +The difference in quality of the REST framework API and implementation should make writing, maintaining and debugging your application far easier. + +## New features + +Notable features of this new release include: + +* Printable representations on serializers that allow you to inspect exactly what fields are present on the instance. +* Simple model serializers that are vastly easier to understand and debug, and that make it easy to switch between the implicit `ModelSerializer` class and the explicit `Serializer` class. +* A new `BaseSerializer` class, making it easier to write serializers for alternative storage backends, or to completely customize your serialization and validation logic. +* A cleaner fields API including new classes such as `ListField` and `MultipleChoiceField`. +* [Super simple default implementations][mixins.py] for the generic views. +* Support for overriding how validation errors are handled by your API. +* A metadata API that allows you to customize how `OPTIONS` requests are handled by your API. +* A more compact JSON output with unicode style encoding turned on by default. +* Templated based HTML form rendering for serializers. This will be finalized as public API in the upcoming 3.1 release. + +Significant new functionality continues to be planned for the 3.1 and 3.2 releases. These releases will correspond to the two [Kickstarter stretch goals](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) - "Feature improvements" and "Admin interface". Further 3.x releases will present simple upgrades, without the same level of fundamental API changes necessary for the 3.0 release. + +Below is an in-depth guide to the API changes and migration notes for 3.0. + +--- + +## Request objects + +#### The `.data` and `.query_params` properties. + +The usage of `request.DATA` and `request.FILES` is now pending deprecation in favor of a single `request.data` attribute that contains *all* the parsed data. + +Having separate attributes is reasonable for web applications that only ever parse url-encoded or multipart requests, but makes less sense for the general-purpose request parsing that REST framework supports. + +You may now pass all the request data to a serializer class in a single argument: + + # Do this... + ExampleSerializer(data=request.data) + +Instead of passing the files argument separately: + + # Don't do this... + ExampleSerializer(data=request.DATA, files=request.FILES) + + +The usage of `request.QUERY_PARAMS` is now pending deprecation in favor of the lowercased `request.query_params`. + +## Serializers + +#### Single-step object creation. + +Previously the serializers used a two-step object creation, as follows: + +1. Validating the data would create an object instance. This instance would be available as `serializer.object`. +2. Calling `serializer.save()` would then save the object instance to the database. + +This style is in-line with how the `ModelForm` class works in Django, but is problematic for a number of reasons: + +* Some data, such as many-to-many relationships, cannot be added to the object instance until after it has been saved. This type of data needed to be hidden in some undocumented state on the object instance, or kept as state on the serializer instance so that it could be used when `.save()` is called. +* Instantiating model instances directly means that you cannot use model manager classes for instance creation, e.g. `ExampleModel.objects.create(...)`. Manager classes are an excellent layer at which to enforce business logic and application-level data constraints. +* The two step process makes it unclear where to put deserialization logic. For example, should extra attributes such as the current user get added to the instance during object creation or during object save? + +We now use single-step object creation, like so: + +1. Validating the data makes the cleaned data available as `serializer.validated_data`. +2. Calling `serializer.save()` then saves and returns the new object instance. + +The resulting API changes are further detailed below. + +#### The `.create()` and `.update()` methods. + +The `.restore_object()` method is now replaced with two separate methods, `.create()` and `.update()`. + +These methods also replace the optional `.save_object()` method, which no longer exists. + +When using the `.create()` and `.update()` methods you should both create *and save* the object instance. This is in contrast to the previous `.restore_object()` behavior that would instantiate the object but not save it. + +The following example from the tutorial previously used `restore_object()` to handle both creating and updating object instances. + + def restore_object(self, attrs, instance=None): + if instance: + # Update existing instance + instance.title = attrs.get('title', instance.title) + instance.code = attrs.get('code', instance.code) + instance.linenos = attrs.get('linenos', instance.linenos) + instance.language = attrs.get('language', instance.language) + instance.style = attrs.get('style', instance.style) + return instance + + # Create new instance + return Snippet(**attrs) + +This would now be split out into two separate methods. + + def update(self, instance, validated_data): + instance.title = validated_data.get('title', instance.title) + instance.code = validated_data.get('code', instance.code) + instance.linenos = validated_data.get('linenos', instance.linenos) + instance.language = validated_data.get('language', instance.language) + instance.style = validated_data.get('style', instance.style) + instance.save() + return instance + + def create(self, validated_data): + return Snippet.objects.create(**validated_data) + +Note that these methods should return the newly created object instance. + +#### Use `.validated_data` instead of `.object`. + +You must now use the `.validated_data` attribute if you need to inspect the data before saving, rather than using the `.object` attribute, which no longer exists. + +For example the following code *is no longer valid*: + + if serializer.is_valid(): + name = serializer.object.name # Inspect validated field data. + logging.info('Creating ticket "%s"' % name) + serializer.object.user = request.user # Include the user when saving. + serializer.save() + +Instead of using `.object` to inspect a partially constructed instance, you would now use `.validated_data` to inspect the cleaned incoming values. Also you can't set extra attributes on the instance directly, but instead pass them to the `.save()` method as keyword arguments. + +The corresponding code would now look like this: + + if serializer.is_valid(): + name = serializer.validated_data['name'] # Inspect validated field data. + logging.info('Creating ticket "%s"' % name) + serializer.save(user=request.user) # Include the user when saving. + +#### Using `.is_valid(raise_exception=True)` + +The `.is_valid()` method now takes an optional boolean flag, `raise_exception`. + +Calling `.is_valid(raise_exception=True)` will cause a `ValidationError` to be raised if the serializer data contains validation errors. This error will be handled by REST framework's default exception handler, allowing you to remove error response handling from your view code. + +The handling and formatting of error responses may be altered globally by using the `EXCEPTION_HANDLER` settings key. + +This change also means it's now possible to alter the style of error responses used by the built-in generic views, without having to include mixin classes or other overrides. + +#### Using `serializers.ValidationError`. + +Previously `serializers.ValidationError` error was simply a synonym for `django.core.exceptions.ValidationError`. This has now been altered so that it inherits from the standard `APIException` base class. + +The reason behind this is that Django's `ValidationError` class is intended for use with HTML forms and its API makes using it slightly awkward with nested validation errors that can occur in serializers. + +For most users this change shouldn't require any updates to your codebase, but it is worth ensuring that whenever raising validation errors you are always using the `serializers.ValidationError` exception class, and not Django's built-in exception. + +We strongly recommend that you use the namespaced import style of `import serializers` and not `from serializers import ValidationError` in order to avoid any potential confusion. + +#### Change to `validate_`. + +The `validate_` method hooks that can be attached to serializer classes change their signature slightly and return type. Previously these would take a dictionary of all incoming data, and a key representing the field name, and would return a dictionary including the validated data for that field: + + def validate_score(self, attrs, source): + if attrs['score'] % 10 != 0: + raise serializers.ValidationError('This field should be a multiple of ten.') + return attrs + +This is now simplified slightly, and the method hooks simply take the value to be validated, and return the validated value. + + def validate_score(self, value): + if value % 10 != 0: + raise serializers.ValidationError('This field should be a multiple of ten.') + return value + +Any ad-hoc validation that applies to more than one field should go in the `.validate(self, attrs)` method as usual. + +Because `.validate_` would previously accept the complete dictionary of attributes, it could be used to validate a field depending on the input in another field. Now if you need to do this you should use `.validate()` instead. + +You can either return `non_field_errors` from the validate method by raising a simple `ValidationError` + + def validate(self, attrs): + # serializer.errors == {'non_field_errors': ['A non field error']} + raise serializers.ValidationError('A non field error') + +Alternatively if you want the errors to be against a specific field, use a dictionary of when instantiating the `ValidationError`, like so: + + def validate(self, attrs): + # serializer.errors == {'my_field': ['A field error']} + raise serializers.ValidationError({'my_field': 'A field error'}) + +This ensures you can still write validation that compares all the input fields, but that marks the error against a particular field. + +#### Differences between ModelSerializer validation and ModelForm. + +This change also means that we no longer use the `.full_clean()` method on model instances, but instead perform all validation explicitly on the serializer. This gives a cleaner separation, and ensures that there's no automatic validation behavior on `ModelSerializer` classes that can't also be easily replicated on regular `Serializer` classes. + +It's important to note that this change also means that the model `.clean()` method will not be called as part of serializer validation, as it would be if using a `ModelForm`. Use the serializer `.validate()` method to perform a final validation step on incoming data where required. + +#### Writable nested serialization. + +REST framework 2.x attempted to automatically support writable nested serialization, but the behavior was complex and non-obvious. Attempting to automatically handle these case is problematic: + +* There can be complex dependencies involved in order of saving multiple related model instances. +* It's unclear what behavior the user should expect when related models are passed `None` data. +* It's unclear how the user should expect to-many relationships to handle updates, creations and deletions of multiple records. + +Using the `depth` option on `ModelSerializer` will now create **read-only nested serializers** by default. + +If you try to use a writable nested serializer without writing a custom `create()` and/or `update()` method you'll see an assertion error when you attempt to save the serializer. For example: + + >>> class ProfileSerializer(serializers.ModelSerializer): + >>> class Meta: + >>> model = Profile + >>> fields = ('address', 'phone') + >>> + >>> class UserSerializer(serializers.ModelSerializer): + >>> profile = ProfileSerializer() + >>> class Meta: + >>> model = User + >>> fields = ('username', 'email', 'profile') + >>> + >>> data = { + >>> 'username': 'lizzy', + >>> 'email': 'lizzy@example.com', + >>> 'profile': {'address': '123 Acacia Avenue', 'phone': '01273 100200'} + >>> } + >>> + >>> serializer = UserSerializer(data=data) + >>> serializer.save() + AssertionError: The `.create()` method does not support nested writable fields by default. Write an explicit `.create()` method for serializer `UserSerializer`, or set `read_only=True` on nested serializer fields. + +To use writable nested serialization you'll want to declare a nested field on the serializer class, and write the `create()` and/or `update()` methods explicitly. + + class UserSerializer(serializers.ModelSerializer): + profile = ProfileSerializer() + + class Meta: + model = User + fields = ('username', 'email', 'profile') + + def create(self, validated_data): + profile_data = validated_data.pop('profile') + user = User.objects.create(**validated_data) + Profile.objects.create(user=user, **profile_data) + return user + +The single-step object creation makes this far simpler and more obvious than the previous `.restore_object()` behavior. + +#### Printable serializer representations. + +Serializer instances now support a printable representation that allows you to inspect the fields present on the instance. + +For instance, given the following example model: + + class LocationRating(models.Model): + location = models.CharField(max_length=100) + rating = models.IntegerField() + created_by = models.ForeignKey(User) + +Let's create a simple `ModelSerializer` class corresponding to the `LocationRating` model. + + class LocationRatingSerializer(serializer.ModelSerializer): + class Meta: + model = LocationRating + +We can now inspect the serializer representation in the Django shell, using `python manage.py shell`... + + >>> serializer = LocationRatingSerializer() + >>> print(serializer) # Or use `print serializer` in Python 2.x + LocationRatingSerializer(): + id = IntegerField(label='ID', read_only=True) + location = CharField(max_length=100) + rating = IntegerField() + created_by = PrimaryKeyRelatedField(queryset=User.objects.all()) + +#### The `extra_kwargs` option. + +The `write_only_fields` option on `ModelSerializer` has been moved to `PendingDeprecation` and replaced with a more generic `extra_kwargs`. + + class MySerializer(serializer.ModelSerializer): + class Meta: + model = MyModel + fields = ('id', 'email', 'notes', 'is_admin') + extra_kwargs = { + 'is_admin': {'write_only': True} + } + +Alternatively, specify the field explicitly on the serializer class: + + class MySerializer(serializer.ModelSerializer): + is_admin = serializers.BooleanField(write_only=True) + + class Meta: + model = MyModel + fields = ('id', 'email', 'notes', 'is_admin') + +The `read_only_fields` option remains as a convenient shortcut for the more common case. + +#### Changes to `HyperlinkedModelSerializer`. + +The `view_name` and `lookup_field` options have been moved to `PendingDeprecation`. They are no longer required, as you can use the `extra_kwargs` argument instead: + + class MySerializer(serializer.HyperlinkedModelSerializer): + class Meta: + model = MyModel + fields = ('url', 'email', 'notes', 'is_admin') + extra_kwargs = { + 'url': {'lookup_field': 'uuid'} + } + +Alternatively, specify the field explicitly on the serializer class: + + class MySerializer(serializer.HyperlinkedModelSerializer): + url = serializers.HyperlinkedIdentityField( + view_name='mymodel-detail', + lookup_field='uuid' + ) + + class Meta: + model = MyModel + fields = ('url', 'email', 'notes', 'is_admin') + +#### Fields for model methods and properties. + +With `ModelSerializer` you can now specify field names in the `fields` option that refer to model methods or properties. For example, suppose you have the following model: + + class Invitation(models.Model): + created = models.DateTimeField() + to_email = models.EmailField() + message = models.CharField(max_length=1000) + + def expiry_date(self): + return self.created + datetime.timedelta(days=30) + +You can include `expiry_date` as a field option on a `ModelSerializer` class. + + class InvitationSerializer(serializers.ModelSerializer): + class Meta: + model = Invitation + fields = ('to_email', 'message', 'expiry_date') + +These fields will be mapped to `serializers.ReadOnlyField()` instances. + + >>> serializer = InvitationSerializer() + >>> print repr(serializer) + InvitationSerializer(): + to_email = EmailField(max_length=75) + message = CharField(max_length=1000) + expiry_date = ReadOnlyField() + +#### The `ListSerializer` class. + +The `ListSerializer` class has now been added, and allows you to create base serializer classes for only accepting multiple inputs. + + class MultipleUserSerializer(ListSerializer): + child = UserSerializer() + +You can also still use the `many=True` argument to serializer classes. It's worth noting that `many=True` argument transparently creates a `ListSerializer` instance, allowing the validation logic for list and non-list data to be cleanly separated in the REST framework codebase. + +You will typically want to *continue to use the existing `many=True` flag* rather than declaring `ListSerializer` classes explicitly, but declaring the classes explicitly can be useful if you need to write custom `create` or `update` methods for bulk updates, or provide for other custom behavior. + +See also the new `ListField` class, which validates input in the same way, but does not include the serializer interfaces of `.is_valid()`, `.data`, `.save()` and so on. + +#### The `BaseSerializer` class. + +REST framework now includes a simple `BaseSerializer` class that can be used to easily support alternative serialization and deserialization styles. + +This class implements the same basic API as the `Serializer` class: + +* `.data` - Returns the outgoing primitive representation. +* `.is_valid()` - Deserializes and validates incoming data. +* `.validated_data` - Returns the validated incoming data. +* `.errors` - Returns an errors during validation. +* `.save()` - Persists the validated data into an object instance. + +There are four methods that can be overridden, depending on what functionality you want the serializer class to support: + +* `.to_representation()` - Override this to support serialization, for read operations. +* `.to_internal_value()` - Override this to support deserialization, for write operations. +* `.create()` and `.update()` - Overide either or both of these to support saving instances. + +##### Read-only `BaseSerializer` classes. + +To implement a read-only serializer using the `BaseSerializer` class, we just need to override the `.to_representation()` method. Let's take a look at an example using a simple Django model: + + class HighScore(models.Model): + created = models.DateTimeField(auto_now_add=True) + player_name = models.CharField(max_length=10) + score = models.IntegerField() + +It's simple to create a read-only serializer for converting `HighScore` instances into primitive data types. + + class HighScoreSerializer(serializers.BaseSerializer): + def to_representation(self, obj): + return { + 'score': obj.score, + 'player_name': obj.player_name + } + +We can now use this class to serialize single `HighScore` instances: + + @api_view(['GET']) + def high_score(request, pk): + instance = HighScore.objects.get(pk=pk) + serializer = HighScoreSerializer(instance) + return Response(serializer.data) + +Or use it to serialize multiple instances: + + @api_view(['GET']) + def all_high_scores(request): + queryset = HighScore.objects.order_by('-score') + serializer = HighScoreSerializer(queryset, many=True) + return Response(serializer.data) + +##### Read-write `BaseSerializer` classes. + +To create a read-write serializer we first need to implement a `.to_internal_value()` method. This method returns the validated values that will be used to construct the object instance, and may raise a `ValidationError` if the supplied data is in an incorrect format. + +Once you've implemented `.to_internal_value()`, the basic validation API will be available on the serializer, and you will be able to use `.is_valid()`, `.validated_data` and `.errors`. + +If you want to also support `.save()` you'll need to also implement either or both of the `.create()` and `.update()` methods. + +Here's a complete example of our previous `HighScoreSerializer`, that's been updated to support both read and write operations. + + class HighScoreSerializer(serializers.BaseSerializer): + def to_internal_value(self, data): + score = data.get('score') + player_name = data.get('player_name') + + # Perform the data validation. + if not score: + raise ValidationError({ + 'score': 'This field is required.' + }) + if not player_name: + raise ValidationError({ + 'player_name': 'This field is required.' + }) + if len(player_name) > 10: + raise ValidationError({ + 'player_name': 'May not be more than 10 characters.' + }) + + # Return the validated values. This will be available as + # the `.validated_data` property. + return { + 'score': int(score), + 'player_name': player_name + } + + def to_representation(self, obj): + return { + 'score': obj.score, + 'player_name': obj.player_name + } + + def create(self, validated_data): + return HighScore.objects.create(**validated_data) + +#### Creating new generic serializers with `BaseSerializer`. + +The `BaseSerializer` class is also useful if you want to implement new generic serializer classes for dealing with particular serialization styles, or for integrating with alternative storage backends. + +The following class is an example of a generic serializer that can handle coercing aribitrary objects into primitive representations. + + class ObjectSerializer(serializers.BaseSerializer): + """ + A read-only serializer that coerces arbitrary complex objects + into primitive representations. + """ + def to_representation(self, obj): + for attribute_name in dir(obj): + attribute = getattr(obj, attribute_name) + if attribute_name('_'): + # Ignore private attributes. + pass + elif hasattr(attribute, '__call__'): + # Ignore methods and other callables. + pass + elif isinstance(attribute, (str, int, bool, float, type(None))): + # Primitive types can be passed through unmodified. + output[attribute_name] = attribute + elif isinstance(attribute, list): + # Recursivly deal with items in lists. + output[attribute_name] = [ + self.to_representation(item) for item in attribute + ] + elif isinstance(attribute, dict): + # Recursivly deal with items in dictionarys. + output[attribute_name] = { + str(key): self.to_representation(value) + for key, value in attribute.items() + } + else: + # Force anything else to its string representation. + output[attribute_name] = str(attribute) + +## Serializer fields + +#### The `Field` and `ReadOnly` field classes. + +There are some minor tweaks to the field base classes. + +Previously we had these two base classes: + +* `Field` as the base class for read-only fields. A default implementation was included for serializing data. +* `WritableField` as the base class for read-write fields. + +We now use the following: + +* `Field` is the base class for all fields. It does not include any default implementation for either serializing or deserializing data. +* `ReadOnlyField` is a concrete implementation for read-only fields that simply returns the attribute value without modification. + +#### The `required`, `allow_none`, `allow_blank` and `default` arguments. + +REST framework now has more explicit and clear control over validating empty values for fields. + +Previously the meaning of the `required=False` keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be `None` or the empty string. + +We now have a better separation, with separate `required`, `allow_none` and `allow_blank` arguments. + +The following set of arguments are used to control validation of empty values: + +* `required=False`: The value does not need to be present in the input, and will not be passed to `.create()` or `.update()` if it is not seen. +* `default=`: The value does not need to be present in the input, and a default value will be passed to `.create()` or `.update()` if it is not seen. +* `allow_none=True`: `None` is a valid input. +* `allow_blank=True`: `''` is valid input. For `CharField` and subclasses only. + +Typically you'll want to use `required=False` if the corresponding model field has a default value, and additionally set either `allow_none=True` or `allow_blank=True` if required. + +The `default` argument is also available and always implies that the field is not required to be in the input. It is unnecessary to use the `required` argument when a default is specified, and doing so will result in an error. + +#### Coercing output types. + +The previous field implementations did not forcibly coerce returned values into the correct type in many cases. For example, an `IntegerField` would return a string output if the attribute value was a string. We now more strictly coerce to the correct return type, leading to more constrained and expected behavior. + +#### The `ListField` class. + +The `ListField` class has now been added. This field validates list input. It takes a `child` keyword argument which is used to specify the field used to validate each item in the list. For example: + + scores = ListField(child=IntegerField(min_value=0, max_value=100)) + +You can also use a declarative style to create new subclasses of `ListField`, like this: + + class ScoresField(ListField): + child = IntegerField(min_value=0, max_value=100) + +We can now use the `ScoresField` class inside another serializer: + + scores = ScoresField() + +See also the new `ListSerializer` class, which validates input in the same way, but also includes the serializer interfaces of `.is_valid()`, `.data`, `.save()` and so on. + +#### The `ChoiceField` class may now accept a flat list. + +The `ChoiceField` class may now accept a list of choices in addition to the existing style of using a list of pairs of `(name, display_value)`. The following is now valid: + + color = ChoiceField(choices=['red', 'green', 'blue']) + +#### The `MultipleChoiceField` class. + +The `MultipleChoiceField` class has been added. This field acts like `ChoiceField`, but returns a set, which may include none, one or many of the valid choices. + +#### Changes to the custom field API. + +The `from_native(self, value)` and `to_native(self, data)` method names have been replaced with the more obviously named `to_internal_value(self, data)` and `to_representation(self, value)`. + +The `field_from_native()` and `field_to_native()` methods are removed. Previously you could use these methods if you wanted to customise the behaviour in a way that did not simply lookup the field value from the object. For example... + + def field_to_native(self, obj, field_name): + """A custom read-only field that returns the class name.""" + return obj.__class__.__name__ + +Now if you need to access the entire object you'll instead need to override one or both of the following: + +* Use `get_attribute` to modify the attribute value passed to `to_representation()`. +* Use `get_value` to modify the data value passed `to_internal_value()`. + +For example: + + def get_attribute(self, obj): + # Pass the entire object through to `to_representation()`, + # instead of the standard attribute lookup. + return obj + + def to_representation(self, value): + return value.__class__.__name__ + +#### Explicit `queryset` required on relational fields. + +Previously relational fields that were explicitly declared on a serializer class could omit the queryset argument if (and only if) they were declared on a `ModelSerializer`. + +This code *would be valid* in `2.4.3`: + + class AccountSerializer(serializers.ModelSerializer): + organizations = serializers.SlugRelatedField(slug_field='name') + + class Meta: + model = Account + +However this code *would not be valid* in `2.4.3`: + + # Missing `queryset` + class AccountSerializer(serializers.Serializer): + organizations = serializers.SlugRelatedField(slug_field='name') + + def restore_object(self, attrs, instance=None): + # ... + +The queryset argument is now always required for writable relational fields. +This removes some magic and makes it easier and more obvious to move between implicit `ModelSerializer` classes and explicit `Serializer` classes. + + class AccountSerializer(serializers.ModelSerializer): + organizations = serializers.SlugRelatedField( + slug_field='name', + queryset=Organization.objects.all() + ) + + class Meta: + model = Account + +The `queryset` argument is only ever required for writable fields, and is not required or valid for fields with `read_only=True`. + +#### Optional argument to `SerializerMethodField`. + +The argument to `SerializerMethodField` is now optional, and defaults to `get_`. For example the following is valid: + + class AccountSerializer(serializers.Serializer): + # `method_name='get_billing_details'` by default. + billing_details = serializers.SerializerMethodField() + + def get_billing_details(self, account): + return calculate_billing(account) + +In order to ensure a consistent code style an assertion error will be raised if you include a redundant method name argument that matches the default method name. For example, the following code *will raise an error*: + + billing_details = serializers.SerializerMethodField('get_billing_details') + +#### Enforcing consistent `source` usage. + +I've see several codebases that unnecessarily include the `source` argument, setting it to the same value as the field name. This usage is redundant and confusing, making it less obvious that `source` is usually not required. + +The following usage will *now raise an error*: + + email = serializers.EmailField(source='email') + +#### The `UniqueValidator` and `UniqueTogetherValidator` classes. + +REST framework now provides new validators that allow you to ensure field uniqueness, while still using a completely explicit `Serializer` class instead of using `ModelSerializer`. + +The `UniqueValidator` should be applied to a serializer field, and takes a single `queryset` argument. + + from rest_framework import serializers + from rest_framework.validators import UniqueValidator + + class OrganizationSerializer(serializers.Serializer): + url = serializers.HyperlinkedIdentityField(view_name='organization_detail') + created = serializers.DateTimeField(read_only=True) + name = serializers.CharField( + max_length=100, + validators=UniqueValidator(queryset=Organization.objects.all()) + ) + +The `UniqueTogetherValidator` should be applied to a serializer, and takes a `queryset` argument and a `fields` argument which should be a list or tuple of field names. + + class RaceResultSerializer(serializers.Serializer): + category = serializers.ChoiceField(['5k', '10k']) + position = serializers.IntegerField() + name = serializers.CharField(max_length=100) + + default_validators = [UniqueTogetherValidator( + queryset=RaceResult.objects.all(), + fields=('category', 'position') + )] + +#### The `UniqueForDateValidator` classes. + +REST framework also now includes explicit validator classes for validating the `unique_for_date`, `unique_for_month`, and `unique_for_year` model field constraints. These are used internally instead of calling into `Model.full_clean()`. + +These classes are documented in the [Validators](../api-guide/validators.md) section of the documentation. + +## Generic views + +#### Simplification of view logic. + +The view logic for the default method handlers has been significantly simplified, due to the new serializers API. + +#### Changes to pre/post save hooks. + +The `pre_save` and `post_save` hooks no longer exist, but are replaced with `perform_create(self, serializer)` and `perform_update(self, serializer)`. + +These methods should save the object instance by calling `serializer.save()`, adding in any additional arguments as required. They may also perform any custom pre-save or post-save behavior. + +For example: + + def perform_create(self, serializer): + # Include the owner attribute directly, rather than from request data. + instance = serializer.save(owner=self.request.user) + # Perform a custom post-save action. + send_email(instance.to_email, instance.message) + +The `pre_delete` and `post_delete` hooks no longer exist, and are replaced with `.perform_destroy(self, instance)`, which should delete the instance and perform any custom actions. + + def perform_destroy(self, instance): + # Perform a custom pre-delete action. + send_deletion_alert(user=instance.created_by, deleted=instance) + # Delete the object instance. + instance.delete() + +#### Removal of view attributes. + +The `.object` and `.object_list` attributes are no longer set on the view instance. Treating views as mutable object instances that store state during the processing of the view tends to be poor design, and can lead to obscure flow logic. + +I would personally recommend that developers treat view instances as immutable objects in their application code. + +#### PUT as create. + +Allowing `PUT` as create operations is problematic, as it necessarily exposes information about the existence or non-existence of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning `404` responses. + +Both styles "`PUT` as 404" and "`PUT` as create" can be valid in different circumstances, but we've now opted for the 404 behavior as the default, due to it being simpler and more obvious. + +If you need to restore the previous behavior you may want to include [this `AllowPUTAsCreateMixin` class](https://gist.github.com/tomchristie/a2ace4577eff2c603b1b) as a mixin to your views. + +#### Customizing error responses. + +The generic views now raise `ValidationFailed` exception for invalid data. This exception is then dealt with by the exception handler, rather than the view returning a `400 Bad Request` response directly. + +This change means that you can now easily customize the style of error responses across your entire API, without having to modify any of the generic views. + +## The metadata API + +Behavior for dealing with `OPTIONS` requests was previously built directly into the class based views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework. + +This makes it far easier to use a different style for `OPTIONS` responses throughout your API, and makes it possible to create third-party metadata policies. + +## Serializers as HTML forms + +REST framework 3.0 includes templated HTML form rendering for serializers. + +This API should not yet be considered finalized, and will only be promoted to public API for the 3.1 release. + +Significant changes that you do need to be aware of include: + +* Nested HTML forms are now supported, for example, a `UserSerializer` with a nested `ProfileSerializer` will now render a nested `fieldset` when used in the browsable API. +* Nested lists of HTML forms are not yet supported, but are planned for 3.1. +* Because we now use templated HTML form generation, **the `widget` option is no longer available for serializer fields**. You can instead control the template that is used for a given field, by using the `style` dictionary. + +#### The `style` keyword argument for serializer fields. + +The `style` keyword argument can be used to pass through additional information from a serializer field, to the renderer class. In particular, the `HTMLFormRenderer` uses the `base_template` key to determine which template to render the field with. + +For example, to use a `textarea` control instead of the default `input` control, you would use the following… + + additional_notes = serializers.CharField( + style={'base_template': 'text_area.html'} + ) + +Similarly, to use a radio button control instead of the default `select` control, you would use the following… + + color_channel = serializers.ChoiceField( + choices=['red', 'blue', 'green'], + style={'base_template': 'radio.html'} + ) + +This API should be considered provisional, and there may be minor alterations with the incoming 3.1 release. + +## API style + +There are some improvements in the default style we use in our API responses. + +#### Unicode JSON by default. + +Unicode JSON is now the default. The `UnicodeJSONRenderer` class no longer exists, and the `UNICODE_JSON` setting has been added. To revert this behavior use the new setting: + + REST_FRAMEWORK = { + 'UNICODE_JSON': False + } + +#### Compact JSON by default. + +We now output compact JSON in responses by default. For example, we return: + + {"email":"amy@example.com","is_admin":true} + +Instead of the following: + + {"email": "amy@example.com", "is_admin": true} + +The `COMPACT_JSON` setting has been added, and can be used to revert this behavior if needed: + + REST_FRAMEWORK = { + 'COMPACT_JSON': False + } + +#### File fields as URLs + +The `FileField` and `ImageField` classes are now represented as URLs by default. You should ensure you set Django's [standard `MEDIA_URL` setting](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-MEDIA_URL) appropriately, and ensure your application [serves the uploaded files](https://docs.djangoproject.com/en/dev/howto/static-files/#serving-uploaded-files-in-development). + +You can revert this behavior, and display filenames in the representation by using the `UPLOADED_FILES_USE_URL` settings key: + + REST_FRAMEWORK = { + 'UPLOADED_FILES_USE_URL': False + } + +You can also modify serializer fields individually, using the `use_url` argument: + + uploaded_file = serializers.FileField(use_url=False) + +Also note that you should pass the `request` object to the serializer as context when instantiating it, so that a fully qualified URL can be returned. Returned URLs will then be of the form `https://example.com/url_path/filename.txt`. For example: + + context = {'request': request} + serializer = ExampleSerializer(instance, context=context) + return Response(serializer.data) + +If the request is omitted from the context, the returned URLs will be of the form `/url_path/filename.txt`. + +#### Throttle headers using `Retry-After`. + +The custom `X-Throttle-Wait-Second` header has now been dropped in favor of the standard `Retry-After` header. You can revert this behavior if needed by writing a custom exception handler for your application. + +#### Date and time objects as ISO-8859-1 strings in serializer data. + +Date and Time objects are now coerced to strings by default in the serializer output. Previously they were returned as `Date`, `Time` and `DateTime` objects, and later coerced to strings by the renderer. + +You can modify this behavior globally by settings the existing `DATE_FORMAT`, `DATETIME_FORMAT` and `TIME_FORMAT` settings keys. Setting these values to `None` instead of their default value of `'iso-8859-1'` will result in native objects being returned in serializer data. + + REST_FRAMEWORK = { + # Return native `Date` and `Time` objects in `serializer.data` + 'DATETIME_FORMAT': None + 'DATE_FORMAT': None + 'TIME_FORMAT': None + } + +You can also modify serializer fields individually, using the `date_format`, `time_format` and `datetime_format` arguments: + + # Return `DateTime` instances in `serializer.data`, not strings. + created = serializers.DateTimeField(format=None) + +#### Decimals as strings in serializer data. + +Decimals are now coerced to strings by default in the serializer output. Previously they were returned as `Decimal` objects, and later coerced to strings by the renderer. + +You can modify this behavior globally by using the `COERCE_DECIMAL_TO_STRING` settings key. + + REST_FRAMEWORK = { + 'COERCE_DECIMAL_TO_STRING': False + } + +Or modify it on an individual serializer field, using the `coerce_to_string` keyword argument. + + # Return `Decimal` instances in `serializer.data`, not strings. + amount = serializers.DecimalField( + max_digits=10, + decimal_places=2, + coerce_to_string=False + ) + +The default JSON renderer will return float objects for uncoerced `Decimal` instances. This allows you to easily switch between string or float representations for decimals depending on your API design needs. + +## Miscellaneous notes. + +* The serializer `ChoiceField` does not currently display nested choices, as was the case in 2.4. This will be address as part of 3.1. +* Due to the new templated form rendering, the 'widget' option is no longer valid. This means there's no easy way of using third party "autocomplete" widgets for rendering select inputs that contain a large number of choices. You'll either need to use a regular select or a plain text input. We may consider addressing this in 3.1 or 3.2 if there's sufficient demand. + +## What's coming next. + +3.0 is an incremental release, and there are several upcoming features that will build on the baseline improvements that it makes. + +The 3.1 release is planned to address improvements in the following components: + +* Public API for using serializers as HTML forms. +* Request parsing, mediatypes & the implementation of the browsable API. +* Introduction of a new pagination API. +* Better support for API versioning. + +The 3.2 release is planned to introduce an alternative admin-style interface to the browsable API. + +You can follow development on the GitHub site, where we use [milestones to indicate planning timescales](https://github.com/tomchristie/django-rest-framework/milestones). + +[mixins.py]: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py diff --git a/docs/topics/ajax-csrf-cors.md b/docs/topics/ajax-csrf-cors.md index 97dd4710b..ad88810da 100644 --- a/docs/topics/ajax-csrf-cors.md +++ b/docs/topics/ajax-csrf-cors.md @@ -10,7 +10,7 @@ If you’re building a JavaScript client to interface with your Web API, you'll AJAX requests that are made within the same context as the API they are interacting with will typically use `SessionAuthentication`. This ensures that once a user has logged in, any AJAX requests made can be authenticated using the same session-based authentication that is used for the rest of the website. -AJAX requests that are made on a different site from the API they are communicating with will typically need to use a non-session-based authentication scheme, such as `TokenAuthentication`. +AJAX requests that are made on a different site from the API they are communicating with will typically need to use a non-session-based authentication scheme, such as `TokenAuthentication`. ## CSRF protection @@ -19,7 +19,7 @@ AJAX requests that are made on a different site from the API they are communicat To guard against these type of attacks, you need to do two things: 1. Ensure that the 'safe' HTTP operations, such as `GET`, `HEAD` and `OPTIONS` cannot be used to alter any server-side state. -2. Ensure that any 'unsafe' HTTP operations, such as `POST`, `PUT`, `PATCH` and `DELETE`, always require a valid CSRF token. +2. Ensure that any 'unsafe' HTTP operations, such as `POST`, `PUT`, `PATCH` and `DELETE`, always require a valid CSRF token. If you're using `SessionAuthentication` you'll need to include valid CSRF tokens for any `POST`, `PUT`, `PATCH` or `DELETE` operations. @@ -35,7 +35,7 @@ The best way to deal with CORS in REST framework is to add the required response [cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html [csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) -[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax +[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax [cors]: http://www.w3.org/TR/cors/ [ottoyiu]: https://github.com/ottoyiu/ [django-cors-headers]: https://github.com/ottoyiu/django-cors-headers/ diff --git a/docs/topics/contributing.md b/docs/topics/contributing.md index 3400bc8f9..7654136cf 100644 --- a/docs/topics/contributing.md +++ b/docs/topics/contributing.md @@ -10,9 +10,9 @@ There are many ways you can contribute to Django REST framework. We'd like it t The most important thing you can do to help push the REST framework project forward is to be actively involved wherever possible. Code contributions are often overvalued as being the primary way to get involved in a project, we don't believe that needs to be the case. -If you use REST framework, we'd love you to be vocal about your experiences with it - you might consider writing a blog post about using REST framework, or publishing a tutorial about building a project with a particular Javascript framework. Experiences from beginners can be particularly helpful because you'll be in the best position to assess which bits of REST framework are more difficult to understand and work with. +If you use REST framework, we'd love you to be vocal about your experiences with it - you might consider writing a blog post about using REST framework, or publishing a tutorial about building a project with a particular JavaScript framework. Experiences from beginners can be particularly helpful because you'll be in the best position to assess which bits of REST framework are more difficult to understand and work with. -Other really great ways you can help move the community forward include helping answer questions on the [discussion group][google-group], or setting up an [email alert on StackOverflow][so-filter] so that you get notified of any new questions with the `django-rest-framework` tag. +Other really great ways you can help move the community forward include helping to answer questions on the [discussion group][google-group], or setting up an [email alert on StackOverflow][so-filter] so that you get notified of any new questions with the `django-rest-framework` tag. When answering questions make sure to help future contributors find their way around by hyperlinking wherever possible to related threads and tickets, and include backlinks from those items if relevant. @@ -33,7 +33,7 @@ Some tips on good issue reporting: * When describing issues try to phrase your ticket in terms of the *behavior* you think needs changing rather than the *code* you think need changing. * Search the issue list first for related items, and make sure you're running the latest version of REST framework before reporting an issue. * If reporting a bug, then try to include a pull request with a failing test case. This will help us quickly identify if there is a valid issue, and make sure that it gets fixed more quickly if there is one. -* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintainence overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation. +* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation. * Closing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened. ## Triaging issues @@ -52,7 +52,7 @@ To start developing on Django REST framework, clone the repo: git clone git@github.com:tomchristie/django-rest-framework.git -Changes should broadly follow the [PEP 8][pep-8] style conventions, and we recommend you setup your editor to automatically indicated non-conforming styles. +Changes should broadly follow the [PEP 8][pep-8] style conventions, and we recommend you set up your editor to automatically indicate non-conforming styles. ## Testing @@ -71,31 +71,31 @@ To run the tests, clone the repository, and then: Run using a more concise output style. - ./runtests -q + ./runtests.py -q Run the tests using a more concise output style, no coverage, no flake8. - ./runtests --fast + ./runtests.py --fast Don't run the flake8 code linting. - ./runtests --nolint + ./runtests.py --nolint Only run the flake8 code linting, don't run the tests. - ./runtests --lintonly + ./runtests.py --lintonly Run the tests for a given test case. - ./runtests MyTestCase + ./runtests.py MyTestCase Run the tests for a given test method. - ./runtests MyTestCase.test_this_method + ./runtests.py MyTestCase.test_this_method Shorter form to run the tests for a given test method. - ./runtests test_this_method + ./runtests.py test_this_method Note: The test case and test method matching is fuzzy and will sometimes run other tests that contain a partial string match to the given command line input. @@ -109,7 +109,7 @@ You can also use the excellent [tox][tox] testing tool to run the tests against It's a good idea to make pull requests early on. A pull request represents the start of a discussion, and doesn't necessarily need to be the final, finished submission. -It's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another seperate issue without interfering with an ongoing pull requests. +It's also always best to make a new branch before starting work on a pull request. This means that you'll be able to later switch back to working on another separate issue without interfering with an ongoing pull requests. It's also useful to remember that if you have an outstanding pull request then pushing new commits to your GitHub repo will also automatically update the pull requests. @@ -117,7 +117,7 @@ GitHub's documentation for working on pull requests is [available here][pull-req Always run the tests before submitting pull requests, and ideally run `tox` in order to check that your modifications are compatible with both Python 2 and Python 3, and that they run properly on all supported versions of Django. -Once you've made a pull request take a look at the travis build status in the GitHub interface and make sure the tests are runnning as you'd expect. +Once you've made a pull request take a look at the Travis build status in the GitHub interface and make sure the tests are running as you'd expect. ![Travis status][travis-status] @@ -131,19 +131,19 @@ Sometimes, in order to ensure your code works on various different versions of D The documentation for REST framework is built from the [Markdown][markdown] source files in [the docs directory][docs]. -There are many great markdown editors that make working with the documentation really easy. The [Mou editor for Mac][mou] is one such editor that comes highly recommended. +There are many great Markdown editors that make working with the documentation really easy. The [Mou editor for Mac][mou] is one such editor that comes highly recommended. ## Building the documentation -To build the documentation, simply run the `mkdocs.py` script. +To build the documentation, install MkDocs with `pip install mkdocs` and then run the following command. - ./mkdocs.py + mkdocs build -This will build the html output into the `html` directory. +This will build the documentation into the `site` directory. -You can build the documentation and open a preview in a browser window by using the `-p` flag. +You can build the documentation and open a preview in a browser window by using the `serve` command. - ./mkdocs.py -p + mkdocs serve ## Language style @@ -153,7 +153,7 @@ Some other tips: * Keep paragraphs reasonably short. * Use double spacing after the end of sentences. -* Don't use the abbreviations such as 'e.g.' but instead use long form, such as 'For example'. +* Don't use abbreviations such as 'e.g.' but instead use the long form, such as 'For example'. ## Markdown style @@ -186,7 +186,7 @@ If you are hyperlinking to another REST framework document, you should use a rel [authentication]: ../api-guide/authentication.md -Linking in this style means you'll be able to click the hyperlink in your markdown editor to open the referenced document. When the documentation is built, these links will be converted into regular links to HTML pages. +Linking in this style means you'll be able to click the hyperlink in your Markdown editor to open the referenced document. When the documentation is built, these links will be converted into regular links to HTML pages. ##### 3. Notes @@ -210,7 +210,9 @@ We recommend the [`django-reusable-app`][django-reusable-app] template as a good ## Linking to your package -Once your package is decently documented and available on PyPI open a pull request or issue, and we'll add a link to it from the main REST framework documentation. +Once your package is decently documented and available on PyPI open a pull request or issue, and we'll add a link to it from the main REST framework documentation. You can add your package under **Third party packages** of the API Guide section that best applies, like [Authentication][authentication] or [Permissions][permissions]. You can also link your package under the [Third Party Resources][third-party-resources] section. + +We also suggest adding it to the [REST Framework][rest-framework-grid] grid on Django Packages. [cite]: http://www.w3.org/People/Berners-Lee/FAQ.html [code-of-conduct]: https://www.djangoproject.com/conduct/ @@ -225,3 +227,7 @@ Once your package is decently documented and available on PyPI open a pull reque [docs]: https://github.com/tomchristie/django-rest-framework/tree/master/docs [mou]: http://mouapp.com/ [django-reusable-app]: https://github.com/dabapps/django-reusable-app +[authentication]: ../api-guide/authentication.md +[permissions]: ../api-guide/permissions.md +[third-party-resources]: third-party-resources.md +[rest-framework-grid]: https://www.djangopackages.com/grids/g/django-rest-framework/ diff --git a/docs/topics/documenting-your-api.md b/docs/topics/documenting-your-api.md index e20f97122..d65e251f1 100644 --- a/docs/topics/documenting-your-api.md +++ b/docs/topics/documenting-your-api.md @@ -54,7 +54,7 @@ The title that is used in the browsable API is generated from the view class nam For example, the view `UserListView`, will be named `User List` when presented in the browsable API. -When working with viewsets, an appropriate suffix is appended to each generated view. For example, the view set `UserViewSet` will generate views named `User List` and `User Instance`. +When working with viewsets, an appropriate suffix is appended to each generated view. For example, the view set `UserViewSet` will generate views named `User List` and `User Instance`. #### Setting the description @@ -65,9 +65,9 @@ If the python `markdown` library is installed, then [markdown syntax][markdown] class AccountListView(views.APIView): """ Returns a list of all **active** accounts in the system. - + For more details on how accounts are activated please [see here][ref]. - + [ref]: http://example.com/activating-accounts """ @@ -84,7 +84,7 @@ You can modify the response behavior to `OPTIONS` requests by overriding the `me def metadata(self, request): """ Don't include the view description in OPTIONS responses. - """ + """ data = super(ExampleView, self).metadata(request) data.pop('description') return data diff --git a/docs/topics/kickstarter-announcement.md b/docs/topics/kickstarter-announcement.md index 7d1f6d0eb..e8bad95be 100644 --- a/docs/topics/kickstarter-announcement.md +++ b/docs/topics/kickstarter-announcement.md @@ -160,4 +160,4 @@ The following individuals made a significant financial contribution to the devel ### Supporters -There were also almost 300 further individuals choosing to help fund the project at other levels or choosing to give anonymously. Again, thank you, thank you, thank you! \ No newline at end of file +There were also almost 300 further individuals choosing to help fund the project at other levels or choosing to give anonymously. Again, thank you, thank you, thank you! diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 16589f3b9..9fca949ab 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -40,6 +40,16 @@ You can determine your currently installed version using `pip freeze`: ## 2.4.x series +### 2.4.4 + +**Date**: [3rd November 2014](https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%222.4.4+Release%22+). + +* **Security fix**: Escape URLs when replacing `format=` query parameter, as used in dropdown on `GET` button in browsable API to allow explicit selection of JSON vs HTML output. +* Maintain ordering of URLs in API root view for `DefaultRouter`. +* Fix `follow=True` in `APIRequestFactory` +* Resolve issue with invalid `read_only=True`, `required=True` fields being automatically generated by `ModelSerializer` in some cases. +* Resolve issue with `OPTIONS` requests returning incorrect information for views using `get_serializer_class` to dynamically determine serializer based on request method. + ### 2.4.3 **Date**: [19th September 2014](https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%222.4.3+Release%22+). @@ -53,7 +63,7 @@ You can determine your currently installed version using `pip freeze`: * Bugfix: Fix migration in `authtoken` application. * Bugfix: Allow selection of integer keys in nested choices. * Bugfix: Return `None` instead of `'None'` in `CharField` with `allow_none=True`. -* Bugfix: Ensure custom model fields map to equivelent serializer fields more reliably. +* Bugfix: Ensure custom model fields map to equivelent serializer fields more reliably. * Bugfix: `DjangoFilterBackend` no longer quietly changes queryset ordering. ### 2.4.2 @@ -149,7 +159,7 @@ You can determine your currently installed version using `pip freeze`: * Added `write_only_fields` option to `ModelSerializer` classes. * JSON renderer now deals with objects that implement a dict-like interface. * Fix compatiblity with newer versions of `django-oauth-plus`. -* Bugfix: Refine behavior that calls model manager `all()` across nested serializer relationships, preventing erronous behavior with some non-ORM objects, and preventing unneccessary queryset re-evaluations. +* Bugfix: Refine behavior that calls model manager `all()` across nested serializer relationships, preventing erronous behavior with some non-ORM objects, and preventing unnecessary queryset re-evaluations. * Bugfix: Allow defaults on BooleanFields to be properly honored when values are not supplied. * Bugfix: Prevent double-escaping of non-latin1 URL query params when appending `format=json` params. diff --git a/docs/topics/rest-framework-2-announcement.md b/docs/topics/rest-framework-2-announcement.md index f1060d90b..a7746932e 100644 --- a/docs/topics/rest-framework-2-announcement.md +++ b/docs/topics/rest-framework-2-announcement.md @@ -8,7 +8,7 @@ What it is, and why you should care. --- -**Announcement:** REST framework 2 released - Tue 30th Oct 2012 +**Announcement:** REST framework 2 released - Tue 30th Oct 2012 --- @@ -37,7 +37,7 @@ REST framework 2 includes a totally re-worked serialization engine, that was ini * A declarative serialization API, that mirrors Django's `Forms`/`ModelForms` API. * Structural concerns are decoupled from encoding concerns. * Able to support rendering and parsing to many formats, including both machine-readable representations and HTML forms. -* Validation that can be mapped to obvious and comprehensive error responses. +* Validation that can be mapped to obvious and comprehensive error responses. * Serializers that support both nested, flat, and partially-nested representations. * Relationships that can be expressed as primary keys, hyperlinks, slug fields, and other custom representations. diff --git a/docs/topics/rest-hypermedia-hateoas.md b/docs/topics/rest-hypermedia-hateoas.md index 3d7004880..4e3ccf924 100644 --- a/docs/topics/rest-hypermedia-hateoas.md +++ b/docs/topics/rest-hypermedia-hateoas.md @@ -13,7 +13,7 @@ The following fall into the "required reading" category. * Roy Fielding's dissertation - [Architectural Styles and the Design of Network-based Software Architectures][dissertation]. * Roy Fielding's "[REST APIs must be hypertext-driven][hypertext-driven]" blog post. -* Leonard Richardson & Sam Ruby's [RESTful Web Services][restful-web-services]. +* Leonard Richardson & Mike Amundsen's [RESTful Web APIs][restful-web-apis]. * Mike Amundsen's [Building Hypermedia APIs with HTML5 and Node][building-hypermedia-apis]. * Steve Klabnik's [Designing Hypermedia APIs][designing-hypermedia-apis]. * The [Richardson Maturity Model][maturitymodel]. @@ -37,7 +37,7 @@ What REST framework doesn't do is give you is machine readable hypermedia format [cite]: http://vimeo.com/channels/restfest/page:2 [dissertation]: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm [hypertext-driven]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven -[restful-web-services]: http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260 +[restful-web-apis]: http://restfulwebapis.org/ [building-hypermedia-apis]: http://www.amazon.com/Building-Hypermedia-APIs-HTML5-Node/dp/1449306578 [designing-hypermedia-apis]: http://designinghypermediaapis.com/ [restisover]: http://blog.steveklabnik.com/posts/2012-02-23-rest-is-over diff --git a/docs/topics/third-party-resources.md b/docs/topics/third-party-resources.md index 1ca917427..ffb490af3 100644 --- a/docs/topics/third-party-resources.md +++ b/docs/topics/third-party-resources.md @@ -1,91 +1,322 @@ # Third Party Resources +## About Third Party Packages + +Third Party Packages allow developers to share code that extends the functionality of Django REST framework, in order to support additional use-cases. + +We **support**, **encourage** and **strongly favour** the creation of Third Party Packages to encapsulate new behaviour rather than adding additional functionality directly to Django REST Framework. + +We aim to make creating Third Party Packages as easy as possible, whilst keeping the **simplicity** of the core API and ensuring that **maintenance** of the main project remains under control. If a Third Party Package proves popular it is relatively easy to move it into the main project; removing features is much more problematic. + +If you have an idea for a new feature please consider how it may be packaged as a Third Party Package. We're always happy to dicuss ideas on the [Mailing List][discussion-group]. + +## How to create a Third Party Package + +### Creating your package + +You can use [this cookiecutter template][cookiecutter] for creating reusable Django REST Framework packages quickly. Cookiecutter creates projects from project templates. While optional, this cookiecutter template includes best practices from Django REST framework and other packages, as well as a Travis CI configuration, Tox configuration, and a sane setup.py for easy PyPI registration/distribution. + +Note: Let us know if you have an alternate cookiecuter package so we can also link to it. + +#### Running the initial cookiecutter command + +To run the initial cookiecutter command, you'll first need to install the Python `cookiecutter` package. + + $ pip install cookiecutter + +Once `cookiecutter` is installed just run the following to create a new project. + + $ cookiecutter gh:jpadilla/cookiecutter-django-rest-framework + +You'll be prompted for some questions, answer them, then it'll create your Python package in the current working directory based on those values. + + full_name (default is "Your full name here")? Johnny Appleseed + email (default is "you@example.com")? jappleseed@example.com + github_username (default is "yourname")? jappleseed + pypi_project_name (default is "dj-package")? djangorestframework-custom-auth + repo_name (default is "dj-package")? django-rest-framework-custom-auth + app_name (default is "djpackage")? custom_auth + project_short_description (default is "Your project description goes here")? + year (default is "2014")? + version (default is "0.1.0")? + +#### Getting it onto GitHub + +To put your project up on GitHub, you'll need a repository for it to live in. You can create a new repository [here][new-repo]. If you need help, check out the [Create A Repo][create-a-repo] article on GitHub. + + +#### Adding to Travis CI + +We recommend using [Travis CI][travis-ci], a hosted continuous integration service which integrates well with GitHub and is free for public repositories. + +To get started with Travis CI, [sign in][travis-ci] with your GitHub account. Once you're signed in, go to your [profile page][travis-profile] and enable the service hook for the repository you want. + +If you use the cookiecutter template, your project will already contain a `.travis.yml` file which Travis CI will use to build your project and run tests. By default, builds are triggered everytime you push to your repository or create Pull Request. + +#### Uploading to PyPI + +Once you've got at least a prototype working and tests running, you should publish it on PyPI to allow others to install it via `pip`. + +You must [register][pypi-register] an account before publishing to PyPI. + +To register your package on PyPI run the following command. + + $ python setup.py register + +If this is the first time publishing to PyPI, you'll be prompted to login. + +Note: Before publishing you'll need to make sure you have the latest pip that supports `wheel` as well as install the `wheel` package. + + $ pip install --upgrade pip + $ pip install wheel + +After this, every time you want to release a new version on PyPI just run the following command. + + $ python setup.py publish + You probably want to also tag the version now: + git tag -a {0} -m 'version 0.1.0' + git push --tags + +After releasing a new version to PyPI, it's always a good idea to tag the version and make available as a GitHub Release. + +We recommend to follow [Semantic Versioning][semver] for your package's versions. + +### Development + +#### Version requirements + +The cookiecutter template assumes a set of supported versions will be provided for Python and Django. Make sure you correctly update your requirements, docs, `tox.ini`, `.travis.yml`, and `setup.py` to match the set of versions you wish to support. + +#### Tests + +The cookiecutter template includes a `runtests.py` which uses the `pytest` package as a test runner. + +Before running, you'll need to install a couple test requirements. + + $ pip install -r requirements-test.txt + +Once requirements installed, you can run `runtests.py`. + + $ ./runtests.py + +Run using a more concise output style. + + $ ./runtests.py -q + +Run the tests using a more concise output style, no coverage, no flake8. + + $ ./runtests.py --fast + +Don't run the flake8 code linting. + + $ ./runtests.py --nolint + +Only run the flake8 code linting, don't run the tests. + + $ ./runtests.py --lintonly + +Run the tests for a given test case. + + $ ./runtests.py MyTestCase + +Run the tests for a given test method. + + $ ./runtests.py MyTestCase.test_this_method + +Shorter form to run the tests for a given test method. + + $ ./runtests.py test_this_method + +To run your tests against multiple versions of Python as different versions of requirements such as Django we recommend using `tox`. [Tox][tox-docs] is a generic virtualenv management and test command line tool. + +First, install `tox` globally. + + $ pip install tox + +To run `tox`, just simply run: + + $ tox + +To run a particular `tox` environment: + + $ tox -e envlist + +`envlist` is a comma-separated value to that specifies the environments to run tests against. To view a list of all possible test environments, run: + + $ tox -l + +#### Version compatibility + +Sometimes, in order to ensure your code works on various different versions of Django, Python or third party libraries, you'll need to run slightly different code depending on the environment. Any code that branches in this way should be isolated into a `compat.py` module, and should provide a single common interface that the rest of the codebase can use. + +Check out Django REST framework's [compat.py][drf-compat] for an example. + +### Once your package is available + +Once your package is decently documented and available on PyPI, you might want share it with others that might find it useful. + +#### Adding to the Django REST framework grid + +We suggest adding your package to the [REST Framework][rest-framework-grid] grid on Django Packages. + +#### Adding to the Django REST framework docs + +Create a [Pull Request][drf-create-pr] or [Issue][drf-create-issue] on GitHub, and we'll add a link to it from the main REST framework documentation. You can add your package under **Third party packages** of the API Guide section that best applies, like [Authentication][authentication] or [Permissions][permissions]. You can also link your package under the [Third Party Resources][third-party-resources] section. + +#### Announce on the discussion group. + +You can also let others know about your package through the [discussion group][discussion-group]. + +## Existing Third Party Packages + Django REST Framework has a growing community of developers, packages, and resources. -Check out a grid detailing all the packages and ecosystem around Django REST Framework at [Django Packages](https://www.djangopackages.com/grids/g/django-rest-framework/). +Check out a grid detailing all the packages and ecosystem around Django REST Framework at [Django Packages][rest-framework-grid]. -To submit new content, [open an issue](https://github.com/tomchristie/django-rest-framework/issues/new) or [create a pull request](https://github.com/tomchristie/django-rest-framework/). - -## Libraries and Extensions +To submit new content, [open an issue][drf-create-issue] or [create a pull request][drf-create-pr]. ### Authentication -* [djangorestframework-digestauth](https://github.com/juanriaza/django-rest-framework-digestauth) - Provides Digest Access Authentication support. -* [django-oauth-toolkit](https://github.com/evonove/django-oauth-toolkit) - Provides OAuth 2.0 support. -* [doac](https://github.com/Rediker-Software/doac) - Provides OAuth 2.0 support. -* [djangorestframework-jwt](https://github.com/GetBlimp/django-rest-framework-jwt) - Provides JSON Web Token Authentication support. -* [hawkrest](https://github.com/kumar303/hawkrest) - Provides Hawk HTTP Authorization. -* [djangorestframework-httpsignature](https://github.com/etoccalino/django-rest-framework-httpsignature) - Provides an easy to use HTTP Signature Authentication mechanism. +* [djangorestframework-digestauth][djangorestframework-digestauth] - Provides Digest Access Authentication support. +* [django-oauth-toolkit][django-oauth-toolkit] - Provides OAuth 2.0 support. +* [doac][doac] - Provides OAuth 2.0 support. +* [djangorestframework-jwt][djangorestframework-jwt] - Provides JSON Web Token Authentication support. +* [hawkrest][hawkrest] - Provides Hawk HTTP Authorization. +* [djangorestframework-httpsignature][djangorestframework-httpsignature] - Provides an easy to use HTTP Signature Authentication mechanism. +* [djoser][djoser] - Provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. ### Permissions -* [drf-any-permissions](https://github.com/kevin-brown/drf-any-permissions) - Provides alternative permission handling. -* [djangorestframework-composed-permissions](https://github.com/niwibe/djangorestframework-composed-permissions) - Provides a simple way to define complex permissions. -* [rest_condition](https://github.com/caxap/rest_condition) - Another extension for building complex permissions in a simple and convenient way. +* [drf-any-permissions][drf-any-permissions] - Provides alternative permission handling. +* [djangorestframework-composed-permissions][djangorestframework-composed-permissions] - Provides a simple way to define complex permissions. +* [rest_condition][rest-condition] - Another extension for building complex permissions in a simple and convenient way. ### Serializers -* [django-rest-framework-mongoengine](https://github.com/umutbozkurt/django-rest-framework-mongoengine) - Serializer class that supports using MongoDB as the storage layer for Django REST framework. -* [djangorestframework-gis](https://github.com/djangonauts/django-rest-framework-gis) - Geographic add-ons -* [djangorestframework-hstore](https://github.com/djangonauts/django-rest-framework-hstore) - Serializer class to support django-hstore DictionaryField model field and its schema-mode feature. +* [django-rest-framework-mongoengine][django-rest-framework-mongoengine] - Serializer class that supports using MongoDB as the storage layer for Django REST framework. +* [djangorestframework-gis][djangorestframework-gis] - Geographic add-ons +* [djangorestframework-hstore][djangorestframework-hstore] - Serializer class to support django-hstore DictionaryField model field and its schema-mode feature. ### Serializer fields -* [drf-compound-fields](https://github.com/estebistec/drf-compound-fields) - Provides "compound" serializer fields, such as lists of simple values. -* [django-extra-fields](https://github.com/Hipo/drf-extra-fields) - Provides extra serializer fields. +* [drf-compound-fields][drf-compound-fields] - Provides "compound" serializer fields, such as lists of simple values. +* [django-extra-fields][django-extra-fields] - Provides extra serializer fields. ### Views -* [djangorestframework-bulk](https://github.com/miki725/django-rest-framework-bulk) - Implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests. +* [djangorestframework-bulk][djangorestframework-bulk] - Implements generic view mixins as well as some common concrete generic views to allow to apply bulk operations via API requests. ### Routers -* [drf-nested-routers](https://github.com/alanjds/drf-nested-routers) - Provides routers and relationship fields for working with nested resources. -* [wq.db.rest](http://wq.io/docs/about-rest) - Provides an admin-style model registration API with reasonable default URLs and viewsets. +* [drf-nested-routers][drf-nested-routers] - Provides routers and relationship fields for working with nested resources. +* [wq.db.rest][wq.db.rest] - Provides an admin-style model registration API with reasonable default URLs and viewsets. ### Parsers -* [djangorestframework-msgpack](https://github.com/juanriaza/django-rest-framework-msgpack) - Provides MessagePack renderer and parser support. -* [djangorestframework-camel-case](https://github.com/vbabiy/djangorestframework-camel-case) - Provides camel case JSON renderers and parsers. +* [djangorestframework-msgpack][djangorestframework-msgpack] - Provides MessagePack renderer and parser support. +* [djangorestframework-camel-case][djangorestframework-camel-case] - Provides camel case JSON renderers and parsers. ### Renderers -* [djangorestframework-csv](https://github.com/mjumbewu/django-rest-framework-csv) - Provides CSV renderer support. -* [drf_ujson](https://github.com/gizmag/drf-ujson-renderer) - Implements JSON rendering using the UJSON package. -* [Django REST Pandas](https://github.com/wq/django-rest-pandas) - Pandas DataFrame-powered renderers including Excel, CSV, and SVG formats. +* [djangorestframework-csv][djangorestframework-csv] - Provides CSV renderer support. +* [drf_ujson][drf_ujson] - Implements JSON rendering using the UJSON package. +* [rest-pandas][rest-pandas] - Pandas DataFrame-powered renderers including Excel, CSV, and SVG formats. ### Filtering -* [djangorestframework-chain](https://github.com/philipn/django-rest-framework-chain) - Allows arbitrary chaining of both relations and lookup filters. +* [djangorestframework-chain][djangorestframework-chain] - Allows arbitrary chaining of both relations and lookup filters. ### Misc -* [djangorestrelationalhyperlink](https://github.com/fredkingham/django_rest_model_hyperlink_serializers_project) - A hyperlinked serialiser that can can be used to alter relationships via hyperlinks, but otherwise like a hyperlink model serializer. -* [django-rest-swagger](https://github.com/marcgibbons/django-rest-swagger) - An API documentation generator for Swagger UI. -* [django-rest-framework-proxy ](https://github.com/eofs/django-rest-framework-proxy) - Proxy to redirect incoming request to another API server. -* [gaiarestframework](https://github.com/AppsFuel/gaiarestframework) - Utils for django-rest-framewok -* [drf-extensions](https://github.com/chibisov/drf-extensions) - A collection of custom extensions -* [ember-data-django-rest-adapter](https://github.com/toranb/ember-data-django-rest-adapter) - An ember-data adapter +* [djangorestrelationalhyperlink][djangorestrelationalhyperlink] - A hyperlinked serialiser that can can be used to alter relationships via hyperlinks, but otherwise like a hyperlink model serializer. +* [django-rest-swagger][django-rest-swagger] - An API documentation generator for Swagger UI. +* [django-rest-framework-proxy][django-rest-framework-proxy] - Proxy to redirect incoming request to another API server. +* [gaiarestframework][gaiarestframework] - Utils for django-rest-framewok +* [drf-extensions][drf-extensions] - A collection of custom extensions +* [ember-data-django-rest-adapter][ember-data-django-rest-adapter] - An ember-data adapter -## Tutorials +## Other Resources -* [Beginner's Guide to the Django Rest Framework](http://code.tutsplus.com/tutorials/beginners-guide-to-the-django-rest-framework--cms-19786) -* [Getting Started with Django Rest Framework and AngularJS](http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html) -* [End to end web app with Django-Rest-Framework & AngularJS](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework) -* [Start Your API - django-rest-framework part 1](https://godjango.com/41-start-your-api-django-rest-framework-part-1/) -* [Permissions & Authentication - django-rest-framework part 2](https://godjango.com/43-permissions-authentication-django-rest-framework-part-2/) -* [ViewSets and Routers - django-rest-framework part 3](https://godjango.com/45-viewsets-and-routers-django-rest-framework-part-3/) -* [Django Rest Framework User Endpoint](http://richardtier.com/2014/02/25/django-rest-framework-user-endpoint/) -* [Check credentials using Django Rest Framework](http://richardtier.com/2014/03/06/110/) +### Tutorials -## Videos +* [Beginner's Guide to the Django Rest Framework][beginners-guide-to-the-django-rest-framework] +* [Getting Started with Django Rest Framework and AngularJS][getting-started-with-django-rest-framework-and-angularjs] +* [End to end web app with Django-Rest-Framework & AngularJS][end-to-end-web-app-with-django-rest-framework-angularjs] +* [Start Your API - django-rest-framework part 1][start-your-api-django-rest-framework-part-1] +* [Permissions & Authentication - django-rest-framework part 2][permissions-authentication-django-rest-framework-part-2] +* [ViewSets and Routers - django-rest-framework part 3][viewsets-and-routers-django-rest-framework-part-3] +* [Django Rest Framework User Endpoint][django-rest-framework-user-endpoint] +* [Check credentials using Django Rest Framework][check-credentials-using-django-rest-framework] -* [Ember and Django Part 1 (Video)](http://www.neckbeardrepublic.com/screencasts/ember-and-django-part-1) -* [Django Rest Framework Part 1 (Video)](http://www.neckbeardrepublic.com/screencasts/django-rest-framework-part-1) -* [Pyowa July 2013 - Django Rest Framework (Video)](http://www.youtube.com/watch?v=E1ZrehVxpBo) -* [django-rest-framework and angularjs (Video)](http://www.youtube.com/watch?v=Q8FRBGTJ020) +### Videos -## Articles +* [Ember and Django Part 1 (Video)][ember-and-django-part 1-video] +* [Django Rest Framework Part 1 (Video)][django-rest-framework-part-1-video] +* [Pyowa July 2013 - Django Rest Framework (Video)][pyowa-july-2013-django-rest-framework-video] +* [django-rest-framework and angularjs (Video)][django-rest-framework-and-angularjs-video] -* [Web API performance: profiling Django REST framework](http://dabapps.com/blog/api-performance-profiling-django-rest-framework/) -* [API Development with Django and Django REST Framework](https://bnotions.com/api-development-with-django-and-django-rest-framework/) +### Articles + +* [Web API performance: profiling Django REST framework][web-api-performance-profiling-django-rest-framework] +* [API Development with Django and Django REST Framework][api-development-with-django-and-django-rest-framework] + + +[cookiecutter]: https://github.com/jpadilla/cookiecutter-django-rest-framework +[new-repo]: https://github.com/new +[create-a-repo]: https://help.github.com/articles/create-a-repo/ +[travis-ci]: https://travis-ci.org +[travis-profile]: https://travis-ci.org/profile +[pypi-register]: https://pypi.python.org/pypi?%3Aaction=register_form +[semver]: http://semver.org/ +[tox-docs]: https://tox.readthedocs.org/en/latest/ +[drf-compat]: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/compat.py +[rest-framework-grid]: https://www.djangopackages.com/grids/g/django-rest-framework/ +[drf-create-pr]: https://github.com/tomchristie/django-rest-framework/compare +[drf-create-issue]: https://github.com/tomchristie/django-rest-framework/issues/new +[authentication]: ../api-guide/authentication.md +[permissions]: ../api-guide/permissions.md +[discussion-group]: https://groups.google.com/forum/#!forum/django-rest-framework +[djangorestframework-digestauth]: https://github.com/juanriaza/django-rest-framework-digestauth +[django-oauth-toolkit]: https://github.com/evonove/django-oauth-toolkit +[doac]: https://github.com/Rediker-Software/doac +[djangorestframework-jwt]: https://github.com/GetBlimp/django-rest-framework-jwt +[hawkrest]: https://github.com/kumar303/hawkrest +[djangorestframework-httpsignature]: https://github.com/etoccalino/django-rest-framework-httpsignature +[djoser]: https://github.com/sunscrapers/djoser +[drf-any-permissions]: https://github.com/kevin-brown/drf-any-permissions +[djangorestframework-composed-permissions]: https://github.com/niwibe/djangorestframework-composed-permissions +[rest-condition]: https://github.com/caxap/rest_condition +[django-rest-framework-mongoengine]: https://github.com/umutbozkurt/django-rest-framework-mongoengine +[djangorestframework-gis]: https://github.com/djangonauts/django-rest-framework-gis +[djangorestframework-hstore]: https://github.com/djangonauts/django-rest-framework-hstore +[drf-compound-fields]: https://github.com/estebistec/drf-compound-fields +[django-extra-fields]: https://github.com/Hipo/drf-extra-fields +[djangorestframework-bulk]: https://github.com/miki725/django-rest-framework-bulk +[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers +[wq.db.rest]: http://wq.io/docs/about-rest +[djangorestframework-msgpack]: https://github.com/juanriaza/django-rest-framework-msgpack +[djangorestframework-camel-case]: https://github.com/vbabiy/djangorestframework-camel-case +[djangorestframework-csv]: https://github.com/mjumbewu/django-rest-framework-csv +[drf_ujson]: https://github.com/gizmag/drf-ujson-renderer +[rest-pandas]: https://github.com/wq/django-rest-pandas +[djangorestframework-chain]: https://github.com/philipn/django-rest-framework-chain +[djangorestrelationalhyperlink]: https://github.com/fredkingham/django_rest_model_hyperlink_serializers_project +[django-rest-swagger]: https://github.com/marcgibbons/django-rest-swagger +[django-rest-framework-proxy]: https://github.com/eofs/django-rest-framework-proxy +[gaiarestframework]: https://github.com/AppsFuel/gaiarestframework +[drf-extensions]: https://github.com/chibisov/drf-extensions +[ember-data-django-rest-adapter]: https://github.com/toranb/ember-data-django-rest-adapter +[beginners-guide-to-the-django-rest-framework]: http://code.tutsplus.com/tutorials/beginners-guide-to-the-django-rest-framework--cms-19786 +[getting-started-with-django-rest-framework-and-angularjs]: http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html +[end-to-end-web-app-with-django-rest-framework-angularjs]: http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework +[start-your-api-django-rest-framework-part-1]: https://godjango.com/41-start-your-api-django-rest-framework-part-1/ +[permissions-authentication-django-rest-framework-part-2]: https://godjango.com/43-permissions-authentication-django-rest-framework-part-2/ +[viewsets-and-routers-django-rest-framework-part-3]: https://godjango.com/45-viewsets-and-routers-django-rest-framework-part-3/ +[django-rest-framework-user-endpoint]: http://richardtier.com/2014/02/25/django-rest-framework-user-endpoint/ +[check-credentials-using-django-rest-framework]: http://richardtier.com/2014/03/06/110/ +[ember-and-django-part 1-video]: http://www.neckbeardrepublic.com/screencasts/ember-and-django-part-1 +[django-rest-framework-part-1-video]: http://www.neckbeardrepublic.com/screencasts/django-rest-framework-part-1 +[pyowa-july-2013-django-rest-framework-video]: http://www.youtube.com/watch?v=e1zrehvxpbo +[django-rest-framework-and-angularjs-video]: http://www.youtube.com/watch?v=q8frbgtj020 +[web-api-performance-profiling-django-rest-framework]: http://dabapps.com/blog/api-performance-profiling-django-rest-framework/ +[api-development-with-django-and-django-rest-framework]: https://bnotions.com/api-development-with-django-and-django-rest-framework/ diff --git a/docs/topics/writable-nested-serializers.md b/docs/topics/writable-nested-serializers.md index 66ea78150..ed614bd24 100644 --- a/docs/topics/writable-nested-serializers.md +++ b/docs/topics/writable-nested-serializers.md @@ -6,9 +6,9 @@ Although flat data structures serve to properly delineate between the individual entities in your service, there are cases where it may be more appropriate or convenient to use nested data structures. -Nested data structures are easy enough to work with if they're read-only - simply nest your serializer classes and you're good to go. However, there are a few more subtleties to using writable nested serializers, due to the dependancies between the various model instances, and the need to save or delete multiple instances in a single action. +Nested data structures are easy enough to work with if they're read-only - simply nest your serializer classes and you're good to go. However, there are a few more subtleties to using writable nested serializers, due to the dependencies between the various model instances, and the need to save or delete multiple instances in a single action. -## One-to-many data structures +## One-to-many data structures *Example of a **read-only** nested serializer. Nothing complex to worry about here.* @@ -16,10 +16,10 @@ Nested data structures are easy enough to work with if they're read-only - simpl class Meta: model = ToDoItem fields = ('text', 'is_completed') - + class ToDoListSerializer(serializers.ModelSerializer): items = ToDoItemSerializer(many=True, read_only=True) - + class Meta: model = ToDoList fields = ('title', 'items') @@ -31,7 +31,7 @@ Some example output from our serializer. 'items': { {'text': 'Compile playlist', 'is_completed': True}, {'text': 'Send invites', 'is_completed': False}, - {'text': 'Clean house', 'is_completed': False} + {'text': 'Clean house', 'is_completed': False} } } @@ -44,4 +44,4 @@ Let's take a look at updating our nested one-to-many data structure. ### Making PATCH requests -[cite]: http://jsonapi.org/format/#url-based-json-api \ No newline at end of file +[cite]: http://jsonapi.org/format/#url-based-json-api diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index b0565d91a..f9027b688 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -41,20 +41,7 @@ Once that's done we can create an app that we'll use to create a simple Web API. python manage.py startapp snippets -The simplest way to get up and running will probably be to use an `sqlite3` database for the tutorial. Edit the `tutorial/settings.py` file, and set the default database `"ENGINE"` to `"sqlite3"`, and `"NAME"` to `"tmp.db"`. - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': 'tmp.db', - 'USER': '', - 'PASSWORD': '', - 'HOST': '', - 'PORT': '', - } - } - -We'll also need to add our new `snippets` app and the `rest_framework` app to `INSTALLED_APPS`. +We'll need to add our new `snippets` app and the `rest_framework` app to `INSTALLED_APPS`. Let's edit the `tutorial/settings.py` file: INSTALLED_APPS = ( ... @@ -72,7 +59,7 @@ Okay, we're ready to roll. ## Creating a model to work with -For the purposes of this tutorial we're going to start by creating a simple `Snippet` model that is used to store code snippets. Go ahead and edit the `snippets` app's `models.py` file. Note: Good programming practices include comments. Although you will find them in our repository version of this tutorial code, we have omitted them here to focus on the code itself. +For the purposes of this tutorial we're going to start by creating a simple `Snippet` model that is used to store code snippets. Go ahead and edit the `snippets/models.py` file. Note: Good programming practices include comments. Although you will find them in our repository version of this tutorial code, we have omitted them here to focus on the code itself. from django.db import models from pygments.lexers import get_all_lexers @@ -98,9 +85,10 @@ For the purposes of this tutorial we're going to start by creating a simple `Sni class Meta: ordering = ('created',) -Don't forget to sync the database for the first time. +We'll also need to create an initial migration for our snippet model, and sync the database for the first time. - python manage.py syncdb + python manage.py makemigrations snippets + python manage.py migrate ## Creating a Serializer class @@ -112,42 +100,41 @@ The first thing we need to get started on our Web API is to provide a way of ser class SnippetSerializer(serializers.Serializer): - pk = serializers.Field() # Note: `Field` is an untyped read-only field. + pk = serializers.IntegerField(read_only=True) title = serializers.CharField(required=False, max_length=100) - code = serializers.CharField(widget=widgets.Textarea, - max_length=100000) + code = serializers.CharField(style={'type': 'textarea'}) linenos = serializers.BooleanField(required=False) language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python') style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly') - def restore_object(self, attrs, instance=None): + def create(self, validated_attrs): """ - Create or update a new snippet instance, given a dictionary - of deserialized field values. - - Note that if we don't define this method, then deserializing - data will simply return a dictionary of items. + Create and return a new `Snippet` instance, given the validated data. """ - if instance: - # Update existing instance - instance.title = attrs.get('title', instance.title) - instance.code = attrs.get('code', instance.code) - instance.linenos = attrs.get('linenos', instance.linenos) - instance.language = attrs.get('language', instance.language) - instance.style = attrs.get('style', instance.style) - return instance + return Snippet.objects.create(**validated_attrs) - # Create new instance - return Snippet(**attrs) + def update(self, instance, validated_attrs): + """ + Update and return an existing `Snippet` instance, given the validated data. + """ + instance.title = validated_attrs.get('title', instance.title) + instance.code = validated_attrs.get('code', instance.code) + instance.linenos = validated_attrs.get('linenos', instance.linenos) + instance.language = validated_attrs.get('language', instance.language) + instance.style = validated_attrs.get('style', instance.style) + instance.save() + return instance -The first part of the serializer class defines the fields that get serialized/deserialized. The `restore_object` method defines how fully fledged instances get created when deserializing data. +The first part of the serializer class defines the fields that get serialized/deserialized. The `create()` and `update()` methods define how fully fledged instances are created or modified when calling `serializer.save()` -Notice that we can also use various attributes that would typically be used on form fields, such as `widget=widgets.Textarea`. These can be used to control how the serializer should render when displayed as an HTML form. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial. +A serializer class is very similar to a Django `Form` class, and includes similar validation flags on the various fields, such as `required`, `max_length` and `default`. -We can actually also save ourselves some time by using the `ModelSerializer` class, as we'll see later, but for now we'll keep our serializer definition explicit. +The field flags can also control how the serializer should be displayed in certain circumstances, such as when rendering to HTML. The `style={'type': 'textarea'}` flag above is equivelent to using `widget=widgets.Textarea` on a Django `Form` class. This is particularly useful for controlling how the browsable API should be displayed, as we'll see later in the tutorial. + +We can actually also save ourselves some time by using the `ModelSerializer` class, as we'll see later, but for now we'll keep our serializer definition explicit. ## Working with Serializers @@ -219,6 +206,24 @@ Open the file `snippets/serializers.py` again, and edit the `SnippetSerializer` model = Snippet fields = ('id', 'title', 'code', 'linenos', 'language', 'style') +Once nice property that serializers have is that you can inspect all the fields an serializer instance, by printing it's representation. Open the Django shell with `python manange.py shell`, then try the following: + + >>> from snippets.serializers import SnippetSerializer + >>> serializer = SnippetSerializer() + >>> print repr(serializer) # In python 3 use `print(repr(serializer))` + SnippetSerializer(): + id = IntegerField(label='ID', read_only=True) + title = CharField(allow_blank=True, max_length=100, required=False) + code = CharField(style={'type': 'textarea'}) + linenos = BooleanField(required=False) + language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')... + style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')... + +It's important to remember that `ModelSerializer` classes don't do anything particularly magically, they are simply a shortcut to creating a serializer class with: + +* An automatically determined set of fields. +* Simple default implementations for the `create()` and `update()` methods. + ## Writing regular Django views using our Serializer Let's see how we can write some API views using our new Serializer class. diff --git a/docs/tutorial/4-authentication-and-permissions.md b/docs/tutorial/4-authentication-and-permissions.md index 9120e2547..4e4edeeac 100644 --- a/docs/tutorial/4-authentication-and-permissions.md +++ b/docs/tutorial/4-authentication-and-permissions.md @@ -44,7 +44,9 @@ When that's all done we'll need to update our database tables. Normally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again. rm tmp.db - python manage.py syncdb + rm -r snippets/migrations + python manage.py makemigrations snippets + python manage.py migrate You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the `createsuperuser` command. @@ -92,24 +94,26 @@ Finally we need to add those views into the API, by referencing them from the UR Right now, if we created a code snippet, there'd be no way of associating the user that created the snippet, with the snippet instance. The user isn't sent as part of the serialized representation, but is instead a property of the incoming request. -The way we deal with that is by overriding a `.pre_save()` method on our snippet views, that allows us to handle any information that is implicit in the incoming request or requested URL. +The way we deal with that is by overriding a `.perform_create()` method on our snippet views, that allows us to modify how the instance save is managed, and handle any information that is implicit in the incoming request or requested URL. -On **both** the `SnippetList` and `SnippetDetail` view classes, add the following method: +On the `SnippetList` view class, add the following method: - def pre_save(self, obj): - obj.owner = self.request.user + def perform_create(self, serializer): + serializer.save(owner=self.request.user) + +The `create()` method of our serializer will now be passed an additional `'owner'` field, along with the validated data from the request. ## Updating our serializer Now that snippets are associated with the user that created them, let's update our `SnippetSerializer` to reflect that. Add the following field to the serializer definition in `serializers.py`: - owner = serializers.Field(source='owner.username') + owner = serializers.ReadOnlyField(source='owner.username') **Note**: Make sure you also add `'owner',` to the list of fields in the inner `Meta` class. This field is doing something quite interesting. The `source` argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django's template language. -The field we've added is the untyped `Field` class, in contrast to the other typed fields, such as `CharField`, `BooleanField` etc... The untyped `Field` is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. +The field we've added is the untyped `ReadOnlyField` class, in contrast to the other typed fields, such as `CharField`, `BooleanField` etc... The untyped `ReadOnlyField` is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. We could have also used `CharField(read_only=True)` here. ## Adding required permissions to views diff --git a/docs/tutorial/5-relationships-and-hyperlinked-apis.md b/docs/tutorial/5-relationships-and-hyperlinked-apis.md index 36473ce91..50552616b 100644 --- a/docs/tutorial/5-relationships-and-hyperlinked-apis.md +++ b/docs/tutorial/5-relationships-and-hyperlinked-apis.md @@ -6,7 +6,6 @@ At the moment relationships within our API are represented by using primary keys Right now we have endpoints for 'snippets' and 'users', but we don't have a single entry point to our API. To create one, we'll use a regular function-based view and the `@api_view` decorator we introduced earlier. In your `snippets/views.py` add: - from rest_framework import renderers from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework.reverse import reverse diff --git a/docs/tutorial/6-viewsets-and-routers.md b/docs/tutorial/6-viewsets-and-routers.md index cf37a2601..3fad509a1 100644 --- a/docs/tutorial/6-viewsets-and-routers.md +++ b/docs/tutorial/6-viewsets-and-routers.md @@ -60,7 +60,7 @@ To see what's going on under the hood let's first explicitly create a set of vie In the `urls.py` file we bind our `ViewSet` classes into a set of concrete views. - from snippets.views import SnippetViewSet, UserViewSet + from snippets.views import SnippetViewSet, UserViewSet, api_root from rest_framework import renderers snippet_list = SnippetViewSet.as_view({ diff --git a/docs/tutorial/quickstart.md b/docs/tutorial/quickstart.md index 813e9872c..1c398c1ff 100644 --- a/docs/tutorial/quickstart.md +++ b/docs/tutorial/quickstart.md @@ -19,18 +19,20 @@ Create a new Django project named `tutorial`, then start a new app called `quick pip install djangorestframework # Set up a new project with a single application - django-admin.py startproject tutorial . + django-admin.py startproject tutorial cd tutorial django-admin.py startapp quickstart cd .. Now sync your database for the first time: - python manage.py syncdb + python manage.py migrate -Make sure to create an initial user named `admin` with a password of `password`. We'll authenticate as that user later in our example. +We'll also create an initial user named `admin` with a password of `password`. We'll authenticate as that user later in our example. -Once you've set up a database and got everything synced and ready to go, open up the app's directory and we'll get coding... + python manage.py createsuperuser + +Once you've set up a database and initial user created and ready to go, open up the app's directory and we'll get coding... ## Serializers diff --git a/docs/404.html b/docs_theme/404.html similarity index 60% rename from docs/404.html rename to docs_theme/404.html index 864247e78..44993e37d 100644 --- a/docs/404.html +++ b/docs_theme/404.html @@ -1,50 +1,54 @@ - - - Django REST framework - 404 - Page not found - - - - - - - - - - + + + + Django REST framework - 404 - Page not found + + + + + - - + + + + + - + - - - + + + + + + + + + -
- +
+ + - - - - - - + + + + - // Dynamically force sidenav to no higher than browser window - $('.side-nav').css('max-height', window.innerHeight - 130); - - $(function(){ - $(window).resize(function(){ - $('.side-nav').css('max-height', window.innerHeight - 130); - }); - }); - - + diff --git a/docs_theme/base.html b/docs_theme/base.html new file mode 100644 index 000000000..6bfccab26 --- /dev/null +++ b/docs_theme/base.html @@ -0,0 +1,196 @@ + + + + + + + {{ page_title }} + + + + + + + + + + + + + + + + + + + + + +
+ + {% include "nav.html" %} + +
+
+ + + + +
+ +
+ +
+ + +
+
+ +
+ {% if meta.source %} + {% for filename in meta.source %} + + {{ filename }} + + {% endfor %} + {% endif %} + + {{ content }} +
+ +
+ +
+ +
+ +
+
+ + + + + + + + + + + + + + diff --git a/docs_theme/nav.html b/docs_theme/nav.html new file mode 100644 index 000000000..ca1afc0ec --- /dev/null +++ b/docs_theme/nav.html @@ -0,0 +1,47 @@ + diff --git a/mkdocs.py b/mkdocs.py deleted file mode 100755 index 25cb55e21..000000000 --- a/mkdocs.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python - -import markdown -import os -import re -import shutil -import sys - -root_dir = os.path.abspath(os.path.dirname(__file__)) -docs_dir = os.path.join(root_dir, 'docs') -html_dir = os.path.join(root_dir, 'html') - -local = not '--deploy' in sys.argv -preview = '-p' in sys.argv - -if local: - base_url = 'file://%s/' % os.path.normpath(os.path.join(os.getcwd(), html_dir)) - suffix = '.html' - index = 'index.html' -else: - base_url = 'http://www.django-rest-framework.org' - suffix = '' - index = '' - - -main_header = '
  • {{ title }}
  • ' -sub_header = '
  • {{ title }}
  • ' -code_label = r'\1' - -page = open(os.path.join(docs_dir, 'template.html'), 'r').read() - -# Copy static files -# 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): -# shutil.rmtree(target) -# shutil.copytree(source, target) - - -# Hacky, but what the hell, it'll do the job -path_list = [ - 'index.md', - 'tutorial/quickstart.md', - 'tutorial/1-serialization.md', - 'tutorial/2-requests-and-responses.md', - 'tutorial/3-class-based-views.md', - 'tutorial/4-authentication-and-permissions.md', - 'tutorial/5-relationships-and-hyperlinked-apis.md', - 'tutorial/6-viewsets-and-routers.md', - 'api-guide/requests.md', - 'api-guide/responses.md', - 'api-guide/views.md', - 'api-guide/generic-views.md', - 'api-guide/viewsets.md', - 'api-guide/routers.md', - 'api-guide/parsers.md', - 'api-guide/renderers.md', - 'api-guide/serializers.md', - 'api-guide/fields.md', - 'api-guide/relations.md', - 'api-guide/authentication.md', - 'api-guide/permissions.md', - 'api-guide/throttling.md', - 'api-guide/filtering.md', - 'api-guide/pagination.md', - 'api-guide/content-negotiation.md', - 'api-guide/format-suffixes.md', - 'api-guide/reverse.md', - 'api-guide/exceptions.md', - 'api-guide/status-codes.md', - 'api-guide/testing.md', - 'api-guide/settings.md', - 'topics/documenting-your-api.md', - 'topics/ajax-csrf-cors.md', - 'topics/browser-enhancements.md', - 'topics/browsable-api.md', - 'topics/rest-hypermedia-hateoas.md', - 'topics/third-party-resources.md', - 'topics/contributing.md', - 'topics/rest-framework-2-announcement.md', - 'topics/2.2-announcement.md', - 'topics/2.3-announcement.md', - 'topics/2.4-announcement.md', - 'topics/release-notes.md', - 'topics/credits.md', -] - -prev_url_map = {} -next_url_map = {} -for idx in range(len(path_list)): - path = path_list[idx] - rel = '../' * path.count('/') - - if idx == 1 and not local: - # Link back to '/', not '/index' - prev_url_map[path] = '/' - elif idx > 0: - prev_url_map[path] = rel + path_list[idx - 1][:-3] + suffix - - if idx < len(path_list) - 1: - next_url_map[path] = rel + path_list[idx + 1][:-3] + suffix - - -for (dirpath, dirnames, filenames) in os.walk(docs_dir): - relative_dir = dirpath.replace(docs_dir, '').lstrip(os.path.sep) - build_dir = os.path.join(html_dir, relative_dir) - - if not os.path.exists(build_dir): - os.makedirs(build_dir) - - for filename in filenames: - path = os.path.join(dirpath, filename) - relative_path = os.path.join(relative_dir, filename) - - if not filename.endswith('.md'): - if relative_dir: - output_path = os.path.join(build_dir, filename) - shutil.copy(path, output_path) - continue - - output_path = os.path.join(build_dir, filename[:-3] + '.html') - - toc = '' - text = open(path, 'r').read().decode('utf-8') - main_title = None - description = 'Django, API, REST' - for line in text.splitlines(): - if line.startswith('# '): - title = line[2:].strip() - template = main_header - description = description + ', ' + title - elif line.startswith('## '): - title = line[3:].strip() - template = sub_header - else: - continue - - if not main_title: - main_title = title - anchor = title.lower().replace(' ', '-').replace(':-', '-').replace("'", '').replace('?', '').replace('.', '') - template = template.replace('{{ title }}', title) - template = template.replace('{{ anchor }}', anchor) - toc += template + '\n' - - if filename == 'index.md': - main_title = 'Django REST framework - Web APIs for Django' - else: - main_title = main_title + ' - Django REST framework' - - if relative_path == 'index.md': - canonical_url = base_url - else: - canonical_url = base_url + '/' + relative_path[:-3] + suffix - prev_url = prev_url_map.get(relative_path) - next_url = next_url_map.get(relative_path) - - content = markdown.markdown(text, ['headerid']) - - output = page.replace('{{ content }}', content).replace('{{ toc }}', toc).replace('{{ base_url }}', base_url).replace('{{ suffix }}', suffix).replace('{{ index }}', index) - output = output.replace('{{ title }}', main_title) - output = output.replace('{{ description }}', description) - output = output.replace('{{ page_id }}', filename[:-3]) - output = output.replace('{{ canonical_url }}', canonical_url) - - if filename =='index.md': - output = output.replace('{{ ad_block }}', """
    - """) - else: - output = output.replace('{{ ad_block }}', '') - - if prev_url: - output = output.replace('{{ prev_url }}', prev_url) - output = output.replace('{{ prev_url_disabled }}', '') - else: - output = output.replace('{{ prev_url }}', '#') - output = output.replace('{{ prev_url_disabled }}', 'disabled') - - if next_url: - output = output.replace('{{ next_url }}', next_url) - output = output.replace('{{ next_url_disabled }}', '') - else: - output = output.replace('{{ next_url }}', '#') - output = output.replace('{{ next_url_disabled }}', 'disabled') - - output = re.sub(r'a href="([^"]*)\.md"', r'a href="\1%s"' % suffix, output) - output = re.sub(r'
    :::bash', r'
    ', output)
    -        output = re.sub(r'
    ', r'
    ', output)
    -        output = re.sub(r'', code_label, output)
    -        open(output_path, 'w').write(output.encode('utf-8'))
    -
    -if preview:
    -    import subprocess
    -
    -    url = 'html/index.html'
    -
    -    try:
    -        subprocess.Popen(["open", url])  # Mac
    -    except OSError:
    -        subprocess.Popen(["xdg-open", url])  # Linux
    -    except:
    -        os.startfile(url)  # Windows
    diff --git a/mkdocs.yml b/mkdocs.yml
    new file mode 100644
    index 000000000..8932fa96e
    --- /dev/null
    +++ b/mkdocs.yml
    @@ -0,0 +1,57 @@
    +site_name: Django REST framework
    +site_url: http://www.django-rest-framework.org/
    +site_description: Django REST framework - Web APIs for Django
    +
    +repo_url: https://github.com/tomchristie/django-rest-framework
    +
    +theme_dir: docs_theme
    +
    +pages:
    + - ['index.md', 'Home']
    + - ['tutorial/quickstart.md', 'Tutorial', 'Quickstart']
    + - ['tutorial/1-serialization.md', 'Tutorial', '1 - Serialization']
    + - ['tutorial/2-requests-and-responses.md', 'Tutorial', '2 - Requests and responses']
    + - ['tutorial/3-class-based-views.md', 'Tutorial', '3 - Class based views']
    + - ['tutorial/4-authentication-and-permissions.md', 'Tutorial', '4 - Authentication and permissions']
    + - ['tutorial/5-relationships-and-hyperlinked-apis.md', 'Tutorial', '5 - Relationships and hyperlinked APIs']
    + - ['tutorial/6-viewsets-and-routers.md', 'Tutorial', '6 - Viewsets and routers']
    + - ['api-guide/requests.md', 'API Guide', 'Requests']
    + - ['api-guide/responses.md', 'API Guide', 'Responses']
    + - ['api-guide/views.md', 'API Guide', 'Views']
    + - ['api-guide/generic-views.md', 'API Guide', 'Generic views']
    + - ['api-guide/viewsets.md', 'API Guide', 'Viewsets']
    + - ['api-guide/routers.md', 'API Guide', 'Routers']
    + - ['api-guide/parsers.md', 'API Guide', 'Parsers']
    + - ['api-guide/renderers.md', 'API Guide', 'Renderers']
    + - ['api-guide/serializers.md', 'API Guide', 'Serializers']
    + - ['api-guide/fields.md', 'API Guide', 'Serializer fields']
    + - ['api-guide/relations.md', 'API Guide', 'Serializer relations']
    +# - ['api-guide/validators.md', 'API Guide', 'Validators']
    + - ['api-guide/authentication.md', 'API Guide', 'Authentication']
    + - ['api-guide/permissions.md', 'API Guide', 'Permissions']
    + - ['api-guide/throttling.md', 'API Guide', 'Throttling']
    + - ['api-guide/filtering.md', 'API Guide', 'Filtering']
    + - ['api-guide/pagination.md', 'API Guide', 'Pagination']
    + - ['api-guide/content-negotiation.md', 'API Guide', 'Content negotiation']
    + - ['api-guide/format-suffixes.md', 'API Guide', 'Format suffixes']
    + - ['api-guide/reverse.md', 'API Guide', 'Returning URLs']
    + - ['api-guide/exceptions.md', 'API Guide', 'Exceptions']
    + - ['api-guide/status-codes.md', 'API Guide', 'Status codes']
    + - ['api-guide/testing.md', 'API Guide', 'Testing']
    + - ['api-guide/settings.md', 'API Guide', 'Settings']
    + - ['topics/documenting-your-api.md', 'Topics', 'Documenting your API']
    + - ['topics/ajax-csrf-cors.md', 'Topics', 'AJAX, CSRF & CORS']
    + - ['topics/browser-enhancements.md', 'Topics',]
    + - ['topics/browsable-api.md', 'Topics', 'The Browsable API']
    + - ['topics/rest-hypermedia-hateoas.md', 'Topics', 'REST, Hypermedia & HATEOAS']
    + - ['topics/third-party-resources.md', 'Topics', 'Third Party Resources']
    + - ['topics/contributing.md', 'Topics', 'Contributing to REST framework']
    + - ['topics/rest-framework-2-announcement.md', 'Topics', '2.0 Announcement']
    + - ['topics/2.2-announcement.md', 'Topics', '2.2 Announcement']
    + - ['topics/2.3-announcement.md', 'Topics', '2.3 Announcement']
    + - ['topics/2.4-announcement.md', 'Topics', '2.4 Announcement']
    + - ['topics/kickstarter-announcement.md', 'Topics', 'Kickstarter Announcement']
    + - ['topics/release-notes.md', 'Topics', 'Release Notes']
    + - ['topics/credits.md', 'Topics', 'Credits']
    +
    +google_analytics: ['UA-18852272-2', 'django-rest-framework.org']
    diff --git a/requirements-test.txt b/requirements-test.txt
    index 411daeba2..06c8849a8 100644
    --- a/requirements-test.txt
    +++ b/requirements-test.txt
    @@ -8,8 +8,8 @@ flake8==2.2.2
     markdown>=2.1.0
     PyYAML>=3.10
     defusedxml>=0.3
    +django-guardian==1.2.4
     django-filter>=0.5.4
     django-oauth-plus>=2.2.1
     oauth2>=1.5.211
     django-oauth2-provider>=0.2.4
    -Pillow==2.3.0
    diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py
    index 7f724c185..261c9c984 100644
    --- a/rest_framework/__init__.py
    +++ b/rest_framework/__init__.py
    @@ -8,7 +8,7 @@ ______ _____ _____ _____    __
     """
     
     __title__ = 'Django REST framework'
    -__version__ = '2.4.3'
    +__version__ = '3.0.0'
     __author__ = 'Tom Christie'
     __license__ = 'BSD 2-Clause'
     __copyright__ = 'Copyright 2011-2014 Tom Christie'
    diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
    index f3fec05ec..36d74dd9b 100644
    --- a/rest_framework/authentication.py
    +++ b/rest_framework/authentication.py
    @@ -129,7 +129,7 @@ class SessionAuthentication(BaseAuthentication):
             reason = CSRFCheck().process_view(request, None, (), {})
             if reason:
                 # CSRF failed, bail with explicit error message
    -            raise exceptions.AuthenticationFailed('CSRF Failed: %s' % reason)
    +            raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
     
     
     class TokenAuthentication(BaseAuthentication):
    diff --git a/rest_framework/authtoken/serializers.py b/rest_framework/authtoken/serializers.py
    index 472e59ee3..f31dded17 100644
    --- a/rest_framework/authtoken/serializers.py
    +++ b/rest_framework/authtoken/serializers.py
    @@ -1,7 +1,7 @@
     from django.contrib.auth import authenticate
     from django.utils.translation import ugettext_lazy as _
     
    -from rest_framework import serializers
    +from rest_framework import exceptions, serializers
     
     
     class AuthTokenSerializer(serializers.Serializer):
    @@ -18,12 +18,13 @@ class AuthTokenSerializer(serializers.Serializer):
                 if user:
                     if not user.is_active:
                         msg = _('User account is disabled.')
    -                    raise serializers.ValidationError(msg)
    -                attrs['user'] = user
    -                return attrs
    +                    raise exceptions.ValidationError(msg)
                 else:
                     msg = _('Unable to log in with provided credentials.')
    -                raise serializers.ValidationError(msg)
    +                raise exceptions.ValidationError(msg)
             else:
                 msg = _('Must include "username" and "password"')
    -            raise serializers.ValidationError(msg)
    +            raise exceptions.ValidationError(msg)
    +
    +        attrs['user'] = user
    +        return attrs
    diff --git a/rest_framework/authtoken/views.py b/rest_framework/authtoken/views.py
    index 7c03cb766..103abb27c 100644
    --- a/rest_framework/authtoken/views.py
    +++ b/rest_framework/authtoken/views.py
    @@ -16,9 +16,10 @@ class ObtainAuthToken(APIView):
         model = Token
     
         def post(self, request):
    -        serializer = self.serializer_class(data=request.DATA)
    +        serializer = self.serializer_class(data=request.data)
             if serializer.is_valid():
    -            token, created = Token.objects.get_or_create(user=serializer.object['user'])
    +            user = serializer.validated_data['user']
    +            token, created = Token.objects.get_or_create(user=user)
                 return Response({'token': token.key})
             return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
     
    diff --git a/rest_framework/compat.py b/rest_framework/compat.py
    index fa0f0bfb1..5bd85e743 100644
    --- a/rest_framework/compat.py
    +++ b/rest_framework/compat.py
    @@ -5,11 +5,12 @@ versions of django/python, and compatibility wrappers around optional packages.
     
     # flake8: noqa
     from __future__ import unicode_literals
    -import django
    -import inspect
    +
     from django.core.exceptions import ImproperlyConfigured
     from django.conf import settings
     from django.utils import six
    +import django
    +import inspect
     
     
     # Handle django.utils.encoding rename in 1.5 onwards.
    @@ -25,6 +26,16 @@ except ImportError:
         from django.utils.encoding import force_unicode as force_text
     
     
    +# OrderedDict only available in Python 2.7.
    +# This will always be the case in Django 1.7 and above, as these versions
    +# no longer support Python 2.6.
    +# For Django <= 1.6 and Python 2.6 fall back to OrderedDict.
    +try:
    +    from collections import OrderedDict
    +except:
    +    from django.utils.datastructures import SortedDict as OrderedDict
    +
    +
     # HttpResponseBase only exists from 1.5 onwards
     try:
         from django.http.response import HttpResponseBase
    @@ -39,6 +50,17 @@ except ImportError:
         django_filters = None
     
     
    +if django.VERSION >= (1, 6):
    +    def clean_manytomany_helptext(text):
    +        return text
    +else:
    +    # Up to version 1.5 many to many fields automatically suffix
    +    # the `help_text` attribute with hardcoded text.
    +    def clean_manytomany_helptext(text):
    +        if text.endswith(' Hold down "Control", or "Command" on a Mac, to select more than one.'):
    +            text = text[:-69]
    +        return text
    +
     # Django-guardian is optional. Import only if guardian is in INSTALLED_APPS
     # Fixes (#1712). We keep the try/except for the test suite.
     guardian = None
    @@ -73,15 +95,6 @@ except ImportError:
         from collections import UserDict
         from collections import MutableMapping as DictMixin
     
    -# Try to import PIL in either of the two ways it can end up installed.
    -try:
    -    from PIL import Image
    -except ImportError:
    -    try:
    -        import Image
    -    except ImportError:
    -        Image = None
    -
     
     def get_model_name(model_cls):
         try:
    @@ -110,6 +123,62 @@ else:
                 return [m.upper() for m in self.http_method_names if hasattr(self, m)]
     
     
    +
    +# MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+
    +if django.VERSION >= (1, 8):
    +    from django.core.validators import MinValueValidator, MaxValueValidator
    +    from django.core.validators import MinLengthValidator, MaxLengthValidator
    +else:
    +    from django.core.validators import MinValueValidator as DjangoMinValueValidator
    +    from django.core.validators import MaxValueValidator as DjangoMaxValueValidator
    +    from django.core.validators import MinLengthValidator as DjangoMinLengthValidator
    +    from django.core.validators import MaxLengthValidator as DjangoMaxLengthValidator
    +
    +    class MinValueValidator(DjangoMinValueValidator):
    +        def __init__(self, *args, **kwargs):
    +            self.message = kwargs.pop('message', self.message)
    +            super(MinValueValidator, self).__init__(*args, **kwargs)
    +
    +    class MaxValueValidator(DjangoMaxValueValidator):
    +        def __init__(self, *args, **kwargs):
    +            self.message = kwargs.pop('message', self.message)
    +            super(MaxValueValidator, self).__init__(*args, **kwargs)
    +
    +    class MinLengthValidator(DjangoMinLengthValidator):
    +        def __init__(self, *args, **kwargs):
    +            self.message = kwargs.pop('message', self.message)
    +            super(MinLengthValidator, self).__init__(*args, **kwargs)
    +
    +    class MaxLengthValidator(DjangoMaxLengthValidator):
    +        def __init__(self, *args, **kwargs):
    +            self.message = kwargs.pop('message', self.message)
    +            super(MaxLengthValidator, self).__init__(*args, **kwargs)
    +
    +
    +# URLValidator only accepts `message` in 1.6+
    +if django.VERSION >= (1, 6):
    +    from django.core.validators import URLValidator
    +else:
    +    from django.core.validators import URLValidator as DjangoURLValidator
    +
    +    class URLValidator(DjangoURLValidator):
    +        def __init__(self, *args, **kwargs):
    +            self.message = kwargs.pop('message', self.message)
    +            super(URLValidator, self).__init__(*args, **kwargs)
    +
    +
    +# EmailValidator requires explicit regex prior to 1.6+
    +if django.VERSION >= (1, 6):
    +    from django.core.validators import EmailValidator
    +else:
    +    from django.core.validators import EmailValidator as DjangoEmailValidator
    +    from django.core.validators import email_re
    +
    +    class EmailValidator(DjangoEmailValidator):
    +        def __init__(self, *args, **kwargs):
    +            super(EmailValidator, self).__init__(email_re, *args, **kwargs)
    +
    +
     # PATCH method is not implemented by Django
     if 'patch' not in View.http_method_names:
         View.http_method_names = View.http_method_names + ['patch']
    @@ -133,12 +202,12 @@ class RequestFactory(DjangoRequestFactory):
             r = {
                 'PATH_INFO':      self._get_path(parsed),
                 'QUERY_STRING':   force_text(parsed[4]),
    -            'REQUEST_METHOD': str(method),
    +            'REQUEST_METHOD': six.text_type(method),
             }
             if data:
                 r.update({
                     'CONTENT_LENGTH': len(data),
    -                'CONTENT_TYPE':   str(content_type),
    +                'CONTENT_TYPE':   six.text_type(content_type),
                     'wsgi.input':     FakePayload(data),
                 })
             elif django.VERSION <= (1, 4):
    @@ -232,6 +301,15 @@ except ImportError:
         oauth2_constants = None
         provider_now = None
     
    +# `seperators` argument to `json.dumps()` differs between 2.x and 3.x
    +# See: http://bugs.python.org/issue22767
    +if six.PY3:
    +    SHORT_SEPARATORS = (',', ':')
    +    LONG_SEPARATORS = (', ', ': ')
    +else:
    +    SHORT_SEPARATORS = (b',', b':')
    +    LONG_SEPARATORS = (b', ', b': ')
    +
     
     # Handle lazy strings across Py2/Py3
     from django.utils.functional import Promise
    diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py
    index 449ba0a29..d28d6e22a 100644
    --- a/rest_framework/decorators.py
    +++ b/rest_framework/decorators.py
    @@ -10,7 +10,6 @@ from __future__ import unicode_literals
     from django.utils import six
     from rest_framework.views import APIView
     import types
    -import warnings
     
     
     def api_view(http_method_names):
    @@ -130,37 +129,3 @@ def list_route(methods=['get'], **kwargs):
             func.kwargs = kwargs
             return func
         return decorator
    -
    -
    -# These are now pending deprecation, in favor of `detail_route` and `list_route`.
    -
    -def link(**kwargs):
    -    """
    -    Used to mark a method on a ViewSet that should be routed for detail GET requests.
    -    """
    -    msg = 'link is pending deprecation. Use detail_route instead.'
    -    warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
    -
    -    def decorator(func):
    -        func.bind_to_methods = ['get']
    -        func.detail = True
    -        func.kwargs = kwargs
    -        return func
    -
    -    return decorator
    -
    -
    -def action(methods=['post'], **kwargs):
    -    """
    -    Used to mark a method on a ViewSet that should be routed for detail POST requests.
    -    """
    -    msg = 'action is pending deprecation. Use detail_route instead.'
    -    warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
    -
    -    def decorator(func):
    -        func.bind_to_methods = methods
    -        func.detail = True
    -        func.kwargs = kwargs
    -        return func
    -
    -    return decorator
    diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py
    index ad52d1726..906de3b04 100644
    --- a/rest_framework/exceptions.py
    +++ b/rest_framework/exceptions.py
    @@ -5,80 +5,143 @@ In addition Django's built in 403 and 404 exceptions are handled.
     (`django.http.Http404` and `django.core.exceptions.PermissionDenied`)
     """
     from __future__ import unicode_literals
    +
    +from django.utils.translation import ugettext_lazy as _
    +from django.utils.translation import ungettext_lazy
     from rest_framework import status
    +from rest_framework.compat import force_text
     import math
     
     
    +def _force_text_recursive(data):
    +    """
    +    Descend into a nested data structure, forcing any
    +    lazy translation strings into plain text.
    +    """
    +    if isinstance(data, list):
    +        return [
    +            _force_text_recursive(item) for item in data
    +        ]
    +    elif isinstance(data, dict):
    +        return dict([
    +            (key, _force_text_recursive(value))
    +            for key, value in data.items()
    +        ])
    +    return force_text(data)
    +
    +
     class APIException(Exception):
         """
         Base class for REST framework exceptions.
         Subclasses should provide `.status_code` and `.default_detail` properties.
         """
         status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    -    default_detail = ''
    +    default_detail = _('A server error occured')
     
         def __init__(self, detail=None):
    -        self.detail = detail or self.default_detail
    +        if detail is not None:
    +            self.detail = force_text(detail)
    +        else:
    +            self.detail = force_text(self.default_detail)
     
         def __str__(self):
             return self.detail
     
     
    +# The recommended style for using `ValidationError` is to keep it namespaced
    +# under `serializers`, in order to minimize potential confusion with Django's
    +# built in `ValidationError`. For example:
    +#
    +# from rest_framework import serializers
    +# raise serializers.ValidationError('Value was invalid')
    +
    +class ValidationError(APIException):
    +    status_code = status.HTTP_400_BAD_REQUEST
    +
    +    def __init__(self, detail):
    +        # For validation errors the 'detail' key is always required.
    +        # The details should always be coerced to a list if not already.
    +        if not isinstance(detail, dict) and not isinstance(detail, list):
    +            detail = [detail]
    +        self.detail = _force_text_recursive(detail)
    +
    +    def __str__(self):
    +        return str(self.detail)
    +
    +
     class ParseError(APIException):
         status_code = status.HTTP_400_BAD_REQUEST
    -    default_detail = 'Malformed request.'
    +    default_detail = _('Malformed request.')
     
     
     class AuthenticationFailed(APIException):
         status_code = status.HTTP_401_UNAUTHORIZED
    -    default_detail = 'Incorrect authentication credentials.'
    +    default_detail = _('Incorrect authentication credentials.')
     
     
     class NotAuthenticated(APIException):
         status_code = status.HTTP_401_UNAUTHORIZED
    -    default_detail = 'Authentication credentials were not provided.'
    +    default_detail = _('Authentication credentials were not provided.')
     
     
     class PermissionDenied(APIException):
         status_code = status.HTTP_403_FORBIDDEN
    -    default_detail = 'You do not have permission to perform this action.'
    +    default_detail = _('You do not have permission to perform this action.')
     
     
     class MethodNotAllowed(APIException):
         status_code = status.HTTP_405_METHOD_NOT_ALLOWED
    -    default_detail = "Method '%s' not allowed."
    +    default_detail = _("Method '%s' not allowed.")
     
         def __init__(self, method, detail=None):
    -        self.detail = (detail or self.default_detail) % method
    +        if detail is not None:
    +            self.detail = force_text(detail)
    +        else:
    +            self.detail = force_text(self.default_detail) % method
     
     
     class NotAcceptable(APIException):
         status_code = status.HTTP_406_NOT_ACCEPTABLE
    -    default_detail = "Could not satisfy the request's Accept header"
    +    default_detail = _('Could not satisfy the request Accept header')
     
         def __init__(self, detail=None, available_renderers=None):
    -        self.detail = detail or self.default_detail
    +        if detail is not None:
    +            self.detail = force_text(detail)
    +        else:
    +            self.detail = force_text(self.default_detail)
             self.available_renderers = available_renderers
     
     
     class UnsupportedMediaType(APIException):
         status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
    -    default_detail = "Unsupported media type '%s' in request."
    +    default_detail = _("Unsupported media type '%s' in request.")
     
         def __init__(self, media_type, detail=None):
    -        self.detail = (detail or self.default_detail) % media_type
    +        if detail is not None:
    +            self.detail = force_text(detail)
    +        else:
    +            self.detail = force_text(self.default_detail) % media_type
     
     
     class Throttled(APIException):
         status_code = status.HTTP_429_TOO_MANY_REQUESTS
    -    default_detail = 'Request was throttled.'
    -    extra_detail = " Expected available in %d second%s."
    +    default_detail = _('Request was throttled.')
    +    extra_detail = ungettext_lazy(
    +        'Expected available in %(wait)d second.',
    +        'Expected available in %(wait)d seconds.',
    +        'wait'
    +    )
     
         def __init__(self, wait=None, detail=None):
    +        if detail is not None:
    +            self.detail = force_text(detail)
    +        else:
    +            self.detail = force_text(self.default_detail)
    +
             if wait is None:
    -            self.detail = detail or self.default_detail
                 self.wait = None
             else:
    -            format = (detail or self.default_detail) + self.extra_detail
    -            self.detail = format % (wait, wait != 1 and 's' or '')
                 self.wait = math.ceil(wait)
    +            self.detail += ' ' + force_text(
    +                self.extra_detail % {'wait': self.wait}
    +            )
    diff --git a/rest_framework/fields.py b/rest_framework/fields.py
    index c0253f86b..3cf348865 100644
    --- a/rest_framework/fields.py
    +++ b/rest_framework/fields.py
    @@ -1,34 +1,35 @@
    -"""
    -Serializer fields perform validation on incoming data.
    -
    -They are very similar to Django's form fields.
    -"""
    -from __future__ import unicode_literals
    -
    -import copy
    -import datetime
    -import inspect
    -import re
    -import warnings
    -from decimal import Decimal, DecimalException
    -from django import forms
    -from django.core import validators
    -from django.core.exceptions import ValidationError
     from django.conf import settings
    -from django.db.models.fields import BLANK_CHOICE_DASH
    -from django.http import QueryDict
    -from django.forms import widgets
    +from django.core.exceptions import ObjectDoesNotExist
    +from django.core.exceptions import ValidationError as DjangoValidationError
    +from django.core.validators import RegexValidator
    +from django.forms import ImageField as DjangoImageField
     from django.utils import six, timezone
    +from django.utils.dateparse import parse_date, parse_datetime, parse_time
     from django.utils.encoding import is_protected_type
     from django.utils.translation import ugettext_lazy as _
    -from django.utils.datastructures import SortedDict
    -from django.utils.dateparse import parse_date, parse_datetime, parse_time
     from rest_framework import ISO_8601
     from rest_framework.compat import (
    -    BytesIO, smart_text,
    -    force_text, is_non_str_iterable
    +    smart_text, EmailValidator, MinValueValidator, MaxValueValidator,
    +    MinLengthValidator, MaxLengthValidator, URLValidator, OrderedDict
     )
    +from rest_framework.exceptions import ValidationError
     from rest_framework.settings import api_settings
    +from rest_framework.utils import html, representation, humanize_datetime
    +import copy
    +import datetime
    +import decimal
    +import inspect
    +import re
    +
    +
    +class empty:
    +    """
    +    This class is used to represent no data being provided for a given input
    +    or output value.
    +
    +    It is required because `None` may be a valid input or output value.
    +    """
    +    pass
     
     
     def is_simple_callable(obj):
    @@ -47,606 +48,782 @@ def is_simple_callable(obj):
         return len_args <= len_defaults
     
     
    -def get_component(obj, attr_name):
    +def get_attribute(instance, attrs):
         """
    -    Given an object, and an attribute name,
    -    return that attribute on the object.
    +    Similar to Python's built in `getattr(instance, attr)`,
    +    but takes a list of nested attributes, instead of a single attribute.
    +
    +    Also accepts either attribute lookup on objects or dictionary lookups.
         """
    -    if isinstance(obj, dict):
    -        val = obj.get(attr_name)
    -    else:
    -        val = getattr(obj, attr_name)
    -
    -    if is_simple_callable(val):
    -        return val()
    -    return val
    +    for attr in attrs:
    +        if instance is None:
    +            # Break out early if we get `None` at any point in a nested lookup.
    +            return None
    +        try:
    +            instance = getattr(instance, attr)
    +        except ObjectDoesNotExist:
    +            return None
    +        except AttributeError as exc:
    +            try:
    +                return instance[attr]
    +            except (KeyError, TypeError, AttributeError):
    +                raise exc
    +    if is_simple_callable(instance):
    +        return instance()
    +    return instance
     
     
    -def readable_datetime_formats(formats):
    -    format = ', '.join(formats).replace(
    -        ISO_8601,
    -        'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]'
    -    )
    -    return humanize_strptime(format)
    -
    -
    -def readable_date_formats(formats):
    -    format = ', '.join(formats).replace(ISO_8601, 'YYYY[-MM[-DD]]')
    -    return humanize_strptime(format)
    -
    -
    -def readable_time_formats(formats):
    -    format = ', '.join(formats).replace(ISO_8601, 'hh:mm[:ss[.uuuuuu]]')
    -    return humanize_strptime(format)
    -
    -
    -def humanize_strptime(format_string):
    -    # Note that we're missing some of the locale specific mappings that
    -    # don't really make sense.
    -    mapping = {
    -        "%Y": "YYYY",
    -        "%y": "YY",
    -        "%m": "MM",
    -        "%b": "[Jan-Dec]",
    -        "%B": "[January-December]",
    -        "%d": "DD",
    -        "%H": "hh",
    -        "%I": "hh",  # Requires '%p' to differentiate from '%H'.
    -        "%M": "mm",
    -        "%S": "ss",
    -        "%f": "uuuuuu",
    -        "%a": "[Mon-Sun]",
    -        "%A": "[Monday-Sunday]",
    -        "%p": "[AM|PM]",
    -        "%z": "[+HHMM|-HHMM]"
    -    }
    -    for key, val in mapping.items():
    -        format_string = format_string.replace(key, val)
    -    return format_string
    -
    -
    -def strip_multiple_choice_msg(help_text):
    +def set_value(dictionary, keys, value):
         """
    -    Remove the 'Hold down "control" ...' message that is Django enforces in
    -    select multiple fields on ModelForms.  (Required for 1.5 and earlier)
    +    Similar to Python's built in `dictionary[key] = value`,
    +    but takes a list of nested keys instead of a single key.
     
    -    See https://code.djangoproject.com/ticket/9321
    +    set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2}
    +    set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2}
    +    set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}}
         """
    -    multiple_choice_msg = _(' Hold down "Control", or "Command" on a Mac, to select more than one.')
    -    multiple_choice_msg = force_text(multiple_choice_msg)
    -
    -    return help_text.replace(multiple_choice_msg, '')
    -
    -
    -class Field(object):
    -    read_only = True
    -    creation_counter = 0
    -    empty = ''
    -    type_name = None
    -    partial = False
    -    use_files = False
    -    form_field_class = forms.CharField
    -    type_label = 'field'
    -    widget = None
    -
    -    def __init__(self, source=None, label=None, help_text=None):
    -        self.parent = None
    -
    -        self.creation_counter = Field.creation_counter
    -        Field.creation_counter += 1
    -
    -        self.source = source
    -
    -        if label is not None:
    -            self.label = smart_text(label)
    -        else:
    -            self.label = None
    -
    -        if help_text is not None:
    -            self.help_text = strip_multiple_choice_msg(smart_text(help_text))
    -        else:
    -            self.help_text = None
    -
    -        self._errors = []
    -        self._value = None
    -        self._name = None
    -
    -    @property
    -    def errors(self):
    -        return self._errors
    -
    -    def widget_html(self):
    -        if not self.widget:
    -            return ''
    -
    -        attrs = {}
    -        if 'id' not in self.widget.attrs:
    -            attrs['id'] = self._name
    -
    -        return self.widget.render(self._name, self._value, attrs=attrs)
    -
    -    def label_tag(self):
    -        return '' % (self._name, self.label)
    -
    -    def initialize(self, parent, field_name):
    -        """
    -        Called to set up a field prior to field_to_native or field_from_native.
    -
    -        parent - The parent serializer.
    -        field_name - The name of the field being initialized.
    -        """
    -        self.parent = parent
    -        self.root = parent.root or parent
    -        self.context = self.root.context
    -        self.partial = self.root.partial
    -        if self.partial:
    -            self.required = False
    -
    -    def field_from_native(self, data, files, field_name, into):
    -        """
    -        Given a dictionary and a field name, updates the dictionary `into`,
    -        with the field and it's deserialized value.
    -        """
    +    if not keys:
    +        dictionary.update(value)
             return
     
    -    def field_to_native(self, obj, field_name):
    -        """
    -        Given an object and a field name, returns the value that should be
    -        serialized for that field.
    -        """
    -        if obj is None:
    -            return self.empty
    +    for key in keys[:-1]:
    +        if key not in dictionary:
    +            dictionary[key] = {}
    +        dictionary = dictionary[key]
     
    -        if self.source == '*':
    -            return self.to_native(obj)
    -
    -        source = self.source or field_name
    -        value = obj
    -
    -        for component in source.split('.'):
    -            value = get_component(value, component)
    -            if value is None:
    -                break
    -
    -        return self.to_native(value)
    -
    -    def to_native(self, value):
    -        """
    -        Converts the field's value into it's simple representation.
    -        """
    -        if is_simple_callable(value):
    -            value = value()
    -
    -        if is_protected_type(value):
    -            return value
    -        elif (is_non_str_iterable(value) and
    -              not isinstance(value, (dict, six.string_types))):
    -            return [self.to_native(item) for item in value]
    -        elif isinstance(value, dict):
    -            # Make sure we preserve field ordering, if it exists
    -            ret = SortedDict()
    -            for key, val in value.items():
    -                ret[key] = self.to_native(val)
    -            return ret
    -        return force_text(value)
    -
    -    def attributes(self):
    -        """
    -        Returns a dictionary of attributes to be used when serializing to xml.
    -        """
    -        if self.type_name:
    -            return {'type': self.type_name}
    -        return {}
    -
    -    def metadata(self):
    -        metadata = SortedDict()
    -        metadata['type'] = self.type_label
    -        metadata['required'] = getattr(self, 'required', False)
    -        optional_attrs = ['read_only', 'label', 'help_text',
    -                          'min_length', 'max_length']
    -        for attr in optional_attrs:
    -            value = getattr(self, attr, None)
    -            if value is not None and value != '':
    -                metadata[attr] = force_text(value, strings_only=True)
    -        return metadata
    +    dictionary[keys[-1]] = value
     
     
    -class WritableField(Field):
    +class CreateOnlyDefault:
         """
    -    Base for read/write fields.
    +    This class may be used to provide default values that are only used
    +    for create operations, but that do not return any value for update
    +    operations.
         """
    -    write_only = False
    -    default_validators = []
    -    default_error_messages = {
    -        'required': _('This field is required.'),
    -        'invalid': _('Invalid value.'),
    -    }
    -    widget = widgets.TextInput
    -    default = None
    +    def __init__(self, default):
    +        self.default = default
     
    -    def __init__(self, source=None, label=None, help_text=None,
    -                 read_only=False, write_only=False, required=None,
    -                 validators=[], error_messages=None, widget=None,
    -                 default=None, blank=None):
    +    def set_context(self, serializer_field):
    +        self.is_update = serializer_field.parent.instance is not None
     
    -        super(WritableField, self).__init__(source=source, label=label, help_text=help_text)
    -
    -        self.read_only = read_only
    -        self.write_only = write_only
    -
    -        assert not (read_only and write_only), "Cannot set read_only=True and write_only=True"
    -
    -        if required is None:
    -            self.required = not(read_only)
    -        else:
    -            assert not (read_only and required), "Cannot set required=True and read_only=True"
    -            self.required = required
    -
    -        messages = {}
    -        for c in reversed(self.__class__.__mro__):
    -            messages.update(getattr(c, 'default_error_messages', {}))
    -        messages.update(error_messages or {})
    -        self.error_messages = messages
    -
    -        self.validators = self.default_validators + validators
    -        self.default = default if default is not None else self.default
    -
    -        # Widgets are only used for HTML forms.
    -        widget = widget or self.widget
    -        if isinstance(widget, type):
    -            widget = widget()
    -        self.widget = widget
    -
    -    def __deepcopy__(self, memo):
    -        result = copy.copy(self)
    -        memo[id(self)] = result
    -        result.validators = self.validators[:]
    -        return result
    -
    -    def get_default_value(self):
    -        if is_simple_callable(self.default):
    +    def __call__(self):
    +        if self.is_update:
    +            raise SkipField()
    +        if callable(self.default):
                 return self.default()
             return self.default
     
    -    def validate(self, value):
    -        if value in validators.EMPTY_VALUES and self.required:
    -            raise ValidationError(self.error_messages['required'])
    +    def __repr__(self):
    +        return '%s(%s)' % (self.__class__.__name__, repr(self.default))
    +
    +
    +class CurrentUserDefault:
    +    def set_context(self, serializer_field):
    +        self.user = serializer_field.context['request'].user
    +
    +    def __call__(self):
    +        return self.user
    +
    +    def __repr__(self):
    +        return '%s()' % self.__class__.__name__
    +
    +
    +class SkipField(Exception):
    +    pass
    +
    +
    +NOT_READ_ONLY_WRITE_ONLY = 'May not set both `read_only` and `write_only`'
    +NOT_READ_ONLY_REQUIRED = 'May not set both `read_only` and `required`'
    +NOT_REQUIRED_DEFAULT = 'May not set both `required` and `default`'
    +USE_READONLYFIELD = 'Field(read_only=True) should be ReadOnlyField'
    +MISSING_ERROR_MESSAGE = (
    +    'ValidationError raised by `{class_name}`, but error key `{key}` does '
    +    'not exist in the `error_messages` dictionary.'
    +)
    +
    +
    +class Field(object):
    +    _creation_counter = 0
    +
    +    default_error_messages = {
    +        'required': _('This field is required.'),
    +        'null': _('This field may not be null.')
    +    }
    +    default_validators = []
    +    default_empty_html = empty
    +    initial = None
    +
    +    def __init__(self, read_only=False, write_only=False,
    +                 required=None, default=empty, initial=empty, source=None,
    +                 label=None, help_text=None, style=None,
    +                 error_messages=None, validators=None, allow_null=False):
    +        self._creation_counter = Field._creation_counter
    +        Field._creation_counter += 1
    +
    +        # If `required` is unset, then use `True` unless a default is provided.
    +        if required is None:
    +            required = default is empty and not read_only
    +
    +        # Some combinations of keyword arguments do not make sense.
    +        assert not (read_only and write_only), NOT_READ_ONLY_WRITE_ONLY
    +        assert not (read_only and required), NOT_READ_ONLY_REQUIRED
    +        assert not (required and default is not empty), NOT_REQUIRED_DEFAULT
    +        assert not (read_only and self.__class__ == Field), USE_READONLYFIELD
    +
    +        self.read_only = read_only
    +        self.write_only = write_only
    +        self.required = required
    +        self.default = default
    +        self.source = source
    +        self.initial = self.initial if (initial is empty) else initial
    +        self.label = label
    +        self.help_text = help_text
    +        self.style = {} if style is None else style
    +        self.allow_null = allow_null
    +
    +        if allow_null and self.default_empty_html is empty:
    +            self.default_empty_html = None
    +
    +        if validators is not None:
    +            self.validators = validators[:]
    +
    +        # These are set up by `.bind()` when the field is added to a serializer.
    +        self.field_name = None
    +        self.parent = None
    +
    +        # Collect default error message from self and parent classes
    +        messages = {}
    +        for cls in reversed(self.__class__.__mro__):
    +            messages.update(getattr(cls, 'default_error_messages', {}))
    +        messages.update(error_messages or {})
    +        self.error_messages = messages
    +
    +    def bind(self, field_name, parent):
    +        """
    +        Initializes the field name and parent for the field instance.
    +        Called when a field is added to the parent serializer instance.
    +        """
    +
    +        # In order to enforce a consistent style, we error if a redundant
    +        # 'source' argument has been used. For example:
    +        # my_field = serializer.CharField(source='my_field')
    +        assert self.source != field_name, (
    +            "It is redundant to specify `source='%s'` on field '%s' in "
    +            "serializer '%s', because it is the same as the field name. "
    +            "Remove the `source` keyword argument." %
    +            (field_name, self.__class__.__name__, parent.__class__.__name__)
    +        )
    +
    +        self.field_name = field_name
    +        self.parent = parent
    +
    +        # `self.label` should default to being based on the field name.
    +        if self.label is None:
    +            self.label = field_name.replace('_', ' ').capitalize()
    +
    +        # self.source should default to being the same as the field name.
    +        if self.source is None:
    +            self.source = field_name
    +
    +        # self.source_attrs is a list of attributes that need to be looked up
    +        # when serializing the instance, or populating the validated data.
    +        if self.source == '*':
    +            self.source_attrs = []
    +        else:
    +            self.source_attrs = self.source.split('.')
    +
    +    # .validators is a lazily loaded property, that gets its default
    +    # value from `get_validators`.
    +    @property
    +    def validators(self):
    +        if not hasattr(self, '_validators'):
    +            self._validators = self.get_validators()
    +        return self._validators
    +
    +    @validators.setter
    +    def validators(self, validators):
    +        self._validators = validators
    +
    +    def get_validators(self):
    +        return self.default_validators[:]
    +
    +    def get_initial(self):
    +        """
    +        Return a value to use when the field is being returned as a primitive
    +        value, without any object instance.
    +        """
    +        return self.initial
    +
    +    def get_value(self, dictionary):
    +        """
    +        Given the *incoming* primitive data, return the value for this field
    +        that should be validated and transformed to a native value.
    +        """
    +        if html.is_html_input(dictionary):
    +            # HTML forms will represent empty fields as '', and cannot
    +            # represent None or False values directly.
    +            if self.field_name not in dictionary:
    +                if getattr(self.root, 'partial', False):
    +                    return empty
    +                return self.default_empty_html
    +            ret = dictionary[self.field_name]
    +            return self.default_empty_html if (ret == '') else ret
    +        return dictionary.get(self.field_name, empty)
    +
    +    def get_attribute(self, instance):
    +        """
    +        Given the *outgoing* object instance, return the primitive value
    +        that should be used for this field.
    +        """
    +        return get_attribute(instance, self.source_attrs)
    +
    +    def get_default(self):
    +        """
    +        Return the default value to use when validating data if no input
    +        is provided for this field.
    +
    +        If a default has not been set for this field then this will simply
    +        return `empty`, indicating that no value should be set in the
    +        validated data for this field.
    +        """
    +        if self.default is empty:
    +            raise SkipField()
    +        if callable(self.default):
    +            if hasattr(self.default, 'set_context'):
    +                self.default.set_context(self)
    +            return self.default()
    +        return self.default
    +
    +    def run_validation(self, data=empty):
    +        """
    +        Validate a simple representation and return the internal value.
    +
    +        The provided data may be `empty` if no representation was included
    +        in the input.
    +
    +        May raise `SkipField` if the field should not be included in the
    +        validated data.
    +        """
    +        if self.read_only:
    +            return self.get_default()
    +
    +        if data is empty:
    +            if getattr(self.root, 'partial', False):
    +                raise SkipField()
    +            if self.required:
    +                self.fail('required')
    +            return self.get_default()
    +
    +        if data is None:
    +            if not self.allow_null:
    +                self.fail('null')
    +            return None
    +
    +        value = self.to_internal_value(data)
    +        self.run_validators(value)
    +        self.validate(value)
    +        return value
     
         def run_validators(self, value):
    -        if value in validators.EMPTY_VALUES:
    -            return
    +        """
    +        Test the given value against all the validators on the field,
    +        and either raise a `ValidationError` or simply return.
    +        """
             errors = []
    -        for v in self.validators:
    +        for validator in self.validators:
    +            if hasattr(validator, 'set_context'):
    +                validator.set_context(self)
    +
                 try:
    -                v(value)
    -            except ValidationError as e:
    -                if hasattr(e, 'code') and e.code in self.error_messages:
    -                    message = self.error_messages[e.code]
    -                    if e.params:
    -                        message = message % e.params
    -                    errors.append(message)
    -                else:
    -                    errors.extend(e.messages)
    +                validator(value)
    +            except ValidationError as exc:
    +                # If the validation error contains a mapping of fields to
    +                # errors then simply raise it immediately rather than
    +                # attempting to accumulate a list of errors.
    +                if isinstance(exc.detail, dict):
    +                    raise
    +                errors.extend(exc.detail)
    +            except DjangoValidationError as exc:
    +                errors.extend(exc.messages)
             if errors:
                 raise ValidationError(errors)
     
    -    def field_to_native(self, obj, field_name):
    -        if self.write_only:
    -            return None
    -        return super(WritableField, self).field_to_native(obj, field_name)
    +    def validate(self, value):
    +        pass
     
    -    def field_from_native(self, data, files, field_name, into):
    +    def to_internal_value(self, data):
             """
    -        Given a dictionary and a field name, updates the dictionary `into`,
    -        with the field and it's deserialized value.
    +        Transform the *incoming* primitive data into a native value.
             """
    -        if self.read_only:
    -            return
    +        raise NotImplementedError('to_internal_value() must be implemented.')
     
    +    def to_representation(self, value):
    +        """
    +        Transform the *outgoing* native value into primitive data.
    +        """
    +        raise NotImplementedError('to_representation() must be implemented.')
    +
    +    def fail(self, key, **kwargs):
    +        """
    +        A helper method that simply raises a validation error.
    +        """
             try:
    -            data = data or {}
    -            if self.use_files:
    -                files = files or {}
    -                try:
    -                    native = files[field_name]
    -                except KeyError:
    -                    native = data[field_name]
    -            else:
    -                native = data[field_name]
    +            msg = self.error_messages[key]
             except KeyError:
    -            if self.default is not None and not self.partial:
    -                # Note: partial updates shouldn't set defaults
    -                native = self.get_default_value()
    -            else:
    -                if self.required:
    -                    raise ValidationError(self.error_messages['required'])
    -                return
    +            class_name = self.__class__.__name__
    +            msg = MISSING_ERROR_MESSAGE.format(class_name=class_name, key=key)
    +            raise AssertionError(msg)
    +        message_string = msg.format(**kwargs)
    +        raise ValidationError(message_string)
     
    -        value = self.from_native(native)
    -        if self.source == '*':
    -            if value:
    -                into.update(value)
    -        else:
    -            self.validate(value)
    -            self.run_validators(value)
    -            into[self.source or field_name] = value
    -
    -    def from_native(self, value):
    +    @property
    +    def root(self):
             """
    -        Reverts a simple representation back to the field's value.
    +        Returns the top-level serializer for this field.
             """
    -        return value
    +        root = self
    +        while root.parent is not None:
    +            root = root.parent
    +        return root
    +
    +    @property
    +    def context(self):
    +        """
    +        Returns the context as passed to the root serializer on initialization.
    +        """
    +        return getattr(self.root, '_context', {})
    +
    +    def __new__(cls, *args, **kwargs):
    +        """
    +        When a field is instantiated, we store the arguments that were used,
    +        so that we can present a helpful representation of the object.
    +        """
    +        instance = super(Field, cls).__new__(cls)
    +        instance._args = args
    +        instance._kwargs = kwargs
    +        return instance
    +
    +    def __deepcopy__(self, memo):
    +        """
    +        When cloning fields we instantiate using the arguments it was
    +        originally created with, rather than copying the complete state.
    +        """
    +        args = copy.deepcopy(self._args)
    +        kwargs = dict(self._kwargs)
    +        # Bit ugly, but we need to special case 'validators' as Django's
    +        # RegexValidator does not support deepcopy.
    +        # We treat validator callables as immutable objects.
    +        # See https://github.com/tomchristie/django-rest-framework/issues/1954
    +        validators = kwargs.pop('validators', None)
    +        kwargs = copy.deepcopy(kwargs)
    +        if validators is not None:
    +            kwargs['validators'] = validators
    +        return self.__class__(*args, **kwargs)
    +
    +    def __repr__(self):
    +        """
    +        Fields are represented using their initial calling arguments.
    +        This allows us to create descriptive representations for serializer
    +        instances that show all the declared fields on the serializer.
    +        """
    +        return representation.field_repr(self)
     
     
    -class ModelField(WritableField):
    -    """
    -    A generic field that can be used against an arbitrary model field.
    -    """
    -    def __init__(self, *args, **kwargs):
    -        try:
    -            self.model_field = kwargs.pop('model_field')
    -        except KeyError:
    -            raise ValueError("ModelField requires 'model_field' kwarg")
    +# Boolean types...
     
    -        self.min_length = kwargs.pop('min_length',
    -                                     getattr(self.model_field, 'min_length', None))
    -        self.max_length = kwargs.pop('max_length',
    -                                     getattr(self.model_field, 'max_length', None))
    -        self.min_value = kwargs.pop('min_value',
    -                                    getattr(self.model_field, 'min_value', None))
    -        self.max_value = kwargs.pop('max_value',
    -                                    getattr(self.model_field, 'max_value', None))
    -
    -        super(ModelField, self).__init__(*args, **kwargs)
    -
    -        if self.min_length is not None:
    -            self.validators.append(validators.MinLengthValidator(self.min_length))
    -        if self.max_length is not None:
    -            self.validators.append(validators.MaxLengthValidator(self.max_length))
    -        if self.min_value is not None:
    -            self.validators.append(validators.MinValueValidator(self.min_value))
    -        if self.max_value is not None:
    -            self.validators.append(validators.MaxValueValidator(self.max_value))
    -
    -    def from_native(self, value):
    -        rel = getattr(self.model_field, "rel", None)
    -        if rel is not None:
    -            return rel.to._meta.get_field(rel.field_name).to_python(value)
    -        else:
    -            return self.model_field.to_python(value)
    -
    -    def field_to_native(self, obj, field_name):
    -        value = self.model_field._get_val_from_obj(obj)
    -        if is_protected_type(value):
    -            return value
    -        return self.model_field.value_to_string(obj)
    -
    -    def attributes(self):
    -        return {
    -            "type": self.model_field.get_internal_type()
    -        }
    -
    -
    -# Typed Fields
    -
    -class BooleanField(WritableField):
    -    type_name = 'BooleanField'
    -    type_label = 'boolean'
    -    form_field_class = forms.BooleanField
    -    widget = widgets.CheckboxInput
    +class BooleanField(Field):
         default_error_messages = {
    -        'invalid': _("'%s' value must be either True or False."),
    +        'invalid': _('`{input}` is not a valid boolean.')
         }
    -    empty = False
    +    default_empty_html = False
    +    initial = False
    +    TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True))
    +    FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False))
     
    -    def field_from_native(self, data, files, field_name, into):
    -        # HTML checkboxes do not explicitly represent unchecked as `False`
    -        # we deal with that here...
    -        if isinstance(data, QueryDict) and self.default is None:
    -            self.default = False
    +    def __init__(self, **kwargs):
    +        assert 'allow_null' not in kwargs, '`allow_null` is not a valid option. Use `NullBooleanField` instead.'
    +        super(BooleanField, self).__init__(**kwargs)
     
    -        return super(BooleanField, self).field_from_native(
    -            data, files, field_name, into
    -        )
    -
    -    def from_native(self, value):
    -        if value in ('true', 't', 'True', '1'):
    +    def to_internal_value(self, data):
    +        if data in self.TRUE_VALUES:
                 return True
    -        if value in ('false', 'f', 'False', '0'):
    +        elif data in self.FALSE_VALUES:
    +            return False
    +        self.fail('invalid', input=data)
    +
    +    def to_representation(self, value):
    +        if value in self.TRUE_VALUES:
    +            return True
    +        elif value in self.FALSE_VALUES:
                 return False
             return bool(value)
     
     
    -class CharField(WritableField):
    -    type_name = 'CharField'
    -    type_label = 'string'
    -    form_field_class = forms.CharField
    -
    -    def __init__(self, max_length=None, min_length=None, allow_none=False, *args, **kwargs):
    -        self.max_length, self.min_length = max_length, min_length
    -        self.allow_none = allow_none
    -        super(CharField, self).__init__(*args, **kwargs)
    -        if min_length is not None:
    -            self.validators.append(validators.MinLengthValidator(min_length))
    -        if max_length is not None:
    -            self.validators.append(validators.MaxLengthValidator(max_length))
    -
    -    def from_native(self, value):
    -        if isinstance(value, six.string_types):
    -            return value
    -
    -        if value is None:
    -            if not self.allow_none:
    -                return ''
    -            else:
    -                # Return None explicitly because smart_text(None) == 'None'. See #1834 for details
    -                return None
    -
    -        return smart_text(value)
    -
    -
    -class URLField(CharField):
    -    type_name = 'URLField'
    -    type_label = 'url'
    +class NullBooleanField(Field):
    +    default_error_messages = {
    +        'invalid': _('`{input}` is not a valid boolean.')
    +    }
    +    initial = None
    +    TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True))
    +    FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False))
    +    NULL_VALUES = set(('n', 'N', 'null', 'Null', 'NULL', '', None))
     
         def __init__(self, **kwargs):
    -        if 'validators' not in kwargs:
    -            kwargs['validators'] = [validators.URLValidator()]
    -        super(URLField, self).__init__(**kwargs)
    +        assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.'
    +        kwargs['allow_null'] = True
    +        super(NullBooleanField, self).__init__(**kwargs)
    +
    +    def to_internal_value(self, data):
    +        if data in self.TRUE_VALUES:
    +            return True
    +        elif data in self.FALSE_VALUES:
    +            return False
    +        elif data in self.NULL_VALUES:
    +            return None
    +        self.fail('invalid', input=data)
    +
    +    def to_representation(self, value):
    +        if value in self.NULL_VALUES:
    +            return None
    +        if value in self.TRUE_VALUES:
    +            return True
    +        elif value in self.FALSE_VALUES:
    +            return False
    +        return bool(value)
     
     
    -class SlugField(CharField):
    -    type_name = 'SlugField'
    -    type_label = 'slug'
    -    form_field_class = forms.SlugField
    +# String types...
     
    +class CharField(Field):
         default_error_messages = {
    -        'invalid': _("Enter a valid 'slug' consisting of letters, numbers,"
    -                     " underscores or hyphens."),
    +        'blank': _('This field may not be blank.'),
    +        'max_length': _('Ensure this field has no more than {max_length} characters.'),
    +        'min_length': _('Ensure this field has no more than {min_length} characters.')
         }
    -    default_validators = [validators.validate_slug]
    +    initial = ''
    +    coerce_blank_to_null = False
    +    default_empty_html = ''
     
    -    def __init__(self, *args, **kwargs):
    -        super(SlugField, self).__init__(*args, **kwargs)
    +    def __init__(self, **kwargs):
    +        self.allow_blank = kwargs.pop('allow_blank', False)
    +        max_length = kwargs.pop('max_length', None)
    +        min_length = kwargs.pop('min_length', None)
    +        super(CharField, self).__init__(**kwargs)
    +        if max_length is not None:
    +            message = self.error_messages['max_length'].format(max_length=max_length)
    +            self.validators.append(MaxLengthValidator(max_length, message=message))
    +        if min_length is not None:
    +            message = self.error_messages['min_length'].format(min_length=min_length)
    +            self.validators.append(MinLengthValidator(min_length, message=message))
     
    +    def run_validation(self, data=empty):
    +        # Test for the empty string here so that it does not get validated,
    +        # and so that subclasses do not need to handle it explicitly
    +        # inside the `to_internal_value()` method.
    +        if data == '':
    +            if not self.allow_blank:
    +                self.fail('blank')
    +            return ''
    +        return super(CharField, self).run_validation(data)
     
    -class ChoiceField(WritableField):
    -    type_name = 'ChoiceField'
    -    type_label = 'choice'
    -    form_field_class = forms.ChoiceField
    -    widget = widgets.Select
    -    default_error_messages = {
    -        'invalid_choice': _('Select a valid choice. %(value)s is not one of '
    -                            'the available choices.'),
    -    }
    +    def to_internal_value(self, data):
    +        return six.text_type(data)
     
    -    def __init__(self, choices=(), blank_display_value=None, *args, **kwargs):
    -        self.empty = kwargs.pop('empty', '')
    -        super(ChoiceField, self).__init__(*args, **kwargs)
    -        self.choices = choices
    -        if not self.required:
    -            if blank_display_value is None:
    -                blank_choice = BLANK_CHOICE_DASH
    -            else:
    -                blank_choice = [('', blank_display_value)]
    -            self.choices = blank_choice + self.choices
    -
    -    def _get_choices(self):
    -        return self._choices
    -
    -    def _set_choices(self, value):
    -        # Setting choices also sets the choices on the widget.
    -        # choices can be any iterable, but we call list() on it because
    -        # it will be consumed more than once.
    -        self._choices = self.widget.choices = list(value)
    -
    -    choices = property(_get_choices, _set_choices)
    -
    -    def metadata(self):
    -        data = super(ChoiceField, self).metadata()
    -        data['choices'] = [{'value': v, 'display_name': n} for v, n in self.choices]
    -        return data
    -
    -    def validate(self, value):
    -        """
    -        Validates that the input is in self.choices.
    -        """
    -        super(ChoiceField, self).validate(value)
    -        if value and not self.valid_value(value):
    -            raise ValidationError(self.error_messages['invalid_choice'] % {'value': value})
    -
    -    def valid_value(self, value):
    -        """
    -        Check to see if the provided value is a valid choice.
    -        """
    -        for k, v in self.choices:
    -            if isinstance(v, (list, tuple)):
    -                # This is an optgroup, so look inside the group for options
    -                for k2, v2 in v:
    -                    if value == smart_text(k2) or value == k2:
    -                        return True
    -            else:
    -                if value == smart_text(k) or value == k:
    -                    return True
    -        return False
    -
    -    def from_native(self, value):
    -        value = super(ChoiceField, self).from_native(value)
    -        if value == self.empty or value in validators.EMPTY_VALUES:
    -            return self.empty
    -        return value
    +    def to_representation(self, value):
    +        return six.text_type(value)
     
     
     class EmailField(CharField):
    -    type_name = 'EmailField'
    -    type_label = 'email'
    -    form_field_class = forms.EmailField
    -
         default_error_messages = {
    -        'invalid': _('Enter a valid email address.'),
    +        'invalid': _('Enter a valid email address.')
         }
    -    default_validators = [validators.validate_email]
     
    -    def from_native(self, value):
    -        ret = super(EmailField, self).from_native(value)
    -        if ret is None:
    -            return None
    -        return ret.strip()
    +    def __init__(self, **kwargs):
    +        super(EmailField, self).__init__(**kwargs)
    +        validator = EmailValidator(message=self.error_messages['invalid'])
    +        self.validators.append(validator)
    +
    +    def to_internal_value(self, data):
    +        return six.text_type(data).strip()
    +
    +    def to_representation(self, value):
    +        return six.text_type(value).strip()
     
     
     class RegexField(CharField):
    -    type_name = 'RegexField'
    -    type_label = 'regex'
    -    form_field_class = forms.RegexField
    -
    -    def __init__(self, regex, max_length=None, min_length=None, *args, **kwargs):
    -        super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
    -        self.regex = regex
    -
    -    def _get_regex(self):
    -        return self._regex
    -
    -    def _set_regex(self, regex):
    -        if isinstance(regex, six.string_types):
    -            regex = re.compile(regex)
    -        self._regex = regex
    -        if hasattr(self, '_regex_validator') and self._regex_validator in self.validators:
    -            self.validators.remove(self._regex_validator)
    -        self._regex_validator = validators.RegexValidator(regex=regex)
    -        self.validators.append(self._regex_validator)
    -
    -    regex = property(_get_regex, _set_regex)
    -
    -
    -class DateField(WritableField):
    -    type_name = 'DateField'
    -    type_label = 'date'
    -    widget = widgets.DateInput
    -    form_field_class = forms.DateField
    -
         default_error_messages = {
    -        'invalid': _("Date has wrong format. Use one of these formats instead: %s"),
    +        'invalid': _('This value does not match the required pattern.')
         }
    -    empty = None
    -    input_formats = api_settings.DATE_INPUT_FORMATS
    -    format = api_settings.DATE_FORMAT
     
    -    def __init__(self, input_formats=None, format=None, *args, **kwargs):
    +    def __init__(self, regex, **kwargs):
    +        super(RegexField, self).__init__(**kwargs)
    +        validator = RegexValidator(regex, message=self.error_messages['invalid'])
    +        self.validators.append(validator)
    +
    +
    +class SlugField(CharField):
    +    default_error_messages = {
    +        'invalid': _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.")
    +    }
    +
    +    def __init__(self, **kwargs):
    +        super(SlugField, self).__init__(**kwargs)
    +        slug_regex = re.compile(r'^[-a-zA-Z0-9_]+$')
    +        validator = RegexValidator(slug_regex, message=self.error_messages['invalid'])
    +        self.validators.append(validator)
    +
    +
    +class URLField(CharField):
    +    default_error_messages = {
    +        'invalid': _("Enter a valid URL.")
    +    }
    +
    +    def __init__(self, **kwargs):
    +        super(URLField, self).__init__(**kwargs)
    +        validator = URLValidator(message=self.error_messages['invalid'])
    +        self.validators.append(validator)
    +
    +
    +# Number types...
    +
    +class IntegerField(Field):
    +    default_error_messages = {
    +        'invalid': _('A valid integer is required.'),
    +        'max_value': _('Ensure this value is less than or equal to {max_value}.'),
    +        'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
    +        'max_string_length': _('String value too large')
    +    }
    +    MAX_STRING_LENGTH = 1000  # Guard against malicious string inputs.
    +
    +    def __init__(self, **kwargs):
    +        max_value = kwargs.pop('max_value', None)
    +        min_value = kwargs.pop('min_value', None)
    +        super(IntegerField, self).__init__(**kwargs)
    +        if max_value is not None:
    +            message = self.error_messages['max_value'].format(max_value=max_value)
    +            self.validators.append(MaxValueValidator(max_value, message=message))
    +        if min_value is not None:
    +            message = self.error_messages['min_value'].format(min_value=min_value)
    +            self.validators.append(MinValueValidator(min_value, message=message))
    +
    +    def to_internal_value(self, data):
    +        if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
    +            self.fail('max_string_length')
    +
    +        try:
    +            data = int(data)
    +        except (ValueError, TypeError):
    +            self.fail('invalid')
    +        return data
    +
    +    def to_representation(self, value):
    +        return int(value)
    +
    +
    +class FloatField(Field):
    +    default_error_messages = {
    +        'invalid': _("A valid number is required."),
    +        'max_value': _('Ensure this value is less than or equal to {max_value}.'),
    +        'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
    +        'max_string_length': _('String value too large')
    +    }
    +    MAX_STRING_LENGTH = 1000  # Guard against malicious string inputs.
    +
    +    def __init__(self, **kwargs):
    +        max_value = kwargs.pop('max_value', None)
    +        min_value = kwargs.pop('min_value', None)
    +        super(FloatField, self).__init__(**kwargs)
    +        if max_value is not None:
    +            message = self.error_messages['max_value'].format(max_value=max_value)
    +            self.validators.append(MaxValueValidator(max_value, message=message))
    +        if min_value is not None:
    +            message = self.error_messages['min_value'].format(min_value=min_value)
    +            self.validators.append(MinValueValidator(min_value, message=message))
    +
    +    def to_internal_value(self, data):
    +        if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
    +            self.fail('max_string_length')
    +
    +        try:
    +            return float(data)
    +        except (TypeError, ValueError):
    +            self.fail('invalid')
    +
    +    def to_representation(self, value):
    +        return float(value)
    +
    +
    +class DecimalField(Field):
    +    default_error_messages = {
    +        'invalid': _('A valid number is required.'),
    +        'max_value': _('Ensure this value is less than or equal to {max_value}.'),
    +        'min_value': _('Ensure this value is greater than or equal to {min_value}.'),
    +        'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'),
    +        'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'),
    +        'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'),
    +        'max_string_length': _('String value too large')
    +    }
    +    MAX_STRING_LENGTH = 1000  # Guard against malicious string inputs.
    +
    +    coerce_to_string = api_settings.COERCE_DECIMAL_TO_STRING
    +
    +    def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, **kwargs):
    +        self.max_digits = max_digits
    +        self.decimal_places = decimal_places
    +        self.coerce_to_string = coerce_to_string if (coerce_to_string is not None) else self.coerce_to_string
    +        super(DecimalField, self).__init__(**kwargs)
    +        if max_value is not None:
    +            message = self.error_messages['max_value'].format(max_value=max_value)
    +            self.validators.append(MaxValueValidator(max_value, message=message))
    +        if min_value is not None:
    +            message = self.error_messages['min_value'].format(min_value=min_value)
    +            self.validators.append(MinValueValidator(min_value, message=message))
    +
    +    def to_internal_value(self, data):
    +        """
    +        Validates that the input is a decimal number. Returns a Decimal
    +        instance. Returns None for empty values. Ensures that there are no more
    +        than max_digits in the number, and no more than decimal_places digits
    +        after the decimal point.
    +        """
    +        data = smart_text(data).strip()
    +        if len(data) > self.MAX_STRING_LENGTH:
    +            self.fail('max_string_length')
    +
    +        try:
    +            value = decimal.Decimal(data)
    +        except decimal.DecimalException:
    +            self.fail('invalid')
    +
    +        # Check for NaN. It is the only value that isn't equal to itself,
    +        # so we can use this to identify NaN values.
    +        if value != value:
    +            self.fail('invalid')
    +
    +        # Check for infinity and negative infinity.
    +        if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')):
    +            self.fail('invalid')
    +
    +        sign, digittuple, exponent = value.as_tuple()
    +        decimals = abs(exponent)
    +        # digittuple doesn't include any leading zeros.
    +        digits = len(digittuple)
    +        if decimals > digits:
    +            # We have leading zeros up to or past the decimal point.  Count
    +            # everything past the decimal point as a digit.  We do not count
    +            # 0 before the decimal point as a digit since that would mean
    +            # we would not allow max_digits = decimal_places.
    +            digits = decimals
    +        whole_digits = digits - decimals
    +
    +        if self.max_digits is not None and digits > self.max_digits:
    +            self.fail('max_digits', max_digits=self.max_digits)
    +        if self.decimal_places is not None and decimals > self.decimal_places:
    +            self.fail('max_decimal_places', max_decimal_places=self.decimal_places)
    +        if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places):
    +            self.fail('max_whole_digits', max_whole_digits=self.max_digits - self.decimal_places)
    +
    +        return value
    +
    +    def to_representation(self, value):
    +        if not isinstance(value, decimal.Decimal):
    +            value = decimal.Decimal(six.text_type(value).strip())
    +
    +        context = decimal.getcontext().copy()
    +        context.prec = self.max_digits
    +        quantized = value.quantize(
    +            decimal.Decimal('.1') ** self.decimal_places,
    +            context=context
    +        )
    +        if not self.coerce_to_string:
    +            return quantized
    +        return '{0:f}'.format(quantized)
    +
    +
    +# Date & time fields...
    +
    +class DateTimeField(Field):
    +    default_error_messages = {
    +        'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}'),
    +        'date': _('Expected a datetime but got a date.'),
    +    }
    +    format = api_settings.DATETIME_FORMAT
    +    input_formats = api_settings.DATETIME_INPUT_FORMATS
    +    default_timezone = timezone.get_default_timezone() if settings.USE_TZ else None
    +
    +    def __init__(self, format=empty, input_formats=None, default_timezone=None, *args, **kwargs):
    +        self.format = format if format is not empty else self.format
             self.input_formats = input_formats if input_formats is not None else self.input_formats
    -        self.format = format if format is not None else self.format
    -        super(DateField, self).__init__(*args, **kwargs)
    +        self.default_timezone = default_timezone if default_timezone is not None else self.default_timezone
    +        super(DateTimeField, self).__init__(*args, **kwargs)
     
    -    def from_native(self, value):
    -        if value in validators.EMPTY_VALUES:
    -            return None
    +    def enforce_timezone(self, value):
    +        """
    +        When `self.default_timezone` is `None`, always return naive datetimes.
    +        When `self.default_timezone` is not `None`, always return aware datetimes.
    +        """
    +        if (self.default_timezone is not None) and not timezone.is_aware(value):
    +            return timezone.make_aware(value, self.default_timezone)
    +        elif (self.default_timezone is None) and timezone.is_aware(value):
    +            return timezone.make_naive(value, timezone.UTC())
    +        return value
    +
    +    def to_internal_value(self, value):
    +        if isinstance(value, datetime.date) and not isinstance(value, datetime.datetime):
    +            self.fail('date')
     
             if isinstance(value, datetime.datetime):
    -            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()
    -                value = timezone.make_naive(value, default_timezone)
    -            return value.date()
    +            return self.enforce_timezone(value)
    +
    +        for format in self.input_formats:
    +            if format.lower() == ISO_8601:
    +                try:
    +                    parsed = parse_datetime(value)
    +                except (ValueError, TypeError):
    +                    pass
    +                else:
    +                    if parsed is not None:
    +                        return self.enforce_timezone(parsed)
    +            else:
    +                try:
    +                    parsed = datetime.datetime.strptime(value, format)
    +                except (ValueError, TypeError):
    +                    pass
    +                else:
    +                    return self.enforce_timezone(parsed)
    +
    +        humanized_format = humanize_datetime.datetime_formats(self.input_formats)
    +        self.fail('invalid', format=humanized_format)
    +
    +    def to_representation(self, value):
    +        if self.format is None:
    +            return value
    +
    +        if self.format.lower() == ISO_8601:
    +            value = value.isoformat()
    +            if value.endswith('+00:00'):
    +                value = value[:-6] + 'Z'
    +            return value
    +        return value.strftime(self.format)
    +
    +
    +class DateField(Field):
    +    default_error_messages = {
    +        'invalid': _('Date has wrong format. Use one of these formats instead: {format}'),
    +        'datetime': _('Expected a date but got a datetime.'),
    +    }
    +    format = api_settings.DATE_FORMAT
    +    input_formats = api_settings.DATE_INPUT_FORMATS
    +
    +    def __init__(self, format=empty, input_formats=None, *args, **kwargs):
    +        self.format = format if format is not empty else self.format
    +        self.input_formats = input_formats if input_formats is not None else self.input_formats
    +        super(DateField, self).__init__(*args, **kwargs)
    +
    +    def to_internal_value(self, value):
    +        if isinstance(value, datetime.datetime):
    +            self.fail('datetime')
    +
             if isinstance(value, datetime.date):
                 return value
     
    @@ -667,113 +844,40 @@ class DateField(WritableField):
                     else:
                         return parsed.date()
     
    -        msg = self.error_messages['invalid'] % readable_date_formats(self.input_formats)
    -        raise ValidationError(msg)
    +        humanized_format = humanize_datetime.date_formats(self.input_formats)
    +        self.fail('invalid', format=humanized_format)
     
    -    def to_native(self, value):
    -        if value is None or self.format is None:
    +    def to_representation(self, value):
    +        if self.format is None:
                 return value
     
    -        if isinstance(value, datetime.datetime):
    -            value = value.date()
    +        # Applying a `DateField` to a datetime value is almost always
    +        # not a sensible thing to do, as it means naively dropping
    +        # any explicit or implicit timezone info.
    +        assert not isinstance(value, datetime.datetime), (
    +            'Expected a `date`, but got a `datetime`. Refusing to coerce, '
    +            'as this may mean losing timezone information. Use a custom '
    +            'read-only field and deal with timezone issues explicitly.'
    +        )
     
             if self.format.lower() == ISO_8601:
                 return value.isoformat()
             return value.strftime(self.format)
     
     
    -class DateTimeField(WritableField):
    -    type_name = 'DateTimeField'
    -    type_label = 'datetime'
    -    widget = widgets.DateTimeInput
    -    form_field_class = forms.DateTimeField
    -
    +class TimeField(Field):
         default_error_messages = {
    -        'invalid': _("Datetime has wrong format. Use one of these formats instead: %s"),
    +        'invalid': _('Time has wrong format. Use one of these formats instead: {format}'),
         }
    -    empty = None
    -    input_formats = api_settings.DATETIME_INPUT_FORMATS
    -    format = api_settings.DATETIME_FORMAT
    -
    -    def __init__(self, input_formats=None, format=None, *args, **kwargs):
    -        self.input_formats = input_formats if input_formats is not None else self.input_formats
    -        self.format = format if format is not None else self.format
    -        super(DateTimeField, self).__init__(*args, **kwargs)
    -
    -    def from_native(self, value):
    -        if value in validators.EMPTY_VALUES:
    -            return None
    -
    -        if isinstance(value, datetime.datetime):
    -            return value
    -        if isinstance(value, datetime.date):
    -            value = datetime.datetime(value.year, value.month, value.day)
    -            if settings.USE_TZ:
    -                # For backwards compatibility, interpret naive datetimes in
    -                # local time. This won't work during DST change, but we can't
    -                # do much about it, so we let the exceptions percolate up the
    -                # call stack.
    -                warnings.warn("DateTimeField received a naive datetime (%s)"
    -                              " while time zone support is active." % value,
    -                              RuntimeWarning)
    -                default_timezone = timezone.get_default_timezone()
    -                value = timezone.make_aware(value, default_timezone)
    -            return value
    -
    -        for format in self.input_formats:
    -            if format.lower() == ISO_8601:
    -                try:
    -                    parsed = parse_datetime(value)
    -                except (ValueError, TypeError):
    -                    pass
    -                else:
    -                    if parsed is not None:
    -                        return parsed
    -            else:
    -                try:
    -                    parsed = datetime.datetime.strptime(value, format)
    -                except (ValueError, TypeError):
    -                    pass
    -                else:
    -                    return parsed
    -
    -        msg = self.error_messages['invalid'] % readable_datetime_formats(self.input_formats)
    -        raise ValidationError(msg)
    -
    -    def to_native(self, value):
    -        if value is None or self.format is None:
    -            return value
    -
    -        if self.format.lower() == ISO_8601:
    -            ret = value.isoformat()
    -            if ret.endswith('+00:00'):
    -                ret = ret[:-6] + 'Z'
    -            return ret
    -        return value.strftime(self.format)
    -
    -
    -class TimeField(WritableField):
    -    type_name = 'TimeField'
    -    type_label = 'time'
    -    widget = widgets.TimeInput
    -    form_field_class = forms.TimeField
    -
    -    default_error_messages = {
    -        'invalid': _("Time has wrong format. Use one of these formats instead: %s"),
    -    }
    -    empty = None
    -    input_formats = api_settings.TIME_INPUT_FORMATS
         format = api_settings.TIME_FORMAT
    +    input_formats = api_settings.TIME_INPUT_FORMATS
     
    -    def __init__(self, input_formats=None, format=None, *args, **kwargs):
    +    def __init__(self, format=empty, input_formats=None, *args, **kwargs):
    +        self.format = format if format is not empty else self.format
             self.input_formats = input_formats if input_formats is not None else self.input_formats
    -        self.format = format if format is not None else self.format
             super(TimeField, self).__init__(*args, **kwargs)
     
    -    def from_native(self, value):
    -        if value in validators.EMPTY_VALUES:
    -            return None
    -
    +    def to_internal_value(self, value):
             if isinstance(value, datetime.time):
                 return value
     
    @@ -794,249 +898,330 @@ class TimeField(WritableField):
                     else:
                         return parsed.time()
     
    -        msg = self.error_messages['invalid'] % readable_time_formats(self.input_formats)
    -        raise ValidationError(msg)
    +        humanized_format = humanize_datetime.time_formats(self.input_formats)
    +        self.fail('invalid', format=humanized_format)
     
    -    def to_native(self, value):
    -        if value is None or self.format is None:
    +    def to_representation(self, value):
    +        if self.format is None:
                 return value
     
    -        if isinstance(value, datetime.datetime):
    -            value = value.time()
    +        # Applying a `TimeField` to a datetime value is almost always
    +        # not a sensible thing to do, as it means naively dropping
    +        # any explicit or implicit timezone info.
    +        assert not isinstance(value, datetime.datetime), (
    +            'Expected a `time`, but got a `datetime`. Refusing to coerce, '
    +            'as this may mean losing timezone information. Use a custom '
    +            'read-only field and deal with timezone issues explicitly.'
    +        )
     
             if self.format.lower() == ISO_8601:
                 return value.isoformat()
             return value.strftime(self.format)
     
     
    -class IntegerField(WritableField):
    -    type_name = 'IntegerField'
    -    type_label = 'integer'
    -    form_field_class = forms.IntegerField
    -    empty = 0
    +# Choice types...
     
    +class ChoiceField(Field):
         default_error_messages = {
    -        'invalid': _('Enter a whole number.'),
    -        'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
    -        'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'),
    +        'invalid_choice': _('`{input}` is not a valid choice.')
         }
     
    -    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
    -        self.max_value, self.min_value = max_value, min_value
    -        super(IntegerField, self).__init__(*args, **kwargs)
    +    def __init__(self, choices, **kwargs):
    +        # Allow either single or paired choices style:
    +        # choices = [1, 2, 3]
    +        # choices = [(1, 'First'), (2, 'Second'), (3, 'Third')]
    +        pairs = [
    +            isinstance(item, (list, tuple)) and len(item) == 2
    +            for item in choices
    +        ]
    +        if all(pairs):
    +            self.choices = OrderedDict([(key, display_value) for key, display_value in choices])
    +        else:
    +            self.choices = OrderedDict([(item, item) for item in choices])
     
    -        if max_value is not None:
    -            self.validators.append(validators.MaxValueValidator(max_value))
    -        if min_value is not None:
    -            self.validators.append(validators.MinValueValidator(min_value))
    +        # Map the string representation of choices to the underlying value.
    +        # Allows us to deal with eg. integer choices while supporting either
    +        # integer or string input, but still get the correct datatype out.
    +        self.choice_strings_to_values = dict([
    +            (six.text_type(key), key) for key in self.choices.keys()
    +        ])
     
    -    def from_native(self, value):
    -        if value in validators.EMPTY_VALUES:
    -            return None
    +        super(ChoiceField, self).__init__(**kwargs)
     
    +    def to_internal_value(self, data):
             try:
    -            value = int(str(value))
    -        except (ValueError, TypeError):
    -            raise ValidationError(self.error_messages['invalid'])
    -        return value
    +            return self.choice_strings_to_values[six.text_type(data)]
    +        except KeyError:
    +            self.fail('invalid_choice', input=data)
    +
    +    def to_representation(self, value):
    +        if value in ('', None):
    +            return value
    +        return self.choice_strings_to_values[six.text_type(value)]
     
     
    -class FloatField(WritableField):
    -    type_name = 'FloatField'
    -    type_label = 'float'
    -    form_field_class = forms.FloatField
    -    empty = 0
    -
    +class MultipleChoiceField(ChoiceField):
         default_error_messages = {
    -        'invalid': _("'%s' value must be a float."),
    +        'invalid_choice': _('`{input}` is not a valid choice.'),
    +        'not_a_list': _('Expected a list of items but got type `{input_type}`.')
         }
    +    default_empty_html = []
     
    -    def from_native(self, value):
    -        if value in validators.EMPTY_VALUES:
    -            return None
    +    def get_value(self, dictionary):
    +        # We override the default field access in order to support
    +        # lists in HTML forms.
    +        if html.is_html_input(dictionary):
    +            return dictionary.getlist(self.field_name)
    +        return dictionary.get(self.field_name, empty)
     
    -        try:
    -            return float(value)
    -        except (TypeError, ValueError):
    -            msg = self.error_messages['invalid'] % value
    -            raise ValidationError(msg)
    +    def to_internal_value(self, data):
    +        if isinstance(data, type('')) or not hasattr(data, '__iter__'):
    +            self.fail('not_a_list', input_type=type(data).__name__)
    +
    +        return set([
    +            super(MultipleChoiceField, self).to_internal_value(item)
    +            for item in data
    +        ])
    +
    +    def to_representation(self, value):
    +        return set([
    +            self.choice_strings_to_values[six.text_type(item)] for item in value
    +        ])
     
     
    -class DecimalField(WritableField):
    -    type_name = 'DecimalField'
    -    type_label = 'decimal'
    -    form_field_class = forms.DecimalField
    -    empty = Decimal('0')
    +# File types...
     
    +class FileField(Field):
         default_error_messages = {
    -        'invalid': _('Enter a number.'),
    -        'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
    -        'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'),
    -        'max_digits': _('Ensure that there are no more than %s digits in total.'),
    -        'max_decimal_places': _('Ensure that there are no more than %s decimal places.'),
    -        'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')
    -    }
    -
    -    def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
    -        self.max_value, self.min_value = max_value, min_value
    -        self.max_digits, self.decimal_places = max_digits, decimal_places
    -        super(DecimalField, self).__init__(*args, **kwargs)
    -
    -        if max_value is not None:
    -            self.validators.append(validators.MaxValueValidator(max_value))
    -        if min_value is not None:
    -            self.validators.append(validators.MinValueValidator(min_value))
    -
    -    def from_native(self, value):
    -        """
    -        Validates that the input is a decimal number. Returns a Decimal
    -        instance. Returns None for empty values. Ensures that there are no more
    -        than max_digits in the number, and no more than decimal_places digits
    -        after the decimal point.
    -        """
    -        if value in validators.EMPTY_VALUES:
    -            return None
    -        value = smart_text(value).strip()
    -        try:
    -            value = Decimal(value)
    -        except DecimalException:
    -            raise ValidationError(self.error_messages['invalid'])
    -        return value
    -
    -    def validate(self, value):
    -        super(DecimalField, self).validate(value)
    -        if value in validators.EMPTY_VALUES:
    -            return
    -        # Check for NaN, Inf and -Inf values. We can't compare directly for NaN,
    -        # since it is never equal to itself. However, NaN is the only value that
    -        # isn't equal to itself, so we can use this to identify NaN
    -        if value != value or value == Decimal("Inf") or value == Decimal("-Inf"):
    -            raise ValidationError(self.error_messages['invalid'])
    -        sign, digittuple, exponent = value.as_tuple()
    -        decimals = abs(exponent)
    -        # digittuple doesn't include any leading zeros.
    -        digits = len(digittuple)
    -        if decimals > digits:
    -            # We have leading zeros up to or past the decimal point.  Count
    -            # everything past the decimal point as a digit.  We do not count
    -            # 0 before the decimal point as a digit since that would mean
    -            # we would not allow max_digits = decimal_places.
    -            digits = decimals
    -        whole_digits = digits - decimals
    -
    -        if self.max_digits is not None and digits > self.max_digits:
    -            raise ValidationError(self.error_messages['max_digits'] % self.max_digits)
    -        if self.decimal_places is not None and decimals > self.decimal_places:
    -            raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places)
    -        if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places):
    -            raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
    -        return value
    -
    -
    -class FileField(WritableField):
    -    use_files = True
    -    type_name = 'FileField'
    -    type_label = 'file upload'
    -    form_field_class = forms.FileField
    -    widget = widgets.FileInput
    -
    -    default_error_messages = {
    -        'invalid': _("No file was submitted. Check the encoding type on the form."),
    -        'missing': _("No file was submitted."),
    +        'required': _("No file was submitted."),
    +        'invalid': _("The submitted data was not a file. Check the encoding type on the form."),
    +        'no_name': _("No filename could be determined."),
             'empty': _("The submitted file is empty."),
    -        'max_length': _('Ensure this filename has at most %(max)d characters (it has %(length)d).'),
    -        'contradiction': _('Please either submit a file or check the clear checkbox, not both.')
    +        'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'),
         }
    +    use_url = api_settings.UPLOADED_FILES_USE_URL
     
         def __init__(self, *args, **kwargs):
             self.max_length = kwargs.pop('max_length', None)
             self.allow_empty_file = kwargs.pop('allow_empty_file', False)
    +        self.use_url = kwargs.pop('use_url', self.use_url)
             super(FileField, self).__init__(*args, **kwargs)
     
    -    def from_native(self, data):
    -        if data in validators.EMPTY_VALUES:
    -            return None
    -
    -        # UploadedFile objects should have name and size attributes.
    +    def to_internal_value(self, data):
             try:
    +            # `UploadedFile` objects should have name and size attributes.
                 file_name = data.name
                 file_size = data.size
             except AttributeError:
    -            raise ValidationError(self.error_messages['invalid'])
    +            self.fail('invalid')
     
    -        if self.max_length is not None and len(file_name) > self.max_length:
    -            error_values = {'max': self.max_length, 'length': len(file_name)}
    -            raise ValidationError(self.error_messages['max_length'] % error_values)
             if not file_name:
    -            raise ValidationError(self.error_messages['invalid'])
    +            self.fail('no_name')
             if not self.allow_empty_file and not file_size:
    -            raise ValidationError(self.error_messages['empty'])
    +            self.fail('empty')
    +        if self.max_length and len(file_name) > self.max_length:
    +            self.fail('max_length', max_length=self.max_length, length=len(file_name))
     
             return data
     
    -    def to_native(self, value):
    +    def to_representation(self, value):
    +        if self.use_url:
    +            if not value:
    +                return None
    +            url = value.url
    +            request = self.context.get('request', None)
    +            if request is not None:
    +                return request.build_absolute_uri(url)
    +            return url
             return value.name
     
     
     class ImageField(FileField):
    -    use_files = True
    -    type_name = 'ImageField'
    -    type_label = 'image upload'
    -    form_field_class = forms.ImageField
    -
         default_error_messages = {
    -        'invalid_image': _("Upload a valid image. The file you uploaded was "
    -                           "either not an image or a corrupted image."),
    +        'invalid_image': _(
    +            'Upload a valid image. The file you uploaded was either not an '
    +            'image or a corrupted image.'
    +        ),
         }
     
    -    def from_native(self, data):
    +    def __init__(self, *args, **kwargs):
    +        self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField)
    +        super(ImageField, self).__init__(*args, **kwargs)
    +
    +    def to_internal_value(self, data):
    +        # Image validation is a bit grungy, so we'll just outright
    +        # defer to Django's implementation so we don't need to
    +        # consider it, or treat PIL as a test dependency.
    +        file_object = super(ImageField, self).to_internal_value(data)
    +        django_field = self._DjangoImageField()
    +        django_field.error_messages = self.error_messages
    +        django_field.to_python(file_object)
    +        return file_object
    +
    +
    +# Composite field types...
    +
    +class ListField(Field):
    +    child = None
    +    initial = []
    +    default_error_messages = {
    +        'not_a_list': _('Expected a list of items but got type `{input_type}`')
    +    }
    +
    +    def __init__(self, *args, **kwargs):
    +        self.child = kwargs.pop('child', copy.deepcopy(self.child))
    +        assert self.child is not None, '`child` is a required argument.'
    +        assert not inspect.isclass(self.child), '`child` has not been instantiated.'
    +        super(ListField, self).__init__(*args, **kwargs)
    +        self.child.bind(field_name='', parent=self)
    +
    +    def get_value(self, dictionary):
    +        # We override the default field access in order to support
    +        # lists in HTML forms.
    +        if html.is_html_input(dictionary):
    +            return html.parse_html_list(dictionary, prefix=self.field_name)
    +        return dictionary.get(self.field_name, empty)
    +
    +    def to_internal_value(self, data):
             """
    -        Checks that the file-upload field data contains a valid image (GIF, JPG,
    -        PNG, possibly others -- whatever the Python Imaging Library supports).
    +        List of dicts of native values <- List of dicts of primitive datatypes.
             """
    -        f = super(ImageField, self).from_native(data)
    -        if f is None:
    -            return None
    +        if html.is_html_input(data):
    +            data = html.parse_html_list(data)
    +        if isinstance(data, type('')) or not hasattr(data, '__iter__'):
    +            self.fail('not_a_list', input_type=type(data).__name__)
    +        return [self.child.run_validation(item) for item in data]
     
    -        from rest_framework.compat import Image
    -        assert Image is not None, 'Either Pillow or PIL must be installed for ImageField support.'
    +    def to_representation(self, data):
    +        """
    +        List of object instances -> List of dicts of primitive datatypes.
    +        """
    +        return [self.child.to_representation(item) for item in data]
     
    -        # We need to get a file object for PIL. We might have a path or we might
    -        # have to read the data into memory.
    -        if hasattr(data, 'temporary_file_path'):
    -            file = data.temporary_file_path()
    -        else:
    -            if hasattr(data, 'read'):
    -                file = BytesIO(data.read())
    -            else:
    -                file = BytesIO(data['content'])
     
    -        try:
    -            # load() could spot a truncated JPEG, but it loads the entire
    -            # image in memory, which is a DoS vector. See #3848 and #18520.
    -            # verify() must be called immediately after the constructor.
    -            Image.open(file).verify()
    -        except ImportError:
    -            # Under PyPy, it is possible to import PIL. However, the underlying
    -            # _imaging C module isn't available, so an ImportError will be
    -            # raised. Catch and re-raise.
    -            raise
    -        except Exception:  # Python Imaging Library doesn't recognize it as an image
    -            raise ValidationError(self.error_messages['invalid_image'])
    -        if hasattr(f, 'seek') and callable(f.seek):
    -            f.seek(0)
    -        return f
    +# Miscellaneous field types...
    +
    +class ReadOnlyField(Field):
    +    """
    +    A read-only field that simply returns the field value.
    +
    +    If the field is a method with no parameters, the method will be called
    +    and it's return value used as the representation.
    +
    +    For example, the following would call `get_expiry_date()` on the object:
    +
    +    class ExampleSerializer(self):
    +        expiry_date = ReadOnlyField(source='get_expiry_date')
    +    """
    +
    +    def __init__(self, **kwargs):
    +        kwargs['read_only'] = True
    +        super(ReadOnlyField, self).__init__(**kwargs)
    +
    +    def to_representation(self, value):
    +        return value
    +
    +
    +class HiddenField(Field):
    +    """
    +    A hidden field does not take input from the user, or present any output,
    +    but it does populate a field in `validated_data`, based on its default
    +    value. This is particularly useful when we have a `unique_for_date`
    +    constraint on a pair of fields, as we need some way to include the date in
    +    the validated data.
    +    """
    +    def __init__(self, **kwargs):
    +        assert 'default' in kwargs, 'default is a required argument.'
    +        kwargs['write_only'] = True
    +        super(HiddenField, self).__init__(**kwargs)
    +
    +    def get_value(self, dictionary):
    +        # We always use the default value for `HiddenField`.
    +        # User input is never provided or accepted.
    +        return empty
    +
    +    def to_internal_value(self, data):
    +        return data
     
     
     class SerializerMethodField(Field):
         """
    -    A field that gets its value by calling a method on the serializer it's attached to.
    +    A read-only field that get its representation from calling a method on the
    +    parent serializer class. The method called will be of the form
    +    "get_{field_name}", and should take a single argument, which is the
    +    object being serialized.
    +
    +    For example:
    +
    +    class ExampleSerializer(self):
    +        extra_info = SerializerMethodField()
    +
    +        def get_extra_info(self, obj):
    +            return ...  # Calculate some data to return.
         """
    -
    -    def __init__(self, method_name, *args, **kwargs):
    +    def __init__(self, method_name=None, **kwargs):
             self.method_name = method_name
    -        super(SerializerMethodField, self).__init__(*args, **kwargs)
    +        kwargs['source'] = '*'
    +        kwargs['read_only'] = True
    +        super(SerializerMethodField, self).__init__(**kwargs)
     
    -    def field_to_native(self, obj, field_name):
    -        value = getattr(self.parent, self.method_name)(obj)
    -        return self.to_native(value)
    +    def bind(self, field_name, parent):
    +        # In order to enforce a consistent style, we error if a redundant
    +        # 'method_name' argument has been used. For example:
    +        # my_field = serializer.CharField(source='my_field')
    +        default_method_name = 'get_{field_name}'.format(field_name=field_name)
    +        assert self.method_name != default_method_name, (
    +            "It is redundant to specify `%s` on SerializerMethodField '%s' in "
    +            "serializer '%s', because it is the same as the default method name. "
    +            "Remove the `method_name` argument." %
    +            (self.method_name, field_name, parent.__class__.__name__)
    +        )
    +
    +        # The method name should default to `get_{field_name}`.
    +        if self.method_name is None:
    +            self.method_name = default_method_name
    +
    +        super(SerializerMethodField, self).bind(field_name, parent)
    +
    +    def to_representation(self, value):
    +        method = getattr(self.parent, self.method_name)
    +        return method(value)
    +
    +
    +class ModelField(Field):
    +    """
    +    A generic field that can be used against an arbitrary model field.
    +
    +    This is used by `ModelSerializer` when dealing with custom model fields,
    +    that do not have a serializer field to be mapped to.
    +    """
    +    default_error_messages = {
    +        'max_length': _('Ensure this field has no more than {max_length} characters.'),
    +    }
    +
    +    def __init__(self, model_field, **kwargs):
    +        self.model_field = model_field
    +        # The `max_length` option is supported by Django's base `Field` class,
    +        # so we'd better support it here.
    +        max_length = kwargs.pop('max_length', None)
    +        super(ModelField, self).__init__(**kwargs)
    +        if max_length is not None:
    +            message = self.error_messages['max_length'].format(max_length=max_length)
    +            self.validators.append(MaxLengthValidator(max_length, message=message))
    +
    +    def to_internal_value(self, data):
    +        rel = getattr(self.model_field, 'rel', None)
    +        if rel is not None:
    +            return rel.to._meta.get_field(rel.field_name).to_python(data)
    +        return self.model_field.to_python(data)
    +
    +    def get_attribute(self, obj):
    +        # We pass the object instance onto `to_representation`,
    +        # not just the field attribute.
    +        return obj
    +
    +    def to_representation(self, obj):
    +        value = self.model_field._get_val_from_obj(obj)
    +        if is_protected_type(value):
    +            return value
    +        return self.model_field.value_to_string(obj)
    diff --git a/rest_framework/filters.py b/rest_framework/filters.py
    index c580f9351..d188a2d1e 100644
    --- a/rest_framework/filters.py
    +++ b/rest_framework/filters.py
    @@ -3,6 +3,7 @@ Provides generic filtering backends that can be used to filter the results
     returned by list views.
     """
     from __future__ import unicode_literals
    +
     from django.core.exceptions import ImproperlyConfigured
     from django.db import models
     from django.utils import six
    @@ -64,7 +65,7 @@ class DjangoFilterBackend(BaseFilterBackend):
             filter_class = self.get_filter_class(view, queryset)
     
             if filter_class:
    -            return filter_class(request.QUERY_PARAMS, queryset=queryset).qs
    +            return filter_class(request.query_params, queryset=queryset).qs
     
             return queryset
     
    @@ -78,7 +79,7 @@ class SearchFilter(BaseFilterBackend):
             Search terms are set by a ?search=... query parameter,
             and may be comma and/or whitespace delimited.
             """
    -        params = request.QUERY_PARAMS.get(self.search_param, '')
    +        params = request.query_params.get(self.search_param, '')
             return params.replace(',', ' ').split()
     
         def construct_search(self, field_name):
    @@ -97,7 +98,7 @@ class SearchFilter(BaseFilterBackend):
             if not search_fields:
                 return queryset
     
    -        orm_lookups = [self.construct_search(str(search_field))
    +        orm_lookups = [self.construct_search(six.text_type(search_field))
                            for search_field in search_fields]
     
             for search_term in self.get_search_terms(request):
    @@ -121,7 +122,7 @@ class OrderingFilter(BaseFilterBackend):
             the `ordering_param` value on the OrderingFilter or by
             specifying an `ORDERING_PARAM` value in the API settings.
             """
    -        params = request.QUERY_PARAMS.get(self.ordering_param)
    +        params = request.query_params.get(self.ordering_param)
             if params:
                 return [param.strip() for param in params.split(',')]
     
    @@ -147,7 +148,7 @@ class OrderingFilter(BaseFilterBackend):
                     if not getattr(field, 'write_only', False)
                 ]
             elif valid_fields == '__all__':
    -            # View explictly allows filtering on any model field
    +            # View explicitly allows filtering on any model field
                 valid_fields = [field.name for field in queryset.model._meta.fields]
                 valid_fields += queryset.query.aggregates.keys()
     
    diff --git a/rest_framework/generics.py b/rest_framework/generics.py
    index a62da00b3..3d6cf1684 100644
    --- a/rest_framework/generics.py
    +++ b/rest_framework/generics.py
    @@ -3,15 +3,14 @@ Generic views that provide commonly needed behaviour.
     """
     from __future__ import unicode_literals
     
    -from django.core.exceptions import ImproperlyConfigured, PermissionDenied
     from django.core.paginator import Paginator, InvalidPage
    +from django.db.models.query import QuerySet
     from django.http import Http404
     from django.shortcuts import get_object_or_404 as _get_object_or_404
    +from django.utils import six
     from django.utils.translation import ugettext as _
    -from rest_framework import views, mixins, exceptions
    -from rest_framework.request import clone_request
    +from rest_framework import views, mixins
     from rest_framework.settings import api_settings
    -import warnings
     
     
     def strict_positive_int(integer_string, cutoff=None):
    @@ -28,7 +27,7 @@ def strict_positive_int(integer_string, cutoff=None):
     
     def get_object_or_404(queryset, *filter_args, **filter_kwargs):
         """
    -    Same as Django's standard shortcut, but make sure to raise 404
    +    Same as Django's standard shortcut, but make sure to also raise 404
         if the filter_kwargs don't match the required types.
         """
         try:
    @@ -51,11 +50,6 @@ class GenericAPIView(views.APIView):
         queryset = None
         serializer_class = None
     
    -    # This shortcut may be used instead of setting either or both
    -    # of the `queryset`/`serializer_class` attributes, although using
    -    # the explicit style is generally preferred.
    -    model = None
    -
         # If you want to use object lookups other than pk, set this attribute.
         # For more complex lookup requirements override `get_object()`.
         lookup_field = 'pk'
    @@ -71,20 +65,10 @@ class GenericAPIView(views.APIView):
         # The filter backend classes to use for queryset filtering
         filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
     
    -    # The following attributes may be subject to change,
    +    # The following attribute may be subject to change,
         # and should be considered private API.
    -    model_serializer_class = api_settings.DEFAULT_MODEL_SERIALIZER_CLASS
         paginator_class = Paginator
     
    -    ######################################
    -    # These are pending deprecation...
    -
    -    pk_url_kwarg = 'pk'
    -    slug_url_kwarg = 'slug'
    -    slug_field = 'slug'
    -    allow_empty = True
    -    filter_backend = api_settings.FILTER_BACKEND
    -
         def get_serializer_context(self):
             """
             Extra context provided to the serializer class.
    @@ -95,18 +79,16 @@ class GenericAPIView(views.APIView):
                 'view': self
             }
     
    -    def get_serializer(self, instance=None, data=None, files=None, many=False,
    -                       partial=False, allow_add_remove=False):
    +    def get_serializer(self, instance=None, data=None, many=False, partial=False):
             """
             Return the serializer instance that should be used for validating and
             deserializing input, and for serializing output.
             """
             serializer_class = self.get_serializer_class()
             context = self.get_serializer_context()
    -        return serializer_class(instance, data=data, files=files,
    -                                many=many, partial=partial,
    -                                allow_add_remove=allow_add_remove,
    -                                context=context)
    +        return serializer_class(
    +            instance, data=data, many=many, partial=partial, context=context
    +        )
     
         def get_pagination_serializer(self, page):
             """
    @@ -120,39 +102,18 @@ class GenericAPIView(views.APIView):
             context = self.get_serializer_context()
             return pagination_serializer_class(instance=page, context=context)
     
    -    def paginate_queryset(self, queryset, page_size=None):
    +    def paginate_queryset(self, queryset):
             """
             Paginate a queryset if required, either returning a page object,
             or `None` if pagination is not configured for this view.
             """
    -        deprecated_style = False
    -        if page_size is not None:
    -            warnings.warn('The `page_size` parameter to `paginate_queryset()` '
    -                          'is deprecated. '
    -                          'Note that the return style of this method is also '
    -                          'changed, and will simply return a page object '
    -                          'when called without a `page_size` argument.',
    -                          DeprecationWarning, stacklevel=2)
    -            deprecated_style = True
    -        else:
    -            # Determine the required page size.
    -            # If pagination is not configured, simply return None.
    -            page_size = self.get_paginate_by()
    -            if not page_size:
    -                return None
    +        page_size = self.get_paginate_by()
    +        if not page_size:
    +            return None
     
    -        if not self.allow_empty:
    -            warnings.warn(
    -                'The `allow_empty` parameter is deprecated. '
    -                'To use `allow_empty=False` style behavior, You should override '
    -                '`get_queryset()` and explicitly raise a 404 on empty querysets.',
    -                DeprecationWarning, stacklevel=2
    -            )
    -
    -        paginator = self.paginator_class(queryset, page_size,
    -                                         allow_empty_first_page=self.allow_empty)
    +        paginator = self.paginator_class(queryset, page_size)
             page_kwarg = self.kwargs.get(self.page_kwarg)
    -        page_query_param = self.request.QUERY_PARAMS.get(self.page_kwarg)
    +        page_query_param = self.request.query_params.get(self.page_kwarg)
             page = page_kwarg or page_query_param or 1
             try:
                 page_number = paginator.validate_number(page)
    @@ -167,11 +128,9 @@ class GenericAPIView(views.APIView):
                 error_format = _('Invalid page (%(page_number)s): %(message)s')
                 raise Http404(error_format % {
                     'page_number': page_number,
    -                'message': str(exc)
    +                'message': six.text_type(exc)
                 })
     
    -        if deprecated_style:
    -            return (paginator, page, page.object_list, page.has_other_pages())
             return page
     
         def filter_queryset(self, queryset):
    @@ -191,29 +150,12 @@ class GenericAPIView(views.APIView):
             """
             Returns the list of filter backends that this view requires.
             """
    -        if self.filter_backends is None:
    -            filter_backends = []
    -        else:
    -            # Note that we are returning a *copy* of the class attribute,
    -            # so that it is safe for the view to mutate it if needed.
    -            filter_backends = list(self.filter_backends)
    -
    -        if not filter_backends and self.filter_backend:
    -            warnings.warn(
    -                'The `filter_backend` attribute and `FILTER_BACKEND` setting '
    -                'are deprecated in favor of a `filter_backends` '
    -                'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take '
    -                'a *list* of filter backend classes.',
    -                DeprecationWarning, stacklevel=2
    -            )
    -            filter_backends = [self.filter_backend]
    -
    -        return filter_backends
    +        return list(self.filter_backends)
     
         # The following methods provide default implementations
         # that you may want to override for more complex cases.
     
    -    def get_paginate_by(self, queryset=None):
    +    def get_paginate_by(self):
             """
             Return the size of pages to use with pagination.
     
    @@ -222,15 +164,10 @@ class GenericAPIView(views.APIView):
     
             Otherwise defaults to using `self.paginate_by`.
             """
    -        if queryset is not None:
    -            warnings.warn('The `queryset` parameter to `get_paginate_by()` '
    -                          'is deprecated.',
    -                          DeprecationWarning, stacklevel=2)
    -
             if self.paginate_by_param:
                 try:
                     return strict_positive_int(
    -                    self.request.QUERY_PARAMS[self.paginate_by_param],
    +                    self.request.query_params[self.paginate_by_param],
                         cutoff=self.max_paginate_by
                     )
                 except (KeyError, ValueError):
    @@ -248,26 +185,13 @@ class GenericAPIView(views.APIView):
     
             (Eg. admins get full serialization, others get basic serialization)
             """
    -        serializer_class = self.serializer_class
    -        if serializer_class is not None:
    -            return serializer_class
    -
    -        warnings.warn(
    -            'The `.model` attribute on view classes is now deprecated in favor '
    -            'of the more explicit `serializer_class` and `queryset` attributes.',
    -            DeprecationWarning, stacklevel=2
    +        assert self.serializer_class is not None, (
    +            "'%s' should either include a `serializer_class` attribute, "
    +            "or override the `get_serializer_class()` method."
    +            % self.__class__.__name__
             )
     
    -        assert self.model is not None, \
    -            "'%s' should either include a 'serializer_class' attribute, " \
    -            "or use the 'model' attribute as a shortcut for " \
    -            "automatically generating a serializer class." \
    -            % self.__class__.__name__
    -
    -        class DefaultSerializer(self.model_serializer_class):
    -            class Meta:
    -                model = self.model
    -        return DefaultSerializer
    +        return self.serializer_class
     
         def get_queryset(self):
             """
    @@ -284,21 +208,19 @@ class GenericAPIView(views.APIView):
     
             (Eg. return a list of items that is specific to the user)
             """
    -        if self.queryset is not None:
    -            return self.queryset._clone()
    +        assert self.queryset is not None, (
    +            "'%s' should either include a `queryset` attribute, "
    +            "or override the `get_queryset()` method."
    +            % self.__class__.__name__
    +        )
     
    -        if self.model is not None:
    -            warnings.warn(
    -                'The `.model` attribute on view classes is now deprecated in favor '
    -                'of the more explicit `serializer_class` and `queryset` attributes.',
    -                DeprecationWarning, stacklevel=2
    -            )
    -            return self.model._default_manager.all()
    +        queryset = self.queryset
    +        if isinstance(queryset, QuerySet):
    +            # Ensure queryset is re-evaluated on each request.
    +            queryset = queryset.all()
    +        return queryset
     
    -        error_format = "'%s' must define 'queryset' or 'model'"
    -        raise ImproperlyConfigured(error_format % self.__class__.__name__)
    -
    -    def get_object(self, queryset=None):
    +    def get_object(self):
             """
             Returns the object the view is displaying.
     
    @@ -306,43 +228,19 @@ class GenericAPIView(views.APIView):
             queryset lookups.  Eg if objects are referenced using multiple
             keyword arguments in the url conf.
             """
    -        # Determine the base queryset to use.
    -        if queryset is None:
    -            queryset = self.filter_queryset(self.get_queryset())
    -        else:
    -            pass  # Deprecation warning
    +        queryset = self.filter_queryset(self.get_queryset())
     
             # Perform the lookup filtering.
    -        # Note that `pk` and `slug` are deprecated styles of lookup filtering.
             lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
    -        lookup = self.kwargs.get(lookup_url_kwarg, None)
    -        pk = self.kwargs.get(self.pk_url_kwarg, None)
    -        slug = self.kwargs.get(self.slug_url_kwarg, None)
     
    -        if lookup is not None:
    -            filter_kwargs = {self.lookup_field: lookup}
    -        elif pk is not None and self.lookup_field == 'pk':
    -            warnings.warn(
    -                'The `pk_url_kwarg` attribute is deprecated. '
    -                'Use the `lookup_field` attribute instead',
    -                DeprecationWarning
    -            )
    -            filter_kwargs = {'pk': pk}
    -        elif slug is not None and self.lookup_field == 'pk':
    -            warnings.warn(
    -                'The `slug_url_kwarg` attribute is deprecated. '
    -                'Use the `lookup_field` attribute instead',
    -                DeprecationWarning
    -            )
    -            filter_kwargs = {self.slug_field: slug}
    -        else:
    -            raise ImproperlyConfigured(
    -                'Expected view %s to be called with a URL keyword argument '
    -                'named "%s". Fix your URL conf, or set the `.lookup_field` '
    -                'attribute on the view correctly.' %
    -                (self.__class__.__name__, self.lookup_field)
    -            )
    +        assert lookup_url_kwarg in self.kwargs, (
    +            'Expected view %s to be called with a URL keyword argument '
    +            'named "%s". Fix your URL conf, or set the `.lookup_field` '
    +            'attribute on the view correctly.' %
    +            (self.__class__.__name__, lookup_url_kwarg)
    +        )
     
    +        filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
             obj = get_object_or_404(queryset, **filter_kwargs)
     
             # May raise a permission denied
    @@ -350,84 +248,6 @@ class GenericAPIView(views.APIView):
     
             return obj
     
    -    # The following are placeholder methods,
    -    # and are intended to be overridden.
    -    #
    -    # The are not called by GenericAPIView directly,
    -    # but are used by the mixin methods.
    -
    -    def pre_save(self, obj):
    -        """
    -        Placeholder method for calling before saving an object.
    -
    -        May be used to set attributes on the object that are implicit
    -        in either the request, or the url.
    -        """
    -        pass
    -
    -    def post_save(self, obj, created=False):
    -        """
    -        Placeholder method for calling after saving an object.
    -        """
    -        pass
    -
    -    def pre_delete(self, obj):
    -        """
    -        Placeholder method for calling before deleting an object.
    -        """
    -        pass
    -
    -    def post_delete(self, obj):
    -        """
    -        Placeholder method for calling after deleting an object.
    -        """
    -        pass
    -
    -    def metadata(self, request):
    -        """
    -        Return a dictionary of metadata about the view.
    -        Used to return responses for OPTIONS requests.
    -
    -        We override the default behavior, and add some extra information
    -        about the required request body for POST and PUT operations.
    -        """
    -        ret = super(GenericAPIView, self).metadata(request)
    -
    -        actions = {}
    -        for method in ('PUT', 'POST'):
    -            if method not in self.allowed_methods:
    -                continue
    -
    -            original_request = self.request
    -            self.request = clone_request(request, method)
    -            try:
    -                # Test global permissions
    -                self.check_permissions(self.request)
    -                # Test object permissions
    -                if method == 'PUT':
    -                    try:
    -                        self.get_object()
    -                    except Http404:
    -                        # Http404 should be acceptable and the serializer
    -                        # metadata should be populated. Except this so the
    -                        # outer "else" clause of the try-except-else block
    -                        # will be executed.
    -                        pass
    -            except (exceptions.APIException, PermissionDenied):
    -                pass
    -            else:
    -                # If user has appropriate permissions for the view, include
    -                # appropriate metadata about the fields that should be supplied.
    -                serializer = self.get_serializer()
    -                actions[method] = serializer.metadata()
    -            finally:
    -                self.request = original_request
    -
    -        if actions:
    -            ret['actions'] = actions
    -
    -        return ret
    -
     
     # Concrete view classes that provide method handlers
     # by composing the mixin classes with the base view.
    @@ -543,25 +363,3 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
     
         def delete(self, request, *args, **kwargs):
             return self.destroy(request, *args, **kwargs)
    -
    -
    -# Deprecated classes
    -
    -class MultipleObjectAPIView(GenericAPIView):
    -    def __init__(self, *args, **kwargs):
    -        warnings.warn(
    -            'Subclassing `MultipleObjectAPIView` is deprecated. '
    -            'You should simply subclass `GenericAPIView` instead.',
    -            DeprecationWarning, stacklevel=2
    -        )
    -        super(MultipleObjectAPIView, self).__init__(*args, **kwargs)
    -
    -
    -class SingleObjectAPIView(GenericAPIView):
    -    def __init__(self, *args, **kwargs):
    -        warnings.warn(
    -            'Subclassing `SingleObjectAPIView` is deprecated. '
    -            'You should simply subclass `GenericAPIView` instead.',
    -            DeprecationWarning, stacklevel=2
    -        )
    -        super(SingleObjectAPIView, self).__init__(*args, **kwargs)
    diff --git a/rest_framework/metadata.py b/rest_framework/metadata.py
    new file mode 100644
    index 000000000..de829d003
    --- /dev/null
    +++ b/rest_framework/metadata.py
    @@ -0,0 +1,131 @@
    +"""
    +The metadata API is used to allow cusomization of how `OPTIONS` requests
    +are handled. We currently provide a single default implementation that returns
    +some fairly ad-hoc information about the view.
    +
    +Future implementations might use JSON schema or other definations in order
    +to return this information in a more standardized way.
    +"""
    +from __future__ import unicode_literals
    +
    +from django.core.exceptions import PermissionDenied
    +from django.http import Http404
    +from rest_framework import exceptions, serializers
    +from rest_framework.compat import force_text, OrderedDict
    +from rest_framework.request import clone_request
    +from rest_framework.utils.field_mapping import ClassLookupDict
    +
    +
    +class BaseMetadata(object):
    +    def determine_metadata(self, request, view):
    +        """
    +        Return a dictionary of metadata about the view.
    +        Used to return responses for OPTIONS requests.
    +        """
    +        raise NotImplementedError(".determine_metadata() must be overridden.")
    +
    +
    +class SimpleMetadata(BaseMetadata):
    +    """
    +    This is the default metadata implementation.
    +    It returns an ad-hoc set of information about the view.
    +    There are not any formalized standards for `OPTIONS` responses
    +    for us to base this on.
    +    """
    +    label_lookup = ClassLookupDict({
    +        serializers.Field: 'field',
    +        serializers.BooleanField: 'boolean',
    +        serializers.CharField: 'string',
    +        serializers.URLField: 'url',
    +        serializers.EmailField: 'email',
    +        serializers.RegexField: 'regex',
    +        serializers.SlugField: 'slug',
    +        serializers.IntegerField: 'integer',
    +        serializers.FloatField: 'float',
    +        serializers.DecimalField: 'decimal',
    +        serializers.DateField: 'date',
    +        serializers.DateTimeField: 'datetime',
    +        serializers.TimeField: 'time',
    +        serializers.ChoiceField: 'choice',
    +        serializers.MultipleChoiceField: 'multiple choice',
    +        serializers.FileField: 'file upload',
    +        serializers.ImageField: 'image upload',
    +    })
    +
    +    def determine_metadata(self, request, view):
    +        metadata = OrderedDict()
    +        metadata['name'] = view.get_view_name()
    +        metadata['description'] = view.get_view_description()
    +        metadata['renders'] = [renderer.media_type for renderer in view.renderer_classes]
    +        metadata['parses'] = [parser.media_type for parser in view.parser_classes]
    +        if hasattr(view, 'get_serializer'):
    +            actions = self.determine_actions(request, view)
    +            if actions:
    +                metadata['actions'] = actions
    +        return metadata
    +
    +    def determine_actions(self, request, view):
    +        """
    +        For generic class based views we return information about
    +        the fields that are accepted for 'PUT' and 'POST' methods.
    +        """
    +        actions = {}
    +        for method in set(['PUT', 'POST']) & set(view.allowed_methods):
    +            view.request = clone_request(request, method)
    +            try:
    +                # Test global permissions
    +                if hasattr(view, 'check_permissions'):
    +                    view.check_permissions(view.request)
    +                # Test object permissions
    +                if method == 'PUT' and hasattr(view, 'get_object'):
    +                    view.get_object()
    +            except (exceptions.APIException, PermissionDenied, Http404):
    +                pass
    +            else:
    +                # If user has appropriate permissions for the view, include
    +                # appropriate metadata about the fields that should be supplied.
    +                serializer = view.get_serializer()
    +                actions[method] = self.get_serializer_info(serializer)
    +            finally:
    +                view.request = request
    +
    +        return actions
    +
    +    def get_serializer_info(self, serializer):
    +        """
    +        Given an instance of a serializer, return a dictionary of metadata
    +        about its fields.
    +        """
    +        if hasattr(serializer, 'child'):
    +            # If this is a `ListSerializer` then we want to examine the
    +            # underlying child serializer instance instead.
    +            serializer = serializer.child
    +        return OrderedDict([
    +            (field_name, self.get_field_info(field))
    +            for field_name, field in serializer.fields.items()
    +        ])
    +
    +    def get_field_info(self, field):
    +        """
    +        Given an instance of a serializer field, return a dictionary
    +        of metadata about it.
    +        """
    +        field_info = OrderedDict()
    +        field_info['type'] = self.label_lookup[field]
    +        field_info['required'] = getattr(field, 'required', False)
    +
    +        for attr in ['read_only', 'label', 'help_text', 'min_length', 'max_length']:
    +            value = getattr(field, attr, None)
    +            if value is not None and value != '':
    +                field_info[attr] = force_text(value, strings_only=True)
    +
    +        if hasattr(field, 'choices'):
    +            field_info['choices'] = [
    +                {
    +                    'value': choice_value,
    +                    'display_name': force_text(choice_name, strings_only=True)
    +                }
    +                for choice_value, choice_name in field.choices.items()
    +            ]
    +
    +        return field_info
    diff --git a/rest_framework/mixins.py b/rest_framework/mixins.py
    index 2cc87eef1..2074a1072 100644
    --- a/rest_framework/mixins.py
    +++ b/rest_framework/mixins.py
    @@ -6,40 +6,9 @@ which allows mixin classes to be composed in interesting ways.
     """
     from __future__ import unicode_literals
     
    -from django.core.exceptions import ValidationError
    -from django.http import Http404
     from rest_framework import status
     from rest_framework.response import Response
    -from rest_framework.request import clone_request
     from rest_framework.settings import api_settings
    -import warnings
    -
    -
    -def _get_validation_exclusions(obj, pk=None, slug_field=None, lookup_field=None):
    -    """
    -    Given a model instance, and an optional pk and slug field,
    -    return the full list of all other field names on that model.
    -
    -    For use when performing full_clean on a model instance,
    -    so we only clean the required fields.
    -    """
    -    include = []
    -
    -    if pk:
    -        # Deprecated
    -        pk_field = obj._meta.pk
    -        while pk_field.rel:
    -            pk_field = pk_field.rel.to._meta.pk
    -        include.append(pk_field.name)
    -
    -    if slug_field:
    -        # Deprecated
    -        include.append(slug_field)
    -
    -    if lookup_field and lookup_field != 'pk':
    -        include.append(lookup_field)
    -
    -    return [field.name for field in obj._meta.fields if field.name not in include]
     
     
     class CreateModelMixin(object):
    @@ -47,17 +16,14 @@ class CreateModelMixin(object):
         Create a model instance.
         """
         def create(self, request, *args, **kwargs):
    -        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
    +        serializer = self.get_serializer(data=request.data)
    +        serializer.is_valid(raise_exception=True)
    +        self.perform_create(serializer)
    +        headers = self.get_success_headers(serializer.data)
    +        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
     
    -        if serializer.is_valid():
    -            self.pre_save(serializer.object)
    -            self.object = serializer.save(force_insert=True)
    -            self.post_save(self.object, created=True)
    -            headers = self.get_success_headers(serializer.data)
    -            return Response(serializer.data, status=status.HTTP_201_CREATED,
    -                            headers=headers)
    -
    -        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    +    def perform_create(self, serializer):
    +        serializer.save()
     
         def get_success_headers(self, data):
             try:
    @@ -70,31 +36,13 @@ class ListModelMixin(object):
         """
         List a queryset.
         """
    -    empty_error = "Empty list and '%(class_name)s.allow_empty' is False."
    -
         def list(self, request, *args, **kwargs):
    -        self.object_list = self.filter_queryset(self.get_queryset())
    -
    -        # Default is to allow empty querysets.  This can be altered by setting
    -        # `.allow_empty = False`, to raise 404 errors on empty querysets.
    -        if not self.allow_empty and not self.object_list:
    -            warnings.warn(
    -                'The `allow_empty` parameter is deprecated. '
    -                'To use `allow_empty=False` style behavior, You should override '
    -                '`get_queryset()` and explicitly raise a 404 on empty querysets.',
    -                DeprecationWarning
    -            )
    -            class_name = self.__class__.__name__
    -            error_msg = self.empty_error % {'class_name': class_name}
    -            raise Http404(error_msg)
    -
    -        # Switch between paginated or standard style responses
    -        page = self.paginate_queryset(self.object_list)
    +        instance = self.filter_queryset(self.get_queryset())
    +        page = self.paginate_queryset(instance)
             if page is not None:
                 serializer = self.get_pagination_serializer(page)
             else:
    -            serializer = self.get_serializer(self.object_list, many=True)
    -
    +            serializer = self.get_serializer(instance, many=True)
             return Response(serializer.data)
     
     
    @@ -103,8 +51,8 @@ class RetrieveModelMixin(object):
         Retrieve a model instance.
         """
         def retrieve(self, request, *args, **kwargs):
    -        self.object = self.get_object()
    -        serializer = self.get_serializer(self.object)
    +        instance = self.get_object()
    +        serializer = self.get_serializer(instance)
             return Response(serializer.data)
     
     
    @@ -114,83 +62,28 @@ class UpdateModelMixin(object):
         """
         def update(self, request, *args, **kwargs):
             partial = kwargs.pop('partial', False)
    -        self.object = self.get_object_or_none()
    +        instance = self.get_object()
    +        serializer = self.get_serializer(instance, data=request.data, partial=partial)
    +        serializer.is_valid(raise_exception=True)
    +        self.perform_update(serializer)
    +        return Response(serializer.data)
     
    -        serializer = self.get_serializer(self.object, data=request.DATA,
    -                                         files=request.FILES, partial=partial)
    -
    -        if not serializer.is_valid():
    -            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    -
    -        try:
    -            self.pre_save(serializer.object)
    -        except ValidationError as err:
    -            # full_clean on model instance may be called in pre_save,
    -            # so we have to handle eventual errors.
    -            return Response(err.message_dict, status=status.HTTP_400_BAD_REQUEST)
    -
    -        if self.object is None:
    -            self.object = serializer.save(force_insert=True)
    -            self.post_save(self.object, created=True)
    -            return Response(serializer.data, status=status.HTTP_201_CREATED)
    -
    -        self.object = serializer.save(force_update=True)
    -        self.post_save(self.object, created=False)
    -        return Response(serializer.data, status=status.HTTP_200_OK)
    +    def perform_update(self, serializer):
    +        serializer.save()
     
         def partial_update(self, request, *args, **kwargs):
             kwargs['partial'] = True
             return self.update(request, *args, **kwargs)
     
    -    def get_object_or_none(self):
    -        try:
    -            return self.get_object()
    -        except Http404:
    -            if self.request.method == 'PUT':
    -                # For PUT-as-create operation, we need to ensure that we have
    -                # relevant permissions, as if this was a POST request.  This
    -                # will either raise a PermissionDenied exception, or simply
    -                # return None.
    -                self.check_permissions(clone_request(self.request, 'POST'))
    -            else:
    -                # PATCH requests where the object does not exist should still
    -                # return a 404 response.
    -                raise
    -
    -    def pre_save(self, obj):
    -        """
    -        Set any attributes on the object that are implicit in the request.
    -        """
    -        # pk and/or slug attributes are implicit in the URL.
    -        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
    -        lookup = self.kwargs.get(lookup_url_kwarg, None)
    -        pk = self.kwargs.get(self.pk_url_kwarg, None)
    -        slug = self.kwargs.get(self.slug_url_kwarg, None)
    -        slug_field = slug and self.slug_field or None
    -
    -        if lookup:
    -            setattr(obj, self.lookup_field, lookup)
    -
    -        if pk:
    -            setattr(obj, 'pk', pk)
    -
    -        if slug:
    -            setattr(obj, slug_field, slug)
    -
    -        # Ensure we clean the attributes so that we don't eg return integer
    -        # pk using a string representation, as provided by the url conf kwarg.
    -        if hasattr(obj, 'full_clean'):
    -            exclude = _get_validation_exclusions(obj, pk, slug_field, self.lookup_field)
    -            obj.full_clean(exclude)
    -
     
     class DestroyModelMixin(object):
         """
         Destroy a model instance.
         """
         def destroy(self, request, *args, **kwargs):
    -        obj = self.get_object()
    -        self.pre_delete(obj)
    -        obj.delete()
    -        self.post_delete(obj)
    +        instance = self.get_object()
    +        self.perform_destroy(instance)
             return Response(status=status.HTTP_204_NO_CONTENT)
    +
    +    def perform_destroy(self, instance):
    +        instance.delete()
    diff --git a/rest_framework/negotiation.py b/rest_framework/negotiation.py
    index ca7b53978..1838130a9 100644
    --- a/rest_framework/negotiation.py
    +++ b/rest_framework/negotiation.py
    @@ -38,7 +38,7 @@ class DefaultContentNegotiation(BaseContentNegotiation):
             """
             # Allow URL style format override.  eg. "?format=json
             format_query_param = self.settings.URL_FORMAT_OVERRIDE
    -        format = format_suffix or request.QUERY_PARAMS.get(format_query_param)
    +        format = format_suffix or request.query_params.get(format_query_param)
     
             if format:
                 renderers = self.filter_renderers(renderers, format)
    @@ -87,5 +87,5 @@ class DefaultContentNegotiation(BaseContentNegotiation):
             Allows URL style accept override.  eg. "?accept=application/json"
             """
             header = request.META.get('HTTP_ACCEPT', '*/*')
    -        header = request.QUERY_PARAMS.get(self.settings.URL_ACCEPT_OVERRIDE, header)
    +        header = request.query_params.get(self.settings.URL_ACCEPT_OVERRIDE, header)
             return [token.strip() for token in header.split(',')]
    diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py
    index 1f5749f1a..fb4512854 100644
    --- a/rest_framework/pagination.py
    +++ b/rest_framework/pagination.py
    @@ -13,7 +13,7 @@ class NextPageField(serializers.Field):
         """
         page_field = 'page'
     
    -    def to_native(self, value):
    +    def to_representation(self, value):
             if not value.has_next():
                 return None
             page = value.next_page_number()
    @@ -28,7 +28,7 @@ class PreviousPageField(serializers.Field):
         """
         page_field = 'page'
     
    -    def to_native(self, value):
    +    def to_representation(self, value):
             if not value.has_previous():
                 return None
             page = value.previous_page_number()
    @@ -37,7 +37,7 @@ class PreviousPageField(serializers.Field):
             return replace_query_param(url, self.page_field, page)
     
     
    -class DefaultObjectSerializer(serializers.Field):
    +class DefaultObjectSerializer(serializers.ReadOnlyField):
         """
         If no object serializer is specified, then this serializer will be applied
         as the default.
    @@ -49,25 +49,11 @@ class DefaultObjectSerializer(serializers.Field):
             super(DefaultObjectSerializer, self).__init__(source=source)
     
     
    -class PaginationSerializerOptions(serializers.SerializerOptions):
    -    """
    -    An object that stores the options that may be provided to a
    -    pagination serializer by using the inner `Meta` class.
    -
    -    Accessible on the instance as `serializer.opts`.
    -    """
    -    def __init__(self, meta):
    -        super(PaginationSerializerOptions, self).__init__(meta)
    -        self.object_serializer_class = getattr(meta, 'object_serializer_class',
    -                                               DefaultObjectSerializer)
    -
    -
     class BasePaginationSerializer(serializers.Serializer):
         """
         A base class for pagination serializers to inherit from,
         to make implementing custom serializers more easy.
         """
    -    _options_class = PaginationSerializerOptions
         results_field = 'results'
     
         def __init__(self, *args, **kwargs):
    @@ -76,22 +62,22 @@ class BasePaginationSerializer(serializers.Serializer):
             """
             super(BasePaginationSerializer, self).__init__(*args, **kwargs)
             results_field = self.results_field
    -        object_serializer = self.opts.object_serializer_class
     
    -        if 'context' in kwargs:
    -            context_kwarg = {'context': kwargs['context']}
    -        else:
    -            context_kwarg = {}
    +        try:
    +            object_serializer = self.Meta.object_serializer_class
    +        except AttributeError:
    +            object_serializer = DefaultObjectSerializer
     
    -        self.fields[results_field] = object_serializer(source='object_list',
    -                                                       many=True,
    -                                                       **context_kwarg)
    +        self.fields[results_field] = serializers.ListSerializer(
    +            child=object_serializer(),
    +            source='object_list'
    +        )
     
     
     class PaginationSerializer(BasePaginationSerializer):
         """
         A default implementation of a pagination serializer.
         """
    -    count = serializers.Field(source='paginator.count')
    +    count = serializers.ReadOnlyField(source='paginator.count')
         next = NextPageField(source='*')
         previous = PreviousPageField(source='*')
    diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py
    index c287908dc..ccb82f03b 100644
    --- a/rest_framework/parsers.py
    +++ b/rest_framework/parsers.py
    @@ -5,6 +5,7 @@ They give us a generic way of being able to handle various media types
     on the request, such as form content or json encoded data.
     """
     from __future__ import unicode_literals
    +
     from django.conf import settings
     from django.core.files.uploadhandler import StopFutureHandlers
     from django.http import QueryDict
    @@ -48,7 +49,7 @@ class JSONParser(BaseParser):
         """
     
         media_type = 'application/json'
    -    renderer_class = renderers.UnicodeJSONRenderer
    +    renderer_class = renderers.JSONRenderer
     
         def parse(self, stream, media_type=None, parser_context=None):
             """
    @@ -132,7 +133,7 @@ class MultiPartParser(BaseParser):
                 data, files = parser.parse()
                 return DataAndFiles(data, files)
             except MultiPartParserError as exc:
    -            raise ParseError('Multipart form parse error - %s' % str(exc))
    +            raise ParseError('Multipart form parse error - %s' % six.text_type(exc))
     
     
     class XMLParser(BaseParser):
    diff --git a/rest_framework/relations.py b/rest_framework/relations.py
    index 1acbdce26..79c8057b6 100644
    --- a/rest_framework/relations.py
    +++ b/rest_framework/relations.py
    @@ -1,356 +1,183 @@
    -"""
    -Serializer fields that deal with relationships.
    -
    -These fields allow you to specify the style that should be used to represent
    -model relationships, including hyperlinks, primary keys, or slugs.
    -"""
    -from __future__ import unicode_literals
    -from django.core.exceptions import ObjectDoesNotExist, ValidationError
    -from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch
    -from django import forms
    -from django.db.models.fields import BLANK_CHOICE_DASH
    -from django.forms import widgets
    -from django.forms.models import ModelChoiceIterator
    -from django.utils.translation import ugettext_lazy as _
    -from rest_framework.fields import Field, WritableField, get_component, is_simple_callable
    +from rest_framework.compat import smart_text, urlparse
    +from rest_framework.fields import get_attribute, empty, Field
     from rest_framework.reverse import reverse
    -from rest_framework.compat import urlparse
    -from rest_framework.compat import smart_text
    -import warnings
    +from rest_framework.utils import html
    +from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
    +from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch, Resolver404
    +from django.db.models.query import QuerySet
    +from django.utils import six
    +from django.utils.translation import ugettext_lazy as _
     
     
    -# Relational fields
    -
    -# Not actually Writable, but subclasses may need to be.
    -class RelatedField(WritableField):
    +class PKOnlyObject(object):
         """
    -    Base class for related model fields.
    -
    -    This represents a relationship using the unicode representation of the target.
    +    This is a mock object, used for when we only need the pk of the object
    +    instance, but still want to return an object with a .pk attribute,
    +    in order to keep the same interface as a regular model instance.
         """
    -    widget = widgets.Select
    -    many_widget = widgets.SelectMultiple
    -    form_field_class = forms.ChoiceField
    -    many_form_field_class = forms.MultipleChoiceField
    -    null_values = (None, '', 'None')
    -
    -    cache_choices = False
    -    empty_label = None
    -    read_only = True
    -    many = False
    -
    -    def __init__(self, *args, **kwargs):
    -        queryset = kwargs.pop('queryset', None)
    -        self.many = kwargs.pop('many', self.many)
    -        if self.many:
    -            self.widget = self.many_widget
    -            self.form_field_class = self.many_form_field_class
    -
    -        kwargs['read_only'] = kwargs.pop('read_only', self.read_only)
    -        super(RelatedField, self).__init__(*args, **kwargs)
    -
    -        if not self.required:
    -            # Accessed in ModelChoiceIterator django/forms/models.py:1034
    -            # If set adds empty choice.
    -            self.empty_label = BLANK_CHOICE_DASH[0][1]
    -
    -        self.queryset = queryset
    -
    -    def initialize(self, parent, field_name):
    -        super(RelatedField, self).initialize(parent, field_name)
    -        if self.queryset is None and not self.read_only:
    -            manager = getattr(self.parent.opts.model, self.source or field_name)
    -            if hasattr(manager, 'related'):  # Forward
    -                self.queryset = manager.related.model._default_manager.all()
    -            else:  # Reverse
    -                self.queryset = manager.field.rel.to._default_manager.all()
    -
    -    # We need this stuff to make form choices work...
    -
    -    def prepare_value(self, obj):
    -        return self.to_native(obj)
    -
    -    def label_from_instance(self, obj):
    -        """
    -        Return a readable representation for use with eg. select widgets.
    -        """
    -        desc = smart_text(obj)
    -        ident = smart_text(self.to_native(obj))
    -        if desc == ident:
    -            return desc
    -        return "%s - %s" % (desc, ident)
    -
    -    def _get_queryset(self):
    -        return self._queryset
    -
    -    def _set_queryset(self, queryset):
    -        self._queryset = queryset
    -        self.widget.choices = self.choices
    -
    -    queryset = property(_get_queryset, _set_queryset)
    -
    -    def _get_choices(self):
    -        # If self._choices is set, then somebody must have manually set
    -        # the property self.choices. In this case, just return self._choices.
    -        if hasattr(self, '_choices'):
    -            return self._choices
    -
    -        # Otherwise, execute the QuerySet in self.queryset to determine the
    -        # choices dynamically. Return a fresh ModelChoiceIterator that has not been
    -        # consumed. Note that we're instantiating a new ModelChoiceIterator *each*
    -        # time _get_choices() is called (and, thus, each time self.choices is
    -        # accessed) so that we can ensure the QuerySet has not been consumed. This
    -        # construct might look complicated but it allows for lazy evaluation of
    -        # the queryset.
    -        return ModelChoiceIterator(self)
    -
    -    def _set_choices(self, value):
    -        # Setting choices also sets the choices on the widget.
    -        # choices can be any iterable, but we call list() on it because
    -        # it will be consumed more than once.
    -        self._choices = self.widget.choices = list(value)
    -
    -    choices = property(_get_choices, _set_choices)
    -
    -    # Default value handling
    -
    -    def get_default_value(self):
    -        default = super(RelatedField, self).get_default_value()
    -        if self.many and default is None:
    -            return []
    -        return default
    -
    -    # Regular serializer stuff...
    -
    -    def field_to_native(self, obj, field_name):
    -        try:
    -            if self.source == '*':
    -                return self.to_native(obj)
    -
    -            source = self.source or field_name
    -            value = obj
    -
    -            for component in source.split('.'):
    -                if value is None:
    -                    break
    -                value = get_component(value, component)
    -        except ObjectDoesNotExist:
    -            return None
    -
    -        if value is None:
    -            return None
    -
    -        if self.many:
    -            if is_simple_callable(getattr(value, 'all', None)):
    -                return [self.to_native(item) for item in value.all()]
    -            else:
    -                # Also support non-queryset iterables.
    -                # This allows us to also support plain lists of related items.
    -                return [self.to_native(item) for item in value]
    -        return self.to_native(value)
    -
    -    def field_from_native(self, data, files, field_name, into):
    -        if self.read_only:
    -            return
    -
    -        try:
    -            if self.many:
    -                try:
    -                    # Form data
    -                    value = data.getlist(field_name)
    -                    if value == [''] or value == []:
    -                        raise KeyError
    -                except AttributeError:
    -                    # Non-form data
    -                    value = data[field_name]
    -            else:
    -                value = data[field_name]
    -        except KeyError:
    -            if self.partial:
    -                return
    -            value = self.get_default_value()
    -
    -        if value in self.null_values:
    -            if self.required:
    -                raise ValidationError(self.error_messages['required'])
    -            into[(self.source or field_name)] = None
    -        elif self.many:
    -            into[(self.source or field_name)] = [self.from_native(item) for item in value]
    -        else:
    -            into[(self.source or field_name)] = self.from_native(value)
    +    def __init__(self, pk):
    +        self.pk = pk
     
     
    -# PrimaryKey relationships
    +# We assume that 'validators' are intended for the child serializer,
    +# rather than the parent serializer.
    +MANY_RELATION_KWARGS = (
    +    'read_only', 'write_only', 'required', 'default', 'initial', 'source',
    +    'label', 'help_text', 'style', 'error_messages'
    +)
    +
    +
    +class RelatedField(Field):
    +    def __init__(self, **kwargs):
    +        self.queryset = kwargs.pop('queryset', None)
    +        assert self.queryset is not None or kwargs.get('read_only', None), (
    +            'Relational field must provide a `queryset` argument, '
    +            'or set read_only=`True`.'
    +        )
    +        assert not (self.queryset is not None and kwargs.get('read_only', None)), (
    +            'Relational fields should not provide a `queryset` argument, '
    +            'when setting read_only=`True`.'
    +        )
    +        super(RelatedField, self).__init__(**kwargs)
    +
    +    def __new__(cls, *args, **kwargs):
    +        # We override this method in order to automagically create
    +        # `ManyRelatedField` classes instead when `many=True` is set.
    +        if kwargs.pop('many', False):
    +            return cls.many_init(*args, **kwargs)
    +        return super(RelatedField, cls).__new__(cls, *args, **kwargs)
    +
    +    @classmethod
    +    def many_init(cls, *args, **kwargs):
    +        list_kwargs = {'child_relation': cls(*args, **kwargs)}
    +        for key in kwargs.keys():
    +            if key in MANY_RELATION_KWARGS:
    +                list_kwargs[key] = kwargs[key]
    +        return ManyRelatedField(**list_kwargs)
    +
    +    def run_validation(self, data=empty):
    +        # We force empty strings to None values for relational fields.
    +        if data == '':
    +            data = None
    +        return super(RelatedField, self).run_validation(data)
    +
    +    def get_queryset(self):
    +        queryset = self.queryset
    +        if isinstance(queryset, QuerySet):
    +            # Ensure queryset is re-evaluated whenever used.
    +            queryset = queryset.all()
    +        return queryset
    +
    +    def get_iterable(self, instance, source_attrs):
    +        relationship = get_attribute(instance, source_attrs)
    +        return relationship.all() if (hasattr(relationship, 'all')) else relationship
    +
    +    @property
    +    def choices(self):
    +        return dict([
    +            (
    +                str(self.to_representation(item)),
    +                str(item)
    +            )
    +            for item in self.queryset.all()
    +        ])
    +
    +
    +class StringRelatedField(RelatedField):
    +    """
    +    A read only field that represents its targets using their
    +    plain string representation.
    +    """
    +
    +    def __init__(self, **kwargs):
    +        kwargs['read_only'] = True
    +        super(StringRelatedField, self).__init__(**kwargs)
    +
    +    def to_representation(self, value):
    +        return six.text_type(value)
    +
     
     class PrimaryKeyRelatedField(RelatedField):
    -    """
    -    Represents a relationship as a pk value.
    -    """
    -    read_only = False
    -
         default_error_messages = {
    -        'does_not_exist': _("Invalid pk '%s' - object does not exist."),
    -        'incorrect_type': _('Incorrect type.  Expected pk value, received %s.'),
    +        'required': 'This field is required.',
    +        'does_not_exist': "Invalid pk '{pk_value}' - object does not exist.",
    +        'incorrect_type': 'Incorrect type. Expected pk value, received {data_type}.',
         }
     
    -    # TODO: Remove these field hacks...
    -    def prepare_value(self, obj):
    -        return self.to_native(obj.pk)
    -
    -    def label_from_instance(self, obj):
    -        """
    -        Return a readable representation for use with eg. select widgets.
    -        """
    -        desc = smart_text(obj)
    -        ident = smart_text(self.to_native(obj.pk))
    -        if desc == ident:
    -            return desc
    -        return "%s - %s" % (desc, ident)
    -
    -    # TODO: Possibly change this to just take `obj`, through prob less performant
    -    def to_native(self, pk):
    -        return pk
    -
    -    def from_native(self, data):
    -        if self.queryset is None:
    -            raise Exception('Writable related fields must include a `queryset` argument')
    -
    +    def to_internal_value(self, data):
             try:
    -            return self.queryset.get(pk=data)
    +            return self.get_queryset().get(pk=data)
             except ObjectDoesNotExist:
    -            msg = self.error_messages['does_not_exist'] % smart_text(data)
    -            raise ValidationError(msg)
    +            self.fail('does_not_exist', pk_value=data)
             except (TypeError, ValueError):
    -            received = type(data).__name__
    -            msg = self.error_messages['incorrect_type'] % received
    -            raise ValidationError(msg)
    +            self.fail('incorrect_type', data_type=type(data).__name__)
     
    -    def field_to_native(self, obj, field_name):
    -        if self.many:
    -            # To-many relationship
    -
    -            queryset = None
    -            if not self.source:
    -                # Prefer obj.serializable_value for performance reasons
    -                try:
    -                    queryset = obj.serializable_value(field_name)
    -                except AttributeError:
    -                    pass
    -            if queryset is None:
    -                # RelatedManager (reverse relationship)
    -                source = self.source or field_name
    -                queryset = obj
    -                for component in source.split('.'):
    -                    if queryset is None:
    -                        return []
    -                    queryset = get_component(queryset, component)
    -
    -            # Forward relationship
    -            if is_simple_callable(getattr(queryset, 'all', None)):
    -                return [self.to_native(item.pk) for item in queryset.all()]
    -            else:
    -                # Also support non-queryset iterables.
    -                # This allows us to also support plain lists of related items.
    -                return [self.to_native(item.pk) for item in queryset]
    -
    -        # To-one relationship
    +    def get_attribute(self, instance):
    +        # We customize `get_attribute` here for performance reasons.
    +        # For relationships the instance will already have the pk of
    +        # the related object. We return this directly instead of returning the
    +        # object itself, which would require a database lookup.
             try:
    -            # Prefer obj.serializable_value for performance reasons
    -            pk = obj.serializable_value(self.source or field_name)
    +            instance = get_attribute(instance, self.source_attrs[:-1])
    +            return PKOnlyObject(pk=instance.serializable_value(self.source_attrs[-1]))
             except AttributeError:
    -            # RelatedObject (reverse relationship)
    -            try:
    -                pk = getattr(obj, self.source or field_name).pk
    -            except (ObjectDoesNotExist, AttributeError):
    -                return None
    +            return get_attribute(instance, self.source_attrs)
     
    -        # Forward relationship
    -        return self.to_native(pk)
    +    def get_iterable(self, instance, source_attrs):
    +        # For consistency with `get_attribute` we're using `serializable_value()`
    +        # here. Typically there won't be any difference, but some custom field
    +        # types might return a non-primative value for the pk otherwise.
    +        #
    +        # We could try to get smart with `values_list('pk', flat=True)`, which
    +        # would be better in some case, but would actually end up with *more*
    +        # queries if the developer is using `prefetch_related` across the
    +        # relationship.
    +        relationship = super(PrimaryKeyRelatedField, self).get_iterable(instance, source_attrs)
    +        return [
    +            PKOnlyObject(pk=item.serializable_value('pk'))
    +            for item in relationship
    +        ]
     
    +    def to_representation(self, value):
    +        return value.pk
     
    -# Slug relationships
    -
    -class SlugRelatedField(RelatedField):
    -    """
    -    Represents a relationship using a unique field on the target.
    -    """
    -    read_only = False
    -
    -    default_error_messages = {
    -        'does_not_exist': _("Object with %s=%s does not exist."),
    -        'invalid': _('Invalid value.'),
    -    }
    -
    -    def __init__(self, *args, **kwargs):
    -        self.slug_field = kwargs.pop('slug_field', None)
    -        assert self.slug_field, 'slug_field is required'
    -        super(SlugRelatedField, self).__init__(*args, **kwargs)
    -
    -    def to_native(self, obj):
    -        return getattr(obj, self.slug_field)
    -
    -    def from_native(self, data):
    -        if self.queryset is None:
    -            raise Exception('Writable related fields must include a `queryset` argument')
    -
    -        try:
    -            return self.queryset.get(**{self.slug_field: data})
    -        except ObjectDoesNotExist:
    -            raise ValidationError(self.error_messages['does_not_exist'] %
    -                                  (self.slug_field, smart_text(data)))
    -        except (TypeError, ValueError):
    -            msg = self.error_messages['invalid']
    -            raise ValidationError(msg)
    -
    -
    -# Hyperlinked relationships
     
     class HyperlinkedRelatedField(RelatedField):
    -    """
    -    Represents a relationship using hyperlinking.
    -    """
    -    read_only = False
         lookup_field = 'pk'
     
         default_error_messages = {
    -        'no_match': _('Invalid hyperlink - No URL match'),
    -        'incorrect_match': _('Invalid hyperlink - Incorrect URL match'),
    -        'configuration_error': _('Invalid hyperlink due to configuration error'),
    -        'does_not_exist': _("Invalid hyperlink - object does not exist."),
    -        'incorrect_type': _('Incorrect type.  Expected url string, received %s.'),
    +        'required': 'This field is required.',
    +        'no_match': 'Invalid hyperlink - No URL match',
    +        'incorrect_match': 'Invalid hyperlink - Incorrect URL match.',
    +        'does_not_exist': 'Invalid hyperlink - Object does not exist.',
    +        'incorrect_type': 'Incorrect type. Expected URL string, received {data_type}.',
         }
     
    -    # These are all deprecated
    -    pk_url_kwarg = 'pk'
    -    slug_field = 'slug'
    -    slug_url_kwarg = None  # Defaults to same as `slug_field` unless overridden
    -
    -    def __init__(self, *args, **kwargs):
    -        try:
    -            self.view_name = kwargs.pop('view_name')
    -        except KeyError:
    -            raise ValueError("Hyperlinked field requires 'view_name' kwarg")
    -
    +    def __init__(self, view_name=None, **kwargs):
    +        assert view_name is not None, 'The `view_name` argument is required.'
    +        self.view_name = view_name
             self.lookup_field = kwargs.pop('lookup_field', self.lookup_field)
    +        self.lookup_url_kwarg = kwargs.pop('lookup_url_kwarg', self.lookup_field)
             self.format = kwargs.pop('format', None)
     
    -        # These are deprecated
    -        if 'pk_url_kwarg' in kwargs:
    -            msg = 'pk_url_kwarg is deprecated. Use lookup_field instead.'
    -            warnings.warn(msg, DeprecationWarning, stacklevel=2)
    -        if 'slug_url_kwarg' in kwargs:
    -            msg = 'slug_url_kwarg is deprecated. Use lookup_field instead.'
    -            warnings.warn(msg, DeprecationWarning, stacklevel=2)
    -        if 'slug_field' in kwargs:
    -            msg = 'slug_field is deprecated. Use lookup_field instead.'
    -            warnings.warn(msg, DeprecationWarning, stacklevel=2)
    +        # We include these simply for dependency injection in tests.
    +        # We can't add them as class attributes or they would expect an
    +        # implicit `self` argument to be passed.
    +        self.reverse = reverse
    +        self.resolve = resolve
     
    -        self.pk_url_kwarg = kwargs.pop('pk_url_kwarg', self.pk_url_kwarg)
    -        self.slug_field = kwargs.pop('slug_field', self.slug_field)
    -        default_slug_kwarg = self.slug_url_kwarg or self.slug_field
    -        self.slug_url_kwarg = kwargs.pop('slug_url_kwarg', default_slug_kwarg)
    +        super(HyperlinkedRelatedField, self).__init__(**kwargs)
     
    -        super(HyperlinkedRelatedField, self).__init__(*args, **kwargs)
    +    def get_object(self, view_name, view_args, view_kwargs):
    +        """
    +        Return the object corresponding to a matched URL.
    +
    +        Takes the matched URL conf arguments, and should return an
    +        object instance, or raise an `ObjectDoesNotExist` exception.
    +        """
    +        lookup_value = view_kwargs[self.lookup_url_kwarg]
    +        lookup_kwargs = {self.lookup_field: lookup_value}
    +        return self.get_queryset().get(**lookup_kwargs)
     
         def get_url(self, obj, view_name, request, format):
             """
    @@ -359,176 +186,48 @@ class HyperlinkedRelatedField(RelatedField):
             May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
             attributes are not configured to correctly match the URL conf.
             """
    -        lookup_field = getattr(obj, self.lookup_field)
    -        kwargs = {self.lookup_field: lookup_field}
    +        # Unsaved objects will not yet have a valid URL.
    +        if obj.pk is None:
    +            return None
    +
    +        lookup_value = getattr(obj, self.lookup_field)
    +        kwargs = {self.lookup_url_kwarg: lookup_value}
    +        return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
    +
    +    def to_internal_value(self, data):
             try:
    -            return reverse(view_name, kwargs=kwargs, request=request, format=format)
    -        except NoReverseMatch:
    -            pass
    -
    -        if self.pk_url_kwarg != 'pk':
    -            # Only try pk if it has been explicitly set.
    -            # Otherwise, the default `lookup_field = 'pk'` has us covered.
    -            pk = obj.pk
    -            kwargs = {self.pk_url_kwarg: pk}
    -            try:
    -                return reverse(view_name, kwargs=kwargs, request=request, format=format)
    -            except NoReverseMatch:
    -                pass
    -
    -        slug = getattr(obj, self.slug_field, None)
    -        if slug is not None:
    -            # Only try slug if it corresponds to an attribute on the object.
    -            kwargs = {self.slug_url_kwarg: slug}
    -            try:
    -                ret = reverse(view_name, kwargs=kwargs, request=request, format=format)
    -                if self.slug_field == 'slug' and self.slug_url_kwarg == 'slug':
    -                    # If the lookup succeeds using the default slug params,
    -                    # then `slug_field` is being used implicitly, and we
    -                    # we need to warn about the pending deprecation.
    -                    msg = 'Implicit slug field hyperlinked fields are deprecated.' \
    -                          'You should set `lookup_field=slug` on the HyperlinkedRelatedField.'
    -                    warnings.warn(msg, DeprecationWarning, stacklevel=2)
    -                return ret
    -            except NoReverseMatch:
    -                pass
    -
    -        raise NoReverseMatch()
    -
    -    def get_object(self, queryset, view_name, view_args, view_kwargs):
    -        """
    -        Return the object corresponding to a matched URL.
    -
    -        Takes the matched URL conf arguments, and the queryset, and should
    -        return an object instance, or raise an `ObjectDoesNotExist` exception.
    -        """
    -        lookup = view_kwargs.get(self.lookup_field, None)
    -        pk = view_kwargs.get(self.pk_url_kwarg, None)
    -        slug = view_kwargs.get(self.slug_url_kwarg, None)
    -
    -        if lookup is not None:
    -            filter_kwargs = {self.lookup_field: lookup}
    -        elif pk is not None:
    -            filter_kwargs = {'pk': pk}
    -        elif slug is not None:
    -            filter_kwargs = {self.slug_field: slug}
    -        else:
    -            raise ObjectDoesNotExist()
    -
    -        return queryset.get(**filter_kwargs)
    -
    -    def to_native(self, obj):
    -        view_name = self.view_name
    -        request = self.context.get('request', None)
    -        format = self.format or self.context.get('format', None)
    -
    -        assert request is not None, (
    -            "`HyperlinkedRelatedField` requires the request in the serializer "
    -            "context. Add `context={'request': request}` when instantiating "
    -            "the serializer."
    -        )
    -
    -        # If the object has not yet been saved then we cannot hyperlink to it.
    -        if getattr(obj, 'pk', None) is None:
    -            return
    -
    -        # Return the hyperlink, or error if incorrectly configured.
    -        try:
    -            return self.get_url(obj, view_name, request, format)
    -        except NoReverseMatch:
    -            msg = (
    -                'Could not resolve URL for hyperlinked relationship using '
    -                'view name "%s". You may have failed to include the related '
    -                'model in your API, or incorrectly configured the '
    -                '`lookup_field` attribute on this field.'
    -            )
    -            raise Exception(msg % view_name)
    -
    -    def from_native(self, value):
    -        # Convert URL -> model instance pk
    -        # TODO: Use values_list
    -        queryset = self.queryset
    -        if queryset is None:
    -            raise Exception('Writable related fields must include a `queryset` argument')
    -
    -        try:
    -            http_prefix = value.startswith(('http:', 'https:'))
    +            http_prefix = data.startswith(('http:', 'https:'))
             except AttributeError:
    -            msg = self.error_messages['incorrect_type']
    -            raise ValidationError(msg % type(value).__name__)
    +            self.fail('incorrect_type', data_type=type(data).__name__)
     
             if http_prefix:
                 # If needed convert absolute URLs to relative path
    -            value = urlparse.urlparse(value).path
    +            data = urlparse.urlparse(data).path
                 prefix = get_script_prefix()
    -            if value.startswith(prefix):
    -                value = '/' + value[len(prefix):]
    +            if data.startswith(prefix):
    +                data = '/' + data[len(prefix):]
     
             try:
    -            match = resolve(value)
    -        except Exception:
    -            raise ValidationError(self.error_messages['no_match'])
    +            match = self.resolve(data)
    +        except Resolver404:
    +            self.fail('no_match')
     
             if match.view_name != self.view_name:
    -            raise ValidationError(self.error_messages['incorrect_match'])
    +            self.fail('incorrect_match')
     
             try:
    -            return self.get_object(queryset, match.view_name,
    -                                   match.args, match.kwargs)
    +            return self.get_object(match.view_name, match.args, match.kwargs)
             except (ObjectDoesNotExist, TypeError, ValueError):
    -            raise ValidationError(self.error_messages['does_not_exist'])
    +            self.fail('does_not_exist')
     
    -
    -class HyperlinkedIdentityField(Field):
    -    """
    -    Represents the instance, or a property on the instance, using hyperlinking.
    -    """
    -    lookup_field = 'pk'
    -    read_only = True
    -
    -    # These are all deprecated
    -    pk_url_kwarg = 'pk'
    -    slug_field = 'slug'
    -    slug_url_kwarg = None  # Defaults to same as `slug_field` unless overridden
    -
    -    def __init__(self, *args, **kwargs):
    -        try:
    -            self.view_name = kwargs.pop('view_name')
    -        except KeyError:
    -            msg = "HyperlinkedIdentityField requires 'view_name' argument"
    -            raise ValueError(msg)
    -
    -        self.format = kwargs.pop('format', None)
    -        lookup_field = kwargs.pop('lookup_field', None)
    -        self.lookup_field = lookup_field or self.lookup_field
    -
    -        # These are deprecated
    -        if 'pk_url_kwarg' in kwargs:
    -            msg = 'pk_url_kwarg is deprecated. Use lookup_field instead.'
    -            warnings.warn(msg, DeprecationWarning, stacklevel=2)
    -        if 'slug_url_kwarg' in kwargs:
    -            msg = 'slug_url_kwarg is deprecated. Use lookup_field instead.'
    -            warnings.warn(msg, DeprecationWarning, stacklevel=2)
    -        if 'slug_field' in kwargs:
    -            msg = 'slug_field is deprecated. Use lookup_field instead.'
    -            warnings.warn(msg, DeprecationWarning, stacklevel=2)
    -
    -        self.slug_field = kwargs.pop('slug_field', self.slug_field)
    -        default_slug_kwarg = self.slug_url_kwarg or self.slug_field
    -        self.pk_url_kwarg = kwargs.pop('pk_url_kwarg', self.pk_url_kwarg)
    -        self.slug_url_kwarg = kwargs.pop('slug_url_kwarg', default_slug_kwarg)
    -
    -        super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
    -
    -    def field_to_native(self, obj, field_name):
    +    def to_representation(self, value):
             request = self.context.get('request', None)
             format = self.context.get('format', None)
    -        view_name = self.view_name
     
             assert request is not None, (
    -            "`HyperlinkedIdentityField` requires the request in the serializer"
    +            "`%s` requires the request in the serializer"
                 " context. Add `context={'request': request}` when instantiating "
    -            "the serializer."
    +            "the serializer." % self.__class__.__name__
             )
     
             # By default use whatever format is given for the current context
    @@ -545,7 +244,7 @@ class HyperlinkedIdentityField(Field):
     
             # Return the hyperlink, or error if incorrectly configured.
             try:
    -            return self.get_url(obj, view_name, request, format)
    +            return self.get_url(value, self.view_name, request, format)
             except NoReverseMatch:
                 msg = (
                     'Could not resolve URL for hyperlinked relationship using '
    @@ -553,43 +252,105 @@ class HyperlinkedIdentityField(Field):
                     'model in your API, or incorrectly configured the '
                     '`lookup_field` attribute on this field.'
                 )
    -            raise Exception(msg % view_name)
    +            raise ImproperlyConfigured(msg % self.view_name)
     
    -    def get_url(self, obj, view_name, request, format):
    -        """
    -        Given an object, return the URL that hyperlinks to the object.
     
    -        May raise a `NoReverseMatch` if the `view_name` and `lookup_field`
    -        attributes are not configured to correctly match the URL conf.
    -        """
    -        lookup_field = getattr(obj, self.lookup_field, None)
    -        kwargs = {self.lookup_field: lookup_field}
    +class HyperlinkedIdentityField(HyperlinkedRelatedField):
    +    """
    +    A read-only field that represents the identity URL for an object, itself.
     
    -        # Handle unsaved object case
    -        if lookup_field is None:
    -            return None
    +    This is in contrast to `HyperlinkedRelatedField` which represents the
    +    URL of relationships to other objects.
    +    """
     
    +    def __init__(self, view_name=None, **kwargs):
    +        assert view_name is not None, 'The `view_name` argument is required.'
    +        kwargs['read_only'] = True
    +        kwargs['source'] = '*'
    +        super(HyperlinkedIdentityField, self).__init__(view_name, **kwargs)
    +
    +
    +class SlugRelatedField(RelatedField):
    +    """
    +    A read-write field the represents the target of the relationship
    +    by a unique 'slug' attribute.
    +    """
    +
    +    default_error_messages = {
    +        'does_not_exist': _("Object with {slug_name}={value} does not exist."),
    +        'invalid': _('Invalid value.'),
    +    }
    +
    +    def __init__(self, slug_field=None, **kwargs):
    +        assert slug_field is not None, 'The `slug_field` argument is required.'
    +        self.slug_field = slug_field
    +        super(SlugRelatedField, self).__init__(**kwargs)
    +
    +    def to_internal_value(self, data):
             try:
    -            return reverse(view_name, kwargs=kwargs, request=request, format=format)
    -        except NoReverseMatch:
    -            pass
    +            return self.get_queryset().get(**{self.slug_field: data})
    +        except ObjectDoesNotExist:
    +            self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
    +        except (TypeError, ValueError):
    +            self.fail('invalid')
     
    -        if self.pk_url_kwarg != 'pk':
    -            # Only try pk lookup if it has been explicitly set.
    -            # Otherwise, the default `lookup_field = 'pk'` has us covered.
    -            kwargs = {self.pk_url_kwarg: obj.pk}
    -            try:
    -                return reverse(view_name, kwargs=kwargs, request=request, format=format)
    -            except NoReverseMatch:
    -                pass
    +    def to_representation(self, obj):
    +        return getattr(obj, self.slug_field)
     
    -        slug = getattr(obj, self.slug_field, None)
    -        if slug:
    -            # Only use slug lookup if a slug field exists on the model
    -            kwargs = {self.slug_url_kwarg: slug}
    -            try:
    -                return reverse(view_name, kwargs=kwargs, request=request, format=format)
    -            except NoReverseMatch:
    -                pass
     
    -        raise NoReverseMatch()
    +class ManyRelatedField(Field):
    +    """
    +    Relationships with `many=True` transparently get coerced into instead being
    +    a ManyRelatedField with a child relationship.
    +
    +    The `ManyRelatedField` class is responsible for handling iterating through
    +    the values and passing each one to the child relationship.
    +
    +    You shouldn't need to be using this class directly yourself.
    +    """
    +    initial = []
    +    default_empty_html = []
    +
    +    def __init__(self, child_relation=None, *args, **kwargs):
    +        self.child_relation = child_relation
    +        assert child_relation is not None, '`child_relation` is a required argument.'
    +        super(ManyRelatedField, self).__init__(*args, **kwargs)
    +        self.child_relation.bind(field_name='', parent=self)
    +
    +    def get_value(self, dictionary):
    +        # We override the default field access in order to support
    +        # lists in HTML forms.
    +        if html.is_html_input(dictionary):
    +            return dictionary.getlist(self.field_name)
    +        return dictionary.get(self.field_name, empty)
    +
    +    def to_internal_value(self, data):
    +        return [
    +            self.child_relation.to_internal_value(item)
    +            for item in data
    +        ]
    +
    +    def get_attribute(self, instance):
    +        return self.child_relation.get_iterable(instance, self.source_attrs)
    +
    +    def to_representation(self, iterable):
    +        return [
    +            self.child_relation.to_representation(value)
    +            for value in iterable
    +        ]
    +
    +    @property
    +    def choices(self):
    +        queryset = self.child_relation.queryset
    +        iterable = queryset.all() if (hasattr(queryset, 'all')) else queryset
    +        items_and_representations = [
    +            (item, self.child_relation.to_representation(item))
    +            for item in iterable
    +        ]
    +        return dict([
    +            (
    +                str(item_representation),
    +                str(item) + ' - ' + str(item_representation)
    +            )
    +            for item, item_representation in items_and_representations
    +        ])
    diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
    index 748ebac94..e87d16d0d 100644
    --- a/rest_framework/renderers.py
    +++ b/rest_framework/renderers.py
    @@ -13,17 +13,24 @@ import django
     from django import forms
     from django.core.exceptions import ImproperlyConfigured
     from django.http.multipartparser import parse_header
    -from django.template import RequestContext, loader, Template
    +from django.template import Context, RequestContext, loader, Template
     from django.test.client import encode_multipart
     from django.utils import six
     from django.utils.xmlutils import SimplerXMLGenerator
    -from rest_framework.compat import StringIO, smart_text, yaml
    +from rest_framework import exceptions, serializers, status, VERSION
    +from rest_framework.compat import (
    +    SHORT_SEPARATORS, LONG_SEPARATORS, StringIO, smart_text, yaml
    +)
     from rest_framework.exceptions import ParseError
     from rest_framework.settings import api_settings
     from rest_framework.request import is_form_media_type, override_method
     from rest_framework.utils import encoders
     from rest_framework.utils.breadcrumbs import get_breadcrumbs
    -from rest_framework import exceptions, status, VERSION
    +from rest_framework.utils.field_mapping import ClassLookupDict
    +
    +
    +def zero_as_none(value):
    +    return None if value == 0 else value
     
     
     class BaseRenderer(object):
    @@ -44,13 +51,13 @@ class BaseRenderer(object):
     class JSONRenderer(BaseRenderer):
         """
         Renderer which serializes to JSON.
    -    Applies JSON's backslash-u character escaping for non-ascii characters.
         """
     
         media_type = 'application/json'
         format = 'json'
         encoder_class = encoders.JSONEncoder
    -    ensure_ascii = True
    +    ensure_ascii = not api_settings.UNICODE_JSON
    +    compact = api_settings.COMPACT_JSON
     
         # We don't set a charset because JSON is a binary encoding,
         # that can be encoded as utf-8, utf-16 or utf-32.
    @@ -62,9 +69,10 @@ class JSONRenderer(BaseRenderer):
             if accepted_media_type:
                 # If the media type looks like 'application/json; indent=4',
                 # then pretty print the result.
    +            # Note that we coerce `indent=0` into `indent=None`.
                 base_media_type, params = parse_header(accepted_media_type.encode('ascii'))
                 try:
    -                return max(min(int(params['indent']), 8), 0)
    +                return zero_as_none(max(min(int(params['indent']), 8), 0))
                 except (KeyError, ValueError, TypeError):
                     pass
     
    @@ -81,10 +89,12 @@ class JSONRenderer(BaseRenderer):
     
             renderer_context = renderer_context or {}
             indent = self.get_indent(accepted_media_type, renderer_context)
    +        separators = SHORT_SEPARATORS if (indent is None and self.compact) else LONG_SEPARATORS
     
             ret = json.dumps(
                 data, cls=self.encoder_class,
    -            indent=indent, ensure_ascii=self.ensure_ascii
    +            indent=indent, ensure_ascii=self.ensure_ascii,
    +            separators=separators
             )
     
             # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
    @@ -96,14 +106,6 @@ class JSONRenderer(BaseRenderer):
             return ret
     
     
    -class UnicodeJSONRenderer(JSONRenderer):
    -    ensure_ascii = False
    -    """
    -    Renderer which serializes to JSON.
    -    Does *not* apply JSON's character escaping for non-ascii characters.
    -    """
    -
    -
     class JSONPRenderer(JSONRenderer):
         """
         Renderer which serializes to json,
    @@ -121,7 +123,7 @@ class JSONPRenderer(JSONRenderer):
             Determine the name of the callback to wrap around the json output.
             """
             request = renderer_context.get('request', None)
    -        params = request and request.QUERY_PARAMS or {}
    +        params = request and request.query_params or {}
             return params.get(self.callback_parameter, self.default_callback)
     
         def render(self, data, accepted_media_type=None, renderer_context=None):
    @@ -196,7 +198,7 @@ class YAMLRenderer(BaseRenderer):
         format = 'yaml'
         encoder = encoders.SafeDumper
         charset = 'utf-8'
    -    ensure_ascii = True
    +    ensure_ascii = False
     
         def render(self, data, accepted_media_type=None, renderer_context=None):
             """
    @@ -210,14 +212,6 @@ class YAMLRenderer(BaseRenderer):
             return yaml.dump(data, stream=None, encoding=self.charset, Dumper=self.encoder, allow_unicode=not self.ensure_ascii)
     
     
    -class UnicodeYAMLRenderer(YAMLRenderer):
    -    """
    -    Renderer which serializes to YAML.
    -    Does *not* apply character escaping for non-ascii characters.
    -    """
    -    ensure_ascii = False
    -
    -
     class TemplateHTMLRenderer(BaseRenderer):
         """
         An HTML renderer for use with templates.
    @@ -347,18 +341,109 @@ class HTMLFormRenderer(BaseRenderer):
         """
         media_type = 'text/html'
         format = 'form'
    -    template = 'rest_framework/form.html'
         charset = 'utf-8'
    +    template_pack = 'rest_framework/horizontal/'
    +    base_template = 'form.html'
    +
    +    default_style = ClassLookupDict({
    +        serializers.Field: {
    +            'base_template': 'input.html',
    +            'input_type': 'text'
    +        },
    +        serializers.EmailField: {
    +            'base_template': 'input.html',
    +            'input_type': 'email'
    +        },
    +        serializers.URLField: {
    +            'base_template': 'input.html',
    +            'input_type': 'url'
    +        },
    +        serializers.IntegerField: {
    +            'base_template': 'input.html',
    +            'input_type': 'number'
    +        },
    +        serializers.DateTimeField: {
    +            'base_template': 'input.html',
    +            'input_type': 'datetime-local'
    +        },
    +        serializers.DateField: {
    +            'base_template': 'input.html',
    +            'input_type': 'date'
    +        },
    +        serializers.TimeField: {
    +            'base_template': 'input.html',
    +            'input_type': 'time'
    +        },
    +        serializers.BooleanField: {
    +            'base_template': 'checkbox.html'
    +        },
    +        serializers.ChoiceField: {
    +            'base_template': 'select.html',  # Also valid: 'radio.html'
    +        },
    +        serializers.MultipleChoiceField: {
    +            'base_template': 'select_multiple.html',  # Also valid: 'checkbox_multiple.html'
    +        },
    +        serializers.RelatedField: {
    +            'base_template': 'select.html',  # Also valid: 'radio.html'
    +        },
    +        serializers.ManyRelatedField: {
    +            'base_template': 'select_multiple.html',  # Also valid: 'checkbox_multiple.html'
    +        },
    +        serializers.Serializer: {
    +            'base_template': 'fieldset.html'
    +        },
    +        serializers.ListSerializer: {
    +            'base_template': 'list_fieldset.html'
    +        }
    +    })
    +
    +    def render_field(self, field, parent_style):
    +        style = dict(self.default_style[field])
    +        style.update(field.style)
    +        if 'template_pack' not in style:
    +            style['template_pack'] = parent_style.get('template_pack', self.template_pack)
    +        style['renderer'] = self
    +
    +        if style.get('input_type') == 'datetime-local' and isinstance(field.value, six.text_type):
    +            field.value = field.value.rstrip('Z')
    +
    +        if 'template' in style:
    +            template_name = style['template']
    +        else:
    +            template_name = style['template_pack'].strip('/') + '/' + style['base_template']
    +
    +        template = loader.get_template(template_name)
    +        context = Context({'field': field, 'style': style})
    +        return template.render(context)
     
         def render(self, data, accepted_media_type=None, renderer_context=None):
             """
             Render serializer data and return an HTML form, as a string.
             """
    +        form = data.serializer
    +        meta = getattr(form, 'Meta', None)
    +        style = getattr(meta, 'style', {})
    +        if 'template_pack' not in style:
    +            style['template_pack'] = self.template_pack
    +        if 'base_template' not in style:
    +            style['base_template'] = self.base_template
    +        style['renderer'] = self
    +
    +        # This API needs to be finessed and finalized for 3.1
    +        if 'template' in renderer_context:
    +            template_name = renderer_context['template']
    +        elif 'template' in style:
    +            template_name = style['template']
    +        else:
    +            template_name = style['template_pack'].strip('/') + '/' + style['base_template']
    +
             renderer_context = renderer_context or {}
             request = renderer_context['request']
    -
    -        template = loader.get_template(self.template)
    -        context = RequestContext(request, {'form': data})
    +        template = loader.get_template(template_name)
    +        context = RequestContext(request, {
    +            'form': form,
    +            'style': style
    +        })
             return template.render(context)
     
     
    @@ -426,27 +511,35 @@ class BrowsableAPIRenderer(BaseRenderer):
                 return False  # Doesn't have permissions
             return True
     
    -    def get_rendered_html_form(self, view, method, request):
    +    def get_rendered_html_form(self, data, view, method, request):
             """
             Return a string representing a rendered HTML form, possibly bound to
             either the input or output data.
     
             In the absence of the View having an associated form then return None.
             """
    -        if request.method == method:
    +        # See issue #2089 for refactoring this.
    +        serializer = getattr(data, 'serializer', None)
    +        if serializer and not getattr(serializer, 'many', False):
    +            instance = getattr(serializer, 'instance', None)
    +        else:
    +            instance = None
    +
    +        # If this is valid serializer data, and the form is for the same
    +        # HTTP method as was used in the request then use the existing
    +        # serializer instance, rather than dynamically creating a new one.
    +        if request.method == method and serializer is not None:
                 try:
    -                data = request.DATA
    -                files = request.FILES
    +                data = request.data
                 except ParseError:
                     data = None
    -                files = None
    +            existing_serializer = serializer
             else:
                 data = None
    -            files = None
    +            existing_serializer = None
     
             with override_method(view, request, method) as request:
    -            obj = getattr(view, 'object', None)
    -            if not self.show_form_for_method(view, method, request, obj):
    +            if not self.show_form_for_method(view, method, request, instance):
                     return
     
                 if method in ('DELETE', 'OPTIONS'):
    @@ -458,19 +551,38 @@ class BrowsableAPIRenderer(BaseRenderer):
                 ):
                     return
     
    -            serializer = view.get_serializer(instance=obj, data=data, files=files)
    -            serializer.is_valid()
    -            data = serializer.data
    -
    +            if existing_serializer is not None:
    +                serializer = existing_serializer
    +            else:
    +                if method in ('PUT', 'PATCH'):
    +                    serializer = view.get_serializer(instance=instance, data=data)
    +                else:
    +                    serializer = view.get_serializer(data=data)
    +                if data is not None:
    +                    serializer.is_valid()
                 form_renderer = self.form_renderer_class()
    -            return form_renderer.render(data, self.accepted_media_type, self.renderer_context)
    +            return form_renderer.render(
    +                serializer.data,
    +                self.accepted_media_type,
    +                dict(
    +                    list(self.renderer_context.items()) +
    +                    [('template', 'rest_framework/api_form.html')]
    +                )
    +            )
     
    -    def get_raw_data_form(self, view, method, request):
    +    def get_raw_data_form(self, data, view, method, request):
             """
             Returns a form that allows for arbitrary content types to be tunneled
             via standard HTML forms.
             (Which are typically application/x-www-form-urlencoded)
             """
    +        # See issue #2089 for refactoring this.
    +        serializer = getattr(data, 'serializer', None)
    +        if serializer and not getattr(serializer, 'many', False):
    +            instance = getattr(serializer, 'instance', None)
    +        else:
    +            instance = None
    +
             with override_method(view, request, method) as request:
                 # If we're not using content overloading there's no point in
                 # supplying a generic form, as the view won't treat the form's
    @@ -480,8 +592,7 @@ class BrowsableAPIRenderer(BaseRenderer):
                     return None
     
                 # Check permissions
    -            obj = getattr(view, 'object', None)
    -            if not self.show_form_for_method(view, method, request, obj):
    +            if not self.show_form_for_method(view, method, request, instance):
                     return
     
                 # If possible, serialize the initial content for the generic form
    @@ -491,12 +602,10 @@ class BrowsableAPIRenderer(BaseRenderer):
                     # View has a serializer defined and parser class has a
                     # corresponding renderer that can be used to render the data.
     
    -                # Get a read-only version of the serializer
    -                serializer = view.get_serializer(instance=obj)
    -                if obj is None:
    -                    for name, field in serializer.fields.items():
    -                        if getattr(field, 'read_only', None):
    -                            del serializer.fields[name]
    +                if method in ('PUT', 'PATCH'):
    +                    serializer = view.get_serializer(instance=instance)
    +                else:
    +                    serializer = view.get_serializer()
     
                     # Render the raw data content
                     renderer = renderer_class()
    @@ -553,9 +662,9 @@ class BrowsableAPIRenderer(BaseRenderer):
     
             renderer = self.get_default_renderer(view)
     
    -        raw_data_post_form = self.get_raw_data_form(view, 'POST', request)
    -        raw_data_put_form = self.get_raw_data_form(view, 'PUT', request)
    -        raw_data_patch_form = self.get_raw_data_form(view, 'PATCH', request)
    +        raw_data_post_form = self.get_raw_data_form(data, view, 'POST', request)
    +        raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request)
    +        raw_data_patch_form = self.get_raw_data_form(data, view, 'PATCH', request)
             raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form
     
             response_headers = dict(response.items())
    @@ -579,10 +688,10 @@ class BrowsableAPIRenderer(BaseRenderer):
                 'available_formats': [renderer_cls.format for renderer_cls in view.renderer_classes],
                 'response_headers': response_headers,
     
    -            'put_form': self.get_rendered_html_form(view, 'PUT', request),
    -            'post_form': self.get_rendered_html_form(view, 'POST', request),
    -            'delete_form': self.get_rendered_html_form(view, 'DELETE', request),
    -            'options_form': self.get_rendered_html_form(view, 'OPTIONS', request),
    +            'put_form': self.get_rendered_html_form(data, view, 'PUT', request),
    +            'post_form': self.get_rendered_html_form(data, view, 'POST', request),
    +            'delete_form': self.get_rendered_html_form(data, view, 'DELETE', request),
    +            'options_form': self.get_rendered_html_form(data, view, 'OPTIONS', request),
     
                 'raw_data_put_form': raw_data_put_form,
                 'raw_data_post_form': raw_data_post_form,
    diff --git a/rest_framework/request.py b/rest_framework/request.py
    index 275326614..096b30424 100644
    --- a/rest_framework/request.py
    +++ b/rest_framework/request.py
    @@ -4,7 +4,7 @@ The Request class is used as a wrapper around the standard request object.
     The wrapped request then offers a richer API, in particular :
     
         - content automatically parsed according to `Content-Type` header,
    -      and available as `request.DATA`
    +      and available as `request.data`
         - full support of PUT method, including support for file uploads
         - form overloading of HTTP method, content type and content
     """
    @@ -13,10 +13,12 @@ from django.conf import settings
     from django.http import QueryDict
     from django.http.multipartparser import parse_header
     from django.utils.datastructures import MultiValueDict
    +from django.utils.datastructures import MergeDict as DjangoMergeDict
     from rest_framework import HTTP_HEADER_ENCODING
     from rest_framework import exceptions
     from rest_framework.compat import BytesIO
     from rest_framework.settings import api_settings
    +import warnings
     
     
     def is_form_media_type(media_type):
    @@ -58,6 +60,15 @@ class override_method(object):
                 self.view.action = self.action
     
     
    +class MergeDict(DjangoMergeDict, dict):
    +    """
    +    Using this as a workaround until the parsers API is properly
    +    addressed in 3.1.
    +    """
    +    def __init__(self, *dicts):
    +        self.dicts = dicts
    +
    +
     class Empty(object):
         """
         Placeholder for unset attributes.
    @@ -82,6 +93,7 @@ def clone_request(request, method):
                       parser_context=request.parser_context)
         ret._data = request._data
         ret._files = request._files
    +    ret._full_data = request._full_data
         ret._content_type = request._content_type
         ret._stream = request._stream
         ret._method = method
    @@ -91,6 +103,10 @@ def clone_request(request, method):
             ret._auth = request._auth
         if hasattr(request, '_authenticator'):
             ret._authenticator = request._authenticator
    +    if hasattr(request, 'accepted_renderer'):
    +        ret.accepted_renderer = request.accepted_renderer
    +    if hasattr(request, 'accepted_media_type'):
    +        ret.accepted_media_type = request.accepted_media_type
         return ret
     
     
    @@ -133,6 +149,7 @@ class Request(object):
             self.parser_context = parser_context
             self._data = Empty
             self._files = Empty
    +        self._full_data = Empty
             self._method = Empty
             self._content_type = Empty
             self._stream = Empty
    @@ -186,12 +203,30 @@ class Request(object):
             return self._stream
     
         @property
    -    def QUERY_PARAMS(self):
    +    def query_params(self):
             """
             More semantically correct name for request.GET.
             """
             return self._request.GET
     
    +    @property
    +    def QUERY_PARAMS(self):
    +        """
    +        Synonym for `.query_params`, for backwards compatibility.
    +        """
    +        warnings.warn(
    +            "`request.QUERY_PARAMS` is pending deprecation. Use `request.query_params` instead.",
    +            PendingDeprecationWarning,
    +            stacklevel=1
    +        )
    +        return self._request.GET
    +
    +    @property
    +    def data(self):
    +        if not _hasattr(self, '_full_data'):
    +            self._load_data_and_files()
    +        return self._full_data
    +
         @property
         def DATA(self):
             """
    @@ -200,6 +235,11 @@ class Request(object):
             Similar to usual behaviour of `request.POST`, except that it handles
             arbitrary parsers, and also works on methods other than POST (eg PUT).
             """
    +        warnings.warn(
    +            "`request.DATA` is pending deprecation. Use `request.data` instead.",
    +            PendingDeprecationWarning,
    +            stacklevel=1
    +        )
             if not _hasattr(self, '_data'):
                 self._load_data_and_files()
             return self._data
    @@ -212,6 +252,11 @@ class Request(object):
             Similar to usual behaviour of `request.FILES`, except that it handles
             arbitrary parsers, and also works on methods other than POST (eg PUT).
             """
    +        warnings.warn(
    +            "`request.FILES` is pending deprecation. Use `request.data` instead.",
    +            PendingDeprecationWarning,
    +            stacklevel=1
    +        )
             if not _hasattr(self, '_files'):
                 self._load_data_and_files()
             return self._files
    @@ -272,6 +317,10 @@ class Request(object):
     
             if not _hasattr(self, '_data'):
                 self._data, self._files = self._parse()
    +            if self._files:
    +                self._full_data = MergeDict(self._data, self._files)
    +            else:
    +                self._full_data = self._data
     
         def _load_method_and_content_type(self):
             """
    @@ -333,6 +382,7 @@ class Request(object):
             # At this point we're committed to parsing the request as form data.
             self._data = self._request.POST
             self._files = self._request.FILES
    +        self._full_data = MergeDict(self._data, self._files)
     
             # Method overloading - change the method and remove the param from the content.
             if (
    @@ -350,7 +400,7 @@ class Request(object):
             ):
                 self._content_type = self._data[self._CONTENTTYPE_PARAM]
                 self._stream = BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding']))
    -            self._data, self._files = (Empty, Empty)
    +            self._data, self._files, self._full_data = (Empty, Empty, Empty)
     
         def _parse(self):
             """
    @@ -380,6 +430,7 @@ class Request(object):
                 # logging the request or similar.
                 self._data = QueryDict('', encoding=self._request._encoding)
                 self._files = MultiValueDict()
    +            self._full_data = self._data
                 raise
     
             # Parser classes may return the raw data, or a
    diff --git a/rest_framework/reverse.py b/rest_framework/reverse.py
    index a51b07f54..a74e8aa2d 100644
    --- a/rest_framework/reverse.py
    +++ b/rest_framework/reverse.py
    @@ -3,6 +3,7 @@ Provide reverse functions that return fully qualified URLs
     """
     from __future__ import unicode_literals
     from django.core.urlresolvers import reverse as django_reverse
    +from django.utils import six
     from django.utils.functional import lazy
     
     
    @@ -20,4 +21,4 @@ def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra
         return url
     
     
    -reverse_lazy = lazy(reverse, str)
    +reverse_lazy = lazy(reverse, six.text_type)
    diff --git a/rest_framework/routers.py b/rest_framework/routers.py
    index f2d062118..6e99f14de 100644
    --- a/rest_framework/routers.py
    +++ b/rest_framework/routers.py
    @@ -21,6 +21,7 @@ from django.conf.urls import patterns, url
     from django.core.exceptions import ImproperlyConfigured
     from django.core.urlresolvers import NoReverseMatch
     from rest_framework import views
    +from rest_framework.compat import OrderedDict
     from rest_framework.response import Response
     from rest_framework.reverse import reverse
     from rest_framework.urlpatterns import format_suffix_patterns
    @@ -277,7 +278,7 @@ class DefaultRouter(SimpleRouter):
             """
             Return a view to use as the API root.
             """
    -        api_root_dict = {}
    +        api_root_dict = OrderedDict()
             list_name = self.routes[0].name
             for prefix, viewset, basename in self.registry:
                 api_root_dict[prefix] = list_name.format(basename=basename)
    @@ -286,7 +287,7 @@ class DefaultRouter(SimpleRouter):
                 _ignore_model_permissions = True
     
                 def get(self, request, *args, **kwargs):
    -                ret = {}
    +                ret = OrderedDict()
                     for key, url_name in api_root_dict.items():
                         try:
                             ret[key] = reverse(
    diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
    index b3db35823..00362dbb4 100644
    --- a/rest_framework/serializers.py
    +++ b/rest_framework/serializers.py
    @@ -10,21 +10,31 @@ python primitives.
     2. The process of marshalling between python primitives and request and
     response content is handled by parsers and renderers.
     """
    -from __future__ import unicode_literals
    -import copy
    -import datetime
    -import inspect
    -import types
    -from decimal import Decimal
    -from django.contrib.contenttypes.generic import GenericForeignKey
    -from django.core.paginator import Page
    +from django.core.exceptions import ImproperlyConfigured
     from django.db import models
    -from django.forms import widgets
    +from django.db.models.fields import FieldDoesNotExist
     from django.utils import six
    -from django.utils.datastructures import SortedDict
    -from django.core.exceptions import ObjectDoesNotExist
    +from django.utils.translation import ugettext_lazy as _
    +from rest_framework.compat import OrderedDict
    +from rest_framework.exceptions import ValidationError
    +from rest_framework.fields import empty, set_value, Field, SkipField
     from rest_framework.settings import api_settings
    -
    +from rest_framework.utils import html, model_meta, representation
    +from rest_framework.utils.field_mapping import (
    +    get_url_kwargs, get_field_kwargs,
    +    get_relation_kwargs, get_nested_relation_kwargs,
    +    ClassLookupDict
    +)
    +from rest_framework.utils.serializer_helpers import (
    +    ReturnDict, ReturnList, BoundField, NestedBoundField, BindingDict
    +)
    +from rest_framework.validators import (
    +    UniqueForDateValidator, UniqueForMonthValidator, UniqueForYearValidator,
    +    UniqueTogetherValidator
    +)
    +import copy
    +import inspect
    +import warnings
     
     # Note: We do the following so that users of the framework can use this style:
     #
    @@ -37,1123 +47,918 @@ from rest_framework.relations import *  # NOQA
     from rest_framework.fields import *  # NOQA
     
     
    -def _resolve_model(obj):
    +# We assume that 'validators' are intended for the child serializer,
    +# rather than the parent serializer.
    +LIST_SERIALIZER_KWARGS = (
    +    'read_only', 'write_only', 'required', 'default', 'initial', 'source',
    +    'label', 'help_text', 'style', 'error_messages',
    +    'instance', 'data', 'partial', 'context'
    +)
    +
    +
    +# BaseSerializer
    +# --------------
    +
    +class BaseSerializer(Field):
         """
    -    Resolve supplied `obj` to a Django model class.
    -
    -    `obj` must be a Django model class itself, or a string
    -    representation of one.  Useful in situtations like GH #1225 where
    -    Django may not have resolved a string-based reference to a model in
    -    another model's foreign key definition.
    -
    -    String representations should have the format:
    -        'appname.ModelName'
    +    The BaseSerializer class provides a minimal class which may be used
    +    for writing custom serializer implementations.
         """
    -    if isinstance(obj, six.string_types) and len(obj.split('.')) == 2:
    -        app_name, model_name = obj.split('.')
    -        return models.get_model(app_name, model_name)
    -    elif inspect.isclass(obj) and issubclass(obj, models.Model):
    -        return obj
    -    else:
    -        raise ValueError("{0} is not a Django model".format(obj))
    -
    -
    -def pretty_name(name):
    -    """Converts 'first_name' to 'First name'"""
    -    if not name:
    -        return ''
    -    return name.replace('_', ' ').capitalize()
    -
    -
    -class RelationsList(list):
    -    _deleted = []
    -
    -
    -class NestedValidationError(ValidationError):
    -    """
    -    The default ValidationError behavior is to stringify each item in the list
    -    if the messages are a list of error messages.
    -
    -    In the case of nested serializers, where the parent has many children,
    -    then the child's `serializer.errors` will be a list of dicts.  In the case
    -    of a single child, the `serializer.errors` will be a dict.
    -
    -    We need to override the default behavior to get properly nested error dicts.
    -    """
    -
    -    def __init__(self, message):
    -        if isinstance(message, dict):
    -            self._messages = [message]
    -        else:
    -            self._messages = message
    -
    -    @property
    -    def messages(self):
    -        return self._messages
    -
    -
    -class DictWithMetadata(dict):
    -    """
    -    A dict-like object, that can have additional properties attached.
    -    """
    -    def __getstate__(self):
    -        """
    -        Used by pickle (e.g., caching).
    -        Overridden to remove the metadata from the dict, since it shouldn't be
    -        pickled and may in some instances be unpickleable.
    -        """
    -        return dict(self)
    -
    -
    -class SortedDictWithMetadata(SortedDict):
    -    """
    -    A sorted dict-like object, that can have additional properties attached.
    -    """
    -    def __getstate__(self):
    -        """
    -        Used by pickle (e.g., caching).
    -        Overriden to remove the metadata from the dict, since it shouldn't be
    -        pickle and may in some instances be unpickleable.
    -        """
    -        return SortedDict(self).__dict__
    -
    -
    -def _is_protected_type(obj):
    -    """
    -    True if the object is a native datatype that does not need to
    -    be serialized further.
    -    """
    -    return isinstance(obj, (
    -        types.NoneType,
    -        int, long,
    -        datetime.datetime, datetime.date, datetime.time,
    -        float, Decimal,
    -        basestring)
    -    )
    -
    -
    -def _get_declared_fields(bases, attrs):
    -    """
    -    Create a list of serializer field instances from the passed in 'attrs',
    -    plus any fields on the base classes (in 'bases').
    -
    -    Note that all fields from the base classes are used.
    -    """
    -    fields = [(field_name, attrs.pop(field_name))
    -              for field_name, obj in list(six.iteritems(attrs))
    -              if isinstance(obj, Field)]
    -    fields.sort(key=lambda x: x[1].creation_counter)
    -
    -    # If this class is subclassing another Serializer, add that Serializer's
    -    # fields.  Note that we loop over the bases in *reverse*. This is necessary
    -    # in order to maintain the correct order of fields.
    -    for base in bases[::-1]:
    -        if hasattr(base, 'base_fields'):
    -            fields = list(base.base_fields.items()) + fields
    -
    -    return SortedDict(fields)
    -
    -
    -class SerializerMetaclass(type):
    -    def __new__(cls, name, bases, attrs):
    -        attrs['base_fields'] = _get_declared_fields(bases, attrs)
    -        return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs)
    -
    -
    -class SerializerOptions(object):
    -    """
    -    Meta class options for Serializer
    -    """
    -    def __init__(self, meta):
    -        self.depth = getattr(meta, 'depth', 0)
    -        self.fields = getattr(meta, 'fields', ())
    -        self.exclude = getattr(meta, 'exclude', ())
    -
    -
    -class BaseSerializer(WritableField):
    -    """
    -    This is the Serializer implementation.
    -    We need to implement it as `BaseSerializer` due to metaclass magicks.
    -    """
    -    class Meta(object):
    -        pass
    -
    -    _options_class = SerializerOptions
    -    _dict_class = SortedDictWithMetadata
    -
    -    def __init__(self, instance=None, data=None, files=None,
    -                 context=None, partial=False, many=False,
    -                 allow_add_remove=False, **kwargs):
    +    def __init__(self, instance=None, data=None, **kwargs):
    +        self.instance = instance
    +        self._initial_data = data
    +        self.partial = kwargs.pop('partial', False)
    +        self._context = kwargs.pop('context', {})
    +        kwargs.pop('many', None)
             super(BaseSerializer, self).__init__(**kwargs)
    -        self.opts = self._options_class(self.Meta)
    -        self.parent = None
    -        self.root = None
    -        self.partial = partial
    -        self.many = many
    -        self.allow_add_remove = allow_add_remove
     
    -        self.context = context or {}
    +    def __new__(cls, *args, **kwargs):
    +        # We override this method in order to automagically create
    +        # `ListSerializer` classes instead when `many=True` is set.
    +        if kwargs.pop('many', False):
    +            return cls.many_init(*args, **kwargs)
    +        return super(BaseSerializer, cls).__new__(cls, *args, **kwargs)
     
    -        self.init_data = data
    -        self.init_files = files
    -        self.object = instance
    -        self.fields = self.get_fields()
    -
    -        self._data = None
    -        self._files = None
    -        self._errors = None
    -
    -        if many and instance is not None and not hasattr(instance, '__iter__'):
    -            raise ValueError('instance should be a queryset or other iterable with many=True')
    -
    -        if allow_add_remove and not many:
    -            raise ValueError('allow_add_remove should only be used for bulk updates, but you have not set many=True')
    -
    -    #####
    -    # Methods to determine which fields to use when (de)serializing objects.
    -
    -    def get_default_fields(self):
    +    @classmethod
    +    def many_init(cls, *args, **kwargs):
             """
    -        Return the complete set of default fields for the object, as a dict.
    +        This method implements the creation of a `ListSerializer` parent
    +        class when `many=True` is used. You can customize it if you need to
    +        control which keyword arguments are passed to the parent, and
    +        which are passed to the child.
    +
    +        Note that we're over-cautious in passing most arguments to both parent
    +        and child classes in order to try to cover the general case. If you're
    +        overriding this method you'll probably want something much simpler, eg:
    +
    +        @classmethod
    +        def many_init(cls, *args, **kwargs):
    +            kwargs['child'] = cls()
    +            return CustomListSerializer(*args, **kwargs)
             """
    -        return {}
    +        child_serializer = cls(*args, **kwargs)
    +        list_kwargs = {'child': child_serializer}
    +        list_kwargs.update(dict([
    +            (key, value) for key, value in kwargs.items()
    +            if key in LIST_SERIALIZER_KWARGS
    +        ]))
    +        return ListSerializer(*args, **list_kwargs)
     
    -    def get_fields(self):
    -        """
    -        Returns the complete set of fields for the object as a dict.
    +    def to_internal_value(self, data):
    +        raise NotImplementedError('`to_internal_value()` must be implemented.')
     
    -        This will be the set of any explicitly declared fields,
    -        plus the set of fields returned by get_default_fields().
    -        """
    -        ret = SortedDict()
    +    def to_representation(self, instance):
    +        raise NotImplementedError('`to_representation()` must be implemented.')
     
    -        # Get the explicitly declared fields
    -        base_fields = copy.deepcopy(self.base_fields)
    -        for key, field in base_fields.items():
    -            ret[key] = field
    +    def update(self, instance, validated_data):
    +        raise NotImplementedError('`update()` must be implemented.')
     
    -        # Add in the default fields
    -        default_fields = self.get_default_fields()
    -        for key, val in default_fields.items():
    -            if key not in ret:
    -                ret[key] = val
    +    def create(self, validated_data):
    +        raise NotImplementedError('`create()` must be implemented.')
     
    -        # If 'fields' is specified, use those fields, in that order.
    -        if self.opts.fields:
    -            assert isinstance(self.opts.fields, (list, tuple)), '`fields` must be a list or tuple'
    -            new = SortedDict()
    -            for key in self.opts.fields:
    -                new[key] = ret[key]
    -            ret = new
    +    def save(self, **kwargs):
    +        assert not hasattr(self, 'save_object'), (
    +            'Serializer `%s.%s` has old-style version 2 `.save_object()` '
    +            'that is no longer compatible with REST framework 3. '
    +            'Use the new-style `.create()` and `.update()` methods instead.' %
    +            (self.__class__.__module__, self.__class__.__name__)
    +        )
     
    -        # Remove anything in 'exclude'
    -        if self.opts.exclude:
    -            assert isinstance(self.opts.exclude, (list, tuple)), '`exclude` must be a list or tuple'
    -            for key in self.opts.exclude:
    -                ret.pop(key, None)
    +        validated_data = dict(
    +            list(self.validated_data.items()) +
    +            list(kwargs.items())
    +        )
     
    -        for key, field in ret.items():
    -            field.initialize(parent=self, field_name=key)
    -
    -        return ret
    -
    -    #####
    -    # Methods to convert or revert from objects <--> primitive representations.
    -
    -    def get_field_key(self, field_name):
    -        """
    -        Return the key that should be used for a given field.
    -        """
    -        return field_name
    -
    -    def restore_fields(self, data, files):
    -        """
    -        Core of deserialization, together with `restore_object`.
    -        Converts a dictionary of data into a dictionary of deserialized fields.
    -        """
    -        reverted_data = {}
    -
    -        if data is not None and not isinstance(data, dict):
    -            self._errors['non_field_errors'] = ['Invalid data']
    -            return None
    -
    -        for field_name, field in self.fields.items():
    -            field.initialize(parent=self, field_name=field_name)
    -            try:
    -                field.field_from_native(data, files, field_name, reverted_data)
    -            except ValidationError as err:
    -                self._errors[field_name] = list(err.messages)
    -
    -        return reverted_data
    -
    -    def perform_validation(self, attrs):
    -        """
    -        Run `validate_()` and `validate()` methods on the serializer
    -        """
    -        for field_name, field in self.fields.items():
    -            if field_name in self._errors:
    -                continue
    -
    -            source = field.source or field_name
    -            if self.partial and source not in attrs:
    -                continue
    -            try:
    -                validate_method = getattr(self, 'validate_%s' % field_name, None)
    -                if validate_method:
    -                    attrs = validate_method(attrs, source)
    -            except ValidationError as err:
    -                self._errors[field_name] = self._errors.get(field_name, []) + list(err.messages)
    -
    -        # If there are already errors, we don't run .validate() because
    -        # field-validation failed and thus `attrs` may not be complete.
    -        # which in turn can cause inconsistent validation errors.
    -        if not self._errors:
    -            try:
    -                attrs = self.validate(attrs)
    -            except ValidationError as err:
    -                if hasattr(err, 'message_dict'):
    -                    for field_name, error_messages in err.message_dict.items():
    -                        self._errors[field_name] = self._errors.get(field_name, []) + list(error_messages)
    -                elif hasattr(err, 'messages'):
    -                    self._errors['non_field_errors'] = err.messages
    -
    -        return attrs
    -
    -    def validate(self, attrs):
    -        """
    -        Stub method, to be overridden in Serializer subclasses
    -        """
    -        return attrs
    -
    -    def restore_object(self, attrs, instance=None):
    -        """
    -        Deserialize a dictionary of attributes into an object instance.
    -        You should override this method to control how deserialized objects
    -        are instantiated.
    -        """
    -        if instance is not None:
    -            instance.update(attrs)
    -            return instance
    -        return attrs
    -
    -    def to_native(self, obj):
    -        """
    -        Serialize objects -> primitives.
    -        """
    -        ret = self._dict_class()
    -        ret.fields = self._dict_class()
    -
    -        for field_name, field in self.fields.items():
    -            if field.read_only and obj is None:
    -                continue
    -            field.initialize(parent=self, field_name=field_name)
    -            key = self.get_field_key(field_name)
    -            value = field.field_to_native(obj, field_name)
    -            method = getattr(self, 'transform_%s' % field_name, None)
    -            if callable(method):
    -                value = method(obj, value)
    -            if not getattr(field, 'write_only', False):
    -                ret[key] = value
    -            ret.fields[key] = self.augment_field(field, field_name, key, value)
    -
    -        return ret
    -
    -    def from_native(self, data, files=None):
    -        """
    -        Deserialize primitives -> objects.
    -        """
    -        self._errors = {}
    -
    -        if data is not None or files is not None:
    -            attrs = self.restore_fields(data, files)
    -            if attrs is not None:
    -                attrs = self.perform_validation(attrs)
    +        if self.instance is not None:
    +            self.instance = self.update(self.instance, validated_data)
    +            assert self.instance is not None, (
    +                '`update()` did not return an object instance.'
    +            )
             else:
    -            self._errors['non_field_errors'] = ['No input provided']
    +            self.instance = self.create(validated_data)
    +            assert self.instance is not None, (
    +                '`create()` did not return an object instance.'
    +            )
     
    -        if not self._errors:
    -            return self.restore_object(attrs, instance=getattr(self, 'object', None))
    +        return self.instance
     
    -    def augment_field(self, field, field_name, key, value):
    -        # This horrible stuff is to manage serializers rendering to HTML
    -        field._errors = self._errors.get(key) if self._errors else None
    -        field._name = field_name
    -        field._value = self.init_data.get(key) if self._errors and self.init_data else value
    -        if not field.label:
    -            field.label = pretty_name(key)
    -        return field
    +    def is_valid(self, raise_exception=False):
    +        assert not hasattr(self, 'restore_object'), (
    +            'Serializer `%s.%s` has old-style version 2 `.restore_object()` '
    +            'that is no longer compatible with REST framework 3. '
    +            'Use the new-style `.create()` and `.update()` methods instead.' %
    +            (self.__class__.__module__, self.__class__.__name__)
    +        )
     
    -    def field_to_native(self, obj, field_name):
    -        """
    -        Override default so that the serializer can be used as a nested field
    -        across relationships.
    -        """
    -        if self.write_only:
    -            return None
    -
    -        if self.source == '*':
    -            return self.to_native(obj)
    -
    -        # Get the raw field value
    -        try:
    -            source = self.source or field_name
    -            value = obj
    -
    -            for component in source.split('.'):
    -                if value is None:
    -                    break
    -                value = get_component(value, component)
    -        except ObjectDoesNotExist:
    -            return None
    -
    -        if is_simple_callable(getattr(value, 'all', None)):
    -            return [self.to_native(item) for item in value.all()]
    -
    -        if value is None:
    -            return None
    -
    -        if self.many:
    -            return [self.to_native(item) for item in value]
    -        return self.to_native(value)
    -
    -    def field_from_native(self, data, files, field_name, into):
    -        """
    -        Override default so that the serializer can be used as a writable
    -        nested field across relationships.
    -        """
    -        if self.read_only:
    -            return
    -
    -        try:
    -            value = data[field_name]
    -        except KeyError:
    -            if self.default is not None and not self.partial:
    -                # Note: partial updates shouldn't set defaults
    -                value = copy.deepcopy(self.default)
    +        if not hasattr(self, '_validated_data'):
    +            try:
    +                self._validated_data = self.run_validation(self._initial_data)
    +            except ValidationError as exc:
    +                self._validated_data = {}
    +                self._errors = exc.detail
                 else:
    -                if self.required:
    -                    raise ValidationError(self.error_messages['required'])
    -                return
    +                self._errors = {}
     
    -        if self.source == '*':
    -            if value:
    -                reverted_data = self.restore_fields(value, {})
    -                if not self._errors:
    -                    into.update(reverted_data)
    -        else:
    -            if value in (None, ''):
    -                into[(self.source or field_name)] = None
    -            else:
    -                # Set the serializer object if it exists
    -                obj = get_component(self.parent.object, self.source or field_name) if self.parent.object else None
    +        if self._errors and raise_exception:
    +            raise ValidationError(self._errors)
     
    -                # If we have a model manager or similar object then we need
    -                # to iterate through each instance.
    -                if (
    -                    self.many and
    -                    not hasattr(obj, '__iter__') and
    -                    is_simple_callable(getattr(obj, 'all', None))
    -                ):
    -                    obj = obj.all()
    -
    -                kwargs = {
    -                    'instance': obj,
    -                    'data': value,
    -                    'context': self.context,
    -                    'partial': self.partial,
    -                    'many': self.many,
    -                    'allow_add_remove': self.allow_add_remove
    -                }
    -                serializer = self.__class__(**kwargs)
    -
    -                if serializer.is_valid():
    -                    into[self.source or field_name] = serializer.object
    -                else:
    -                    # Propagate errors up to our parent
    -                    raise NestedValidationError(serializer.errors)
    -
    -    def get_identity(self, data):
    -        """
    -        This hook is required for bulk update.
    -        It is used to determine the canonical identity of a given object.
    -
    -        Note that the data has not been validated at this point, so we need
    -        to make sure that we catch any cases of incorrect datatypes being
    -        passed to this method.
    -        """
    -        try:
    -            return data.get('id', None)
    -        except AttributeError:
    -            return None
    -
    -    @property
    -    def errors(self):
    -        """
    -        Run deserialization and return error data,
    -        setting self.object if no errors occurred.
    -        """
    -        if self._errors is None:
    -            data, files = self.init_data, self.init_files
    -
    -            if self.many is not None:
    -                many = self.many
    -            else:
    -                many = hasattr(data, '__iter__') and not isinstance(data, (Page, dict, six.text_type))
    -                if many:
    -                    warnings.warn('Implicit list/queryset serialization is deprecated. '
    -                                  'Use the `many=True` flag when instantiating the serializer.',
    -                                  DeprecationWarning, stacklevel=3)
    -
    -            if many:
    -                ret = RelationsList()
    -                errors = []
    -                update = self.object is not None
    -
    -                if update:
    -                    # If this is a bulk update we need to map all the objects
    -                    # to a canonical identity so we can determine which
    -                    # individual object is being updated for each item in the
    -                    # incoming data
    -                    objects = self.object
    -                    identities = [self.get_identity(self.to_native(obj)) for obj in objects]
    -                    identity_to_objects = dict(zip(identities, objects))
    -
    -                if hasattr(data, '__iter__') and not isinstance(data, (dict, six.text_type)):
    -                    for item in data:
    -                        if update:
    -                            # Determine which object we're updating
    -                            identity = self.get_identity(item)
    -                            self.object = identity_to_objects.pop(identity, None)
    -                            if self.object is None and not self.allow_add_remove:
    -                                ret.append(None)
    -                                errors.append({'non_field_errors': ['Cannot create a new item, only existing items may be updated.']})
    -                                continue
    -
    -                        ret.append(self.from_native(item, None))
    -                        errors.append(self._errors)
    -
    -                    if update and self.allow_add_remove:
    -                        ret._deleted = identity_to_objects.values()
    -
    -                    self._errors = any(errors) and errors or []
    -                else:
    -                    self._errors = {'non_field_errors': ['Expected a list of items.']}
    -            else:
    -                ret = self.from_native(data, files)
    -
    -            if not self._errors:
    -                self.object = ret
    -
    -        return self._errors
    -
    -    def is_valid(self):
    -        return not self.errors
    +        return not bool(self._errors)
     
         @property
         def data(self):
    -        """
    -        Returns the serialized data on the serializer.
    -        """
    -        if self._data is None:
    -            obj = self.object
    -
    -            if self.many is not None:
    -                many = self.many
    +        if not hasattr(self, '_data'):
    +            if self.instance is not None and not getattr(self, '_errors', None):
    +                self._data = self.to_representation(self.instance)
    +            elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
    +                self._data = self.to_representation(self.validated_data)
                 else:
    -                many = hasattr(obj, '__iter__') and not isinstance(obj, (Page, dict))
    -                if many:
    -                    warnings.warn('Implicit list/queryset serialization is deprecated. '
    -                                  'Use the `many=True` flag when instantiating the serializer.',
    -                                  DeprecationWarning, stacklevel=2)
    -
    -            if many:
    -                self._data = [self.to_native(item) for item in obj]
    -            else:
    -                self._data = self.to_native(obj)
    -
    +                self._data = self.get_initial()
             return self._data
     
    -    def save_object(self, obj, **kwargs):
    -        obj.save(**kwargs)
    +    @property
    +    def errors(self):
    +        if not hasattr(self, '_errors'):
    +            msg = 'You must call `.is_valid()` before accessing `.errors`.'
    +            raise AssertionError(msg)
    +        return self._errors
     
    -    def delete_object(self, obj):
    -        obj.delete()
    -
    -    def save(self, **kwargs):
    -        """
    -        Save the deserialized object and return it.
    -        """
    -        # Clear cached _data, which may be invalidated by `save()`
    -        self._data = None
    -
    -        if isinstance(self.object, list):
    -            [self.save_object(item, **kwargs) for item in self.object]
    -
    -            if self.object._deleted:
    -                [self.delete_object(item) for item in self.object._deleted]
    -        else:
    -            self.save_object(self.object, **kwargs)
    -
    -        return self.object
    -
    -    def metadata(self):
    -        """
    -        Return a dictionary of metadata about the fields on the serializer.
    -        Useful for things like responding to OPTIONS requests, or generating
    -        API schemas for auto-documentation.
    -        """
    -        return SortedDict(
    -            [
    -                (field_name, field.metadata())
    -                for field_name, field in six.iteritems(self.fields)
    -            ]
    -        )
    +    @property
    +    def validated_data(self):
    +        if not hasattr(self, '_validated_data'):
    +            msg = 'You must call `.is_valid()` before accessing `.validated_data`.'
    +            raise AssertionError(msg)
    +        return self._validated_data
     
     
    -class Serializer(six.with_metaclass(SerializerMetaclass, BaseSerializer)):
    -    pass
    +# Serializer & ListSerializer classes
    +# -----------------------------------
     
    -
    -class ModelSerializerOptions(SerializerOptions):
    +class SerializerMetaclass(type):
         """
    -    Meta class options for ModelSerializer
    +    This metaclass sets a dictionary named `base_fields` on the class.
    +
    +    Any instances of `Field` included as attributes on either the class
    +    or on any of its superclasses will be include in the
    +    `base_fields` dictionary.
         """
    -    def __init__(self, meta):
    -        super(ModelSerializerOptions, self).__init__(meta)
    -        self.model = getattr(meta, 'model', None)
    -        self.read_only_fields = getattr(meta, 'read_only_fields', ())
    -        self.write_only_fields = getattr(meta, 'write_only_fields', ())
    +
    +    @classmethod
    +    def _get_declared_fields(cls, bases, attrs):
    +        fields = [(field_name, attrs.pop(field_name))
    +                  for field_name, obj in list(attrs.items())
    +                  if isinstance(obj, Field)]
    +        fields.sort(key=lambda x: x[1]._creation_counter)
    +
    +        # If this class is subclassing another Serializer, add that Serializer's
    +        # fields.  Note that we loop over the bases in *reverse*. This is necessary
    +        # in order to maintain the correct order of fields.
    +        for base in bases[::-1]:
    +            if hasattr(base, '_declared_fields'):
    +                fields = list(base._declared_fields.items()) + fields
    +
    +        return OrderedDict(fields)
    +
    +    def __new__(cls, name, bases, attrs):
    +        attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
    +        return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs)
     
     
    -def _get_class_mapping(mapping, obj):
    -    """
    -    Takes a dictionary with classes as keys, and an object.
    -    Traverses the object's inheritance hierarchy in method
    -    resolution order, and returns the first matching value
    -    from the dictionary or None.
    -
    -    """
    -    return next(
    -        (mapping[cls] for cls in inspect.getmro(obj.__class__) if cls in mapping),
    -        None
    -    )
    -
    -
    -class ModelSerializer(Serializer):
    -    """
    -    A serializer that deals with model instances and querysets.
    -    """
    -    _options_class = ModelSerializerOptions
    -
    -    field_mapping = {
    -        models.AutoField: IntegerField,
    -        models.FloatField: FloatField,
    -        models.IntegerField: IntegerField,
    -        models.PositiveIntegerField: IntegerField,
    -        models.SmallIntegerField: IntegerField,
    -        models.PositiveSmallIntegerField: IntegerField,
    -        models.DateTimeField: DateTimeField,
    -        models.DateField: DateField,
    -        models.TimeField: TimeField,
    -        models.DecimalField: DecimalField,
    -        models.EmailField: EmailField,
    -        models.CharField: CharField,
    -        models.URLField: URLField,
    -        models.SlugField: SlugField,
    -        models.TextField: CharField,
    -        models.CommaSeparatedIntegerField: CharField,
    -        models.BooleanField: BooleanField,
    -        models.NullBooleanField: BooleanField,
    -        models.FileField: FileField,
    -        models.ImageField: ImageField,
    +@six.add_metaclass(SerializerMetaclass)
    +class Serializer(BaseSerializer):
    +    default_error_messages = {
    +        'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')
         }
     
    -    def get_default_fields(self):
    +    @property
    +    def fields(self):
             """
    -        Return all the fields that should be serialized for the model.
    +        A dictionary of {field_name: field_instance}.
             """
    +        # `fields` is evalutated lazily. We do this to ensure that we don't
    +        # have issues importing modules that use ModelSerializers as fields,
    +        # even if Django's app-loading stage has not yet run.
    +        if not hasattr(self, '_fields'):
    +            self._fields = BindingDict(self)
    +            for key, value in self.get_fields().items():
    +                self._fields[key] = value
    +        return self._fields
     
    -        cls = self.opts.model
    -        assert cls is not None, (
    -            "Serializer class '%s' is missing 'model' Meta option" %
    -            self.__class__.__name__
    -        )
    -        opts = cls._meta.concrete_model._meta
    -        ret = SortedDict()
    -        nested = bool(self.opts.depth)
    +    def get_fields(self):
    +        """
    +        Returns a dictionary of {field_name: field_instance}.
    +        """
    +        # Every new serializer is created with a clone of the field instances.
    +        # This allows users to dynamically modify the fields on a serializer
    +        # instance without affecting every other serializer class.
    +        return copy.deepcopy(self._declared_fields)
     
    -        # Deal with adding the primary key field
    -        pk_field = opts.pk
    -        while pk_field.rel and pk_field.rel.parent_link:
    -            # If model is a child via multitable inheritance, use parent's pk
    -            pk_field = pk_field.rel.to._meta.pk
    +    def get_validators(self):
    +        """
    +        Returns a list of validator callables.
    +        """
    +        # Used by the lazily-evaluated `validators` property.
    +        return getattr(getattr(self, 'Meta', None), 'validators', [])
     
    -        serializer_pk_field = self.get_pk_field(pk_field)
    -        if serializer_pk_field:
    -            ret[pk_field.name] = serializer_pk_field
    +    def get_initial(self):
    +        if self._initial_data is not None:
    +            return OrderedDict([
    +                (field_name, field.get_value(self._initial_data))
    +                for field_name, field in self.fields.items()
    +                if field.get_value(self._initial_data) is not empty
    +                and not field.read_only
    +            ])
     
    -        # Deal with forward relationships
    -        forward_rels = [field for field in opts.fields if field.serialize]
    -        forward_rels += [field for field in opts.many_to_many if field.serialize]
    +        return OrderedDict([
    +            (field.field_name, field.get_initial())
    +            for field in self.fields.values()
    +            if not field.read_only
    +        ])
     
    -        for model_field in forward_rels:
    -            has_through_model = False
    +    def get_value(self, dictionary):
    +        # We override the default field access in order to support
    +        # nested HTML forms.
    +        if html.is_html_input(dictionary):
    +            return html.parse_html_dict(dictionary, prefix=self.field_name)
    +        return dictionary.get(self.field_name, empty)
     
    -            if model_field.rel:
    -                to_many = isinstance(model_field,
    -                                     models.fields.related.ManyToManyField)
    -                related_model = _resolve_model(model_field.rel.to)
    +    def run_validation(self, data=empty):
    +        """
    +        We override the default `run_validation`, because the validation
    +        performed by validators and the `.validate()` method should
    +        be coerced into an error dictionary with a 'non_fields_error' key.
    +        """
    +        if data is empty:
    +            if getattr(self.root, 'partial', False):
    +                raise SkipField()
    +            if self.required:
    +                self.fail('required')
    +            return self.get_default()
     
    -                if to_many and not model_field.rel.through._meta.auto_created:
    -                    has_through_model = True
    +        if data is None:
    +            if not self.allow_null:
    +                self.fail('null')
    +            return None
     
    -            if model_field.rel and nested:
    -                if len(inspect.getargspec(self.get_nested_field).args) == 2:
    -                    warnings.warn(
    -                        'The `get_nested_field(model_field)` call signature '
    -                        'is deprecated. '
    -                        'Use `get_nested_field(model_field, related_model, '
    -                        'to_many) instead',
    -                        DeprecationWarning
    -                    )
    -                    field = self.get_nested_field(model_field)
    -                else:
    -                    field = self.get_nested_field(model_field, related_model, to_many)
    -            elif model_field.rel:
    -                if len(inspect.getargspec(self.get_nested_field).args) == 3:
    -                    warnings.warn(
    -                        'The `get_related_field(model_field, to_many)` call '
    -                        'signature is deprecated. '
    -                        'Use `get_related_field(model_field, related_model, '
    -                        'to_many) instead',
    -                        DeprecationWarning
    -                    )
    -                    field = self.get_related_field(model_field, to_many=to_many)
    -                else:
    -                    field = self.get_related_field(model_field, related_model, to_many)
    +        if not isinstance(data, dict):
    +            message = self.error_messages['invalid'].format(
    +                datatype=type(data).__name__
    +            )
    +            raise ValidationError({
    +                api_settings.NON_FIELD_ERRORS_KEY: [message]
    +            })
    +
    +        value = self.to_internal_value(data)
    +        try:
    +            self.run_validators(value)
    +            value = self.validate(value)
    +            assert value is not None, '.validate() should return the validated data'
    +        except ValidationError as exc:
    +            if isinstance(exc.detail, dict):
    +                # .validate() errors may be a dict, in which case, use
    +                # standard {key: list of values} style.
    +                raise ValidationError(dict([
    +                    (key, value if isinstance(value, list) else [value])
    +                    for key, value in exc.detail.items()
    +                ]))
    +            elif isinstance(exc.detail, list):
    +                raise ValidationError({
    +                    api_settings.NON_FIELD_ERRORS_KEY: exc.detail
    +                })
                 else:
    -                field = self.get_field(model_field)
    +                raise ValidationError({
    +                    api_settings.NON_FIELD_ERRORS_KEY: [exc.detail]
    +                })
     
    -            if field:
    -                if has_through_model:
    -                    field.read_only = True
    +        return value
     
    -                ret[model_field.name] = field
    +    def to_internal_value(self, data):
    +        """
    +        Dict of native values <- Dict of primitive datatypes.
    +        """
    +        ret = OrderedDict()
    +        errors = OrderedDict()
    +        fields = [
    +            field for field in self.fields.values()
    +            if (not field.read_only) or (field.default is not empty)
    +        ]
     
    -        # Deal with reverse relationships
    -        if not self.opts.fields:
    -            reverse_rels = []
    -        else:
    -            # Reverse relationships are only included if they are explicitly
    -            # present in the `fields` option on the serializer
    -            reverse_rels = opts.get_all_related_objects()
    -            reverse_rels += opts.get_all_related_many_to_many_objects()
    -
    -        for relation in reverse_rels:
    -            accessor_name = relation.get_accessor_name()
    -            if not self.opts.fields or accessor_name not in self.opts.fields:
    -                continue
    -            related_model = relation.model
    -            to_many = relation.field.rel.multiple
    -            has_through_model = False
    -            is_m2m = isinstance(relation.field,
    -                                models.fields.related.ManyToManyField)
    -
    -            if (
    -                is_m2m and
    -                hasattr(relation.field.rel, 'through') and
    -                not relation.field.rel.through._meta.auto_created
    -            ):
    -                has_through_model = True
    -
    -            if nested:
    -                field = self.get_nested_field(None, related_model, to_many)
    +        for field in fields:
    +            validate_method = getattr(self, 'validate_' + field.field_name, None)
    +            primitive_value = field.get_value(data)
    +            try:
    +                validated_value = field.run_validation(primitive_value)
    +                if validate_method is not None:
    +                    validated_value = validate_method(validated_value)
    +            except ValidationError as exc:
    +                errors[field.field_name] = exc.detail
    +            except SkipField:
    +                pass
                 else:
    -                field = self.get_related_field(None, related_model, to_many)
    +                set_value(ret, field.source_attrs, validated_value)
     
    -            if field:
    -                if has_through_model:
    -                    field.read_only = True
    -
    -                ret[accessor_name] = field
    -
    -        # Ensure that 'read_only_fields' is an iterable
    -        assert isinstance(self.opts.read_only_fields, (list, tuple)), '`read_only_fields` must be a list or tuple'
    -
    -        # Add the `read_only` flag to any fields that have been specified
    -        # in the `read_only_fields` option
    -        for field_name in self.opts.read_only_fields:
    -            assert field_name not in self.base_fields.keys(), (
    -                "field '%s' on serializer '%s' specified in "
    -                "`read_only_fields`, but also added "
    -                "as an explicit field.  Remove it from `read_only_fields`." %
    -                (field_name, self.__class__.__name__))
    -            assert field_name in ret, (
    -                "Non-existant field '%s' specified in `read_only_fields` "
    -                "on serializer '%s'." %
    -                (field_name, self.__class__.__name__))
    -            ret[field_name].read_only = True
    -
    -        # Ensure that 'write_only_fields' is an iterable
    -        assert isinstance(self.opts.write_only_fields, (list, tuple)), '`write_only_fields` must be a list or tuple'
    -
    -        for field_name in self.opts.write_only_fields:
    -            assert field_name not in self.base_fields.keys(), (
    -                "field '%s' on serializer '%s' specified in "
    -                "`write_only_fields`, but also added "
    -                "as an explicit field.  Remove it from `write_only_fields`." %
    -                (field_name, self.__class__.__name__))
    -            assert field_name in ret, (
    -                "Non-existant field '%s' specified in `write_only_fields` "
    -                "on serializer '%s'." %
    -                (field_name, self.__class__.__name__))
    -            ret[field_name].write_only = True
    +        if errors:
    +            raise ValidationError(errors)
     
             return ret
     
    -    def get_pk_field(self, model_field):
    +    def to_representation(self, instance):
             """
    -        Returns a default instance of the pk field.
    +        Object instance -> Dict of primitive datatypes.
             """
    -        return self.get_field(model_field)
    +        ret = OrderedDict()
    +        fields = [field for field in self.fields.values() if not field.write_only]
     
    -    def get_nested_field(self, model_field, related_model, to_many):
    +        for field in fields:
    +            attribute = field.get_attribute(instance)
    +            if attribute is None:
    +                value = None
    +            else:
    +                value = field.to_representation(attribute)
    +            transform_method = getattr(self, 'transform_' + field.field_name, None)
    +            if transform_method is not None:
    +                value = transform_method(value)
    +
    +            ret[field.field_name] = value
    +
    +        return ret
    +
    +    def validate(self, attrs):
    +        return attrs
    +
    +    def __repr__(self):
    +        return representation.serializer_repr(self, indent=1)
    +
    +    # The following are used for accessing `BoundField` instances on the
    +    # serializer, for the purposes of presenting a form-like API onto the
    +    # field values and field errors.
    +
    +    def __iter__(self):
    +        for field in self.fields.values():
    +            yield self[field.field_name]
    +
    +    def __getitem__(self, key):
    +        field = self.fields[key]
    +        value = self.data.get(key)
    +        error = self.errors.get(key) if hasattr(self, '_errors') else None
    +        if isinstance(field, Serializer):
    +            return NestedBoundField(field, value, error)
    +        return BoundField(field, value, error)
    +
    +    # Include a backlink to the serializer class on return objects.
    +    # Allows renderers such as HTMLFormRenderer to get the full field info.
    +
    +    @property
    +    def data(self):
    +        ret = super(Serializer, self).data
    +        return ReturnDict(ret, serializer=self)
    +
    +    @property
    +    def errors(self):
    +        ret = super(Serializer, self).errors
    +        return ReturnDict(ret, serializer=self)
    +
    +
    +# There's some replication of `ListField` here,
    +# but that's probably better than obfuscating the call hierarchy.
    +
    +class ListSerializer(BaseSerializer):
    +    child = None
    +    many = True
    +
    +    default_error_messages = {
    +        'not_a_list': _('Expected a list of items but got type `{input_type}`.')
    +    }
    +
    +    def __init__(self, *args, **kwargs):
    +        self.child = kwargs.pop('child', copy.deepcopy(self.child))
    +        assert self.child is not None, '`child` is a required argument.'
    +        assert not inspect.isclass(self.child), '`child` has not been instantiated.'
    +        super(ListSerializer, self).__init__(*args, **kwargs)
    +        self.child.bind(field_name='', parent=self)
    +
    +    def get_initial(self):
    +        if self._initial_data is not None:
    +            return self.to_representation(self._initial_data)
    +        return []
    +
    +    def get_value(self, dictionary):
             """
    -        Creates a default instance of a nested relational field.
    -
    -        Note that model_field will be `None` for reverse relationships.
    +        Given the input dictionary, return the field value.
             """
    -        class NestedModelSerializer(ModelSerializer):
    -            class Meta:
    -                model = related_model
    -                depth = self.opts.depth - 1
    +        # We override the default field access in order to support
    +        # lists in HTML forms.
    +        if html.is_html_input(dictionary):
    +            return html.parse_html_list(dictionary, prefix=self.field_name)
    +        return dictionary.get(self.field_name, empty)
     
    -        return NestedModelSerializer(many=to_many)
    -
    -    def get_related_field(self, model_field, related_model, to_many):
    +    def to_internal_value(self, data):
             """
    -        Creates a default instance of a flat relational field.
    -
    -        Note that model_field will be `None` for reverse relationships.
    +        List of dicts of native values <- List of dicts of primitive datatypes.
             """
    -        # TODO: filter queryset using:
    -        # .using(db).complex_filter(self.rel.limit_choices_to)
    +        if html.is_html_input(data):
    +            data = html.parse_html_list(data)
     
    -        kwargs = {
    -            'queryset': related_model._default_manager,
    -            'many': to_many
    -        }
    +        if not isinstance(data, list):
    +            message = self.error_messages['not_a_list'].format(
    +                input_type=type(data).__name__
    +            )
    +            raise ValidationError({
    +                api_settings.NON_FIELD_ERRORS_KEY: [message]
    +            })
     
    -        if model_field:
    -            kwargs['required'] = not(model_field.null or model_field.blank)
    -            if model_field.help_text is not None:
    -                kwargs['help_text'] = model_field.help_text
    -            if model_field.verbose_name is not None:
    -                kwargs['label'] = model_field.verbose_name
    +        ret = []
    +        errors = []
     
    -            if not model_field.editable:
    -                kwargs['read_only'] = True
    -
    -            if model_field.verbose_name is not None:
    -                kwargs['label'] = model_field.verbose_name
    -
    -            if model_field.help_text is not None:
    -                kwargs['help_text'] = model_field.help_text
    -
    -        return PrimaryKeyRelatedField(**kwargs)
    -
    -    def get_field(self, model_field):
    -        """
    -        Creates a default instance of a basic non-relational field.
    -        """
    -        kwargs = {}
    -
    -        if model_field.null or model_field.blank:
    -            kwargs['required'] = False
    -
    -        if isinstance(model_field, models.AutoField) or not model_field.editable:
    -            kwargs['read_only'] = True
    -
    -        if model_field.has_default():
    -            kwargs['default'] = model_field.get_default()
    -
    -        if issubclass(model_field.__class__, models.TextField):
    -            kwargs['widget'] = widgets.Textarea
    -
    -        if model_field.verbose_name is not None:
    -            kwargs['label'] = model_field.verbose_name
    -
    -        if model_field.help_text is not None:
    -            kwargs['help_text'] = model_field.help_text
    -
    -        # TODO: TypedChoiceField?
    -        if model_field.flatchoices:  # This ModelField contains choices
    -            kwargs['choices'] = model_field.flatchoices
    -            if model_field.null:
    -                kwargs['empty'] = None
    -            return ChoiceField(**kwargs)
    -
    -        # put this below the ChoiceField because min_value isn't a valid initializer
    -        if issubclass(model_field.__class__, models.PositiveIntegerField) or\
    -                issubclass(model_field.__class__, models.PositiveSmallIntegerField):
    -            kwargs['min_value'] = 0
    -
    -        if model_field.null and \
    -                issubclass(model_field.__class__, (models.CharField, models.TextField)):
    -            kwargs['allow_none'] = True
    -
    -        attribute_dict = {
    -            models.CharField: ['max_length'],
    -            models.CommaSeparatedIntegerField: ['max_length'],
    -            models.DecimalField: ['max_digits', 'decimal_places'],
    -            models.EmailField: ['max_length'],
    -            models.FileField: ['max_length'],
    -            models.ImageField: ['max_length'],
    -            models.SlugField: ['max_length'],
    -            models.URLField: ['max_length'],
    -        }
    -
    -        attributes = _get_class_mapping(attribute_dict, model_field)
    -        if attributes:
    -            for attribute in attributes:
    -                kwargs.update({attribute: getattr(model_field, attribute)})
    -
    -        serializer_field_class = _get_class_mapping(
    -            self.field_mapping, model_field)
    -
    -        if serializer_field_class:
    -            return serializer_field_class(**kwargs)
    -        return ModelField(model_field=model_field, **kwargs)
    -
    -    def get_validation_exclusions(self, instance=None):
    -        """
    -        Return a list of field names to exclude from model validation.
    -        """
    -        cls = self.opts.model
    -        opts = cls._meta.concrete_model._meta
    -        exclusions = [field.name for field in opts.fields + opts.many_to_many]
    -
    -        for field_name, field in self.fields.items():
    -            field_name = field.source or field_name
    -            if (
    -                field_name in exclusions
    -                and not field.read_only
    -                and (field.required or hasattr(instance, field_name))
    -                and not isinstance(field, Serializer)
    -            ):
    -                exclusions.remove(field_name)
    -        return exclusions
    -
    -    def full_clean(self, instance):
    -        """
    -        Perform Django's full_clean, and populate the `errors` dictionary
    -        if any validation errors occur.
    -
    -        Note that we don't perform this inside the `.restore_object()` method,
    -        so that subclasses can override `.restore_object()`, and still get
    -        the full_clean validation checking.
    -        """
    -        try:
    -            instance.full_clean(exclude=self.get_validation_exclusions(instance))
    -        except ValidationError as err:
    -            self._errors = err.message_dict
    -            return None
    -        return instance
    -
    -    def restore_object(self, attrs, instance=None):
    -        """
    -        Restore the model instance.
    -        """
    -        m2m_data = {}
    -        related_data = {}
    -        nested_forward_relations = {}
    -        meta = self.opts.model._meta
    -
    -        # Reverse fk or one-to-one relations
    -        for (obj, model) in meta.get_all_related_objects_with_model():
    -            field_name = obj.get_accessor_name()
    -            if field_name in attrs:
    -                related_data[field_name] = attrs.pop(field_name)
    -
    -        # Reverse m2m relations
    -        for (obj, model) in meta.get_all_related_m2m_objects_with_model():
    -            field_name = obj.get_accessor_name()
    -            if field_name in attrs:
    -                m2m_data[field_name] = attrs.pop(field_name)
    -
    -        # Forward m2m relations
    -        for field in meta.many_to_many + meta.virtual_fields:
    -            if isinstance(field, GenericForeignKey):
    -                continue
    -            if field.name in attrs:
    -                m2m_data[field.name] = attrs.pop(field.name)
    -
    -        # Nested forward relations - These need to be marked so we can save
    -        # them before saving the parent model instance.
    -        for field_name in attrs.keys():
    -            if isinstance(self.fields.get(field_name, None), Serializer):
    -                nested_forward_relations[field_name] = attrs[field_name]
    -
    -        # Create an empty instance of the model
    -        if instance is None:
    -            instance = self.opts.model()
    -
    -        for key, val in attrs.items():
    +        for item in data:
                 try:
    -                setattr(instance, key, val)
    -            except ValueError:
    -                self._errors[key] = [self.error_messages['required']]
    +                validated = self.child.run_validation(item)
    +            except ValidationError as exc:
    +                errors.append(exc.detail)
    +            else:
    +                ret.append(validated)
    +                errors.append({})
     
    -        # Any relations that cannot be set until we've
    -        # saved the model get hidden away on these
    -        # private attributes, so we can deal with them
    -        # at the point of save.
    -        instance._related_data = related_data
    -        instance._m2m_data = m2m_data
    -        instance._nested_forward_relations = nested_forward_relations
    +        if any(errors):
    +            raise ValidationError(errors)
    +
    +        return ret
    +
    +    def to_representation(self, data):
    +        """
    +        List of object instances -> List of dicts of primitive datatypes.
    +        """
    +        iterable = data.all() if (hasattr(data, 'all')) else data
    +        return [
    +            self.child.to_representation(item) for item in iterable
    +        ]
    +
    +    def update(self, instance, validated_data):
    +        raise NotImplementedError(
    +            "Serializers with many=True do not support multiple update by "
    +            "default, only multiple create. For updates it is unclear how to "
    +            "deal with insertions and deletions. If you need to support "
    +            "multiple update, use a `ListSerializer` class and override "
    +            "`.update()` so you can specify the behavior exactly."
    +        )
    +
    +    def create(self, validated_data):
    +        return [
    +            self.child.create(attrs) for attrs in validated_data
    +        ]
    +
    +    def save(self, **kwargs):
    +        """
    +        Save and return a list of object instances.
    +        """
    +        validated_data = [
    +            dict(list(attrs.items()) + list(kwargs.items()))
    +            for attrs in self.validated_data
    +        ]
    +
    +        if self.instance is not None:
    +            self.instance = self.update(self.instance, validated_data)
    +            assert self.instance is not None, (
    +                '`update()` did not return an object instance.'
    +            )
    +        else:
    +            self.instance = self.create(validated_data)
    +            assert self.instance is not None, (
    +                '`create()` did not return an object instance.'
    +            )
    +
    +        return self.instance
    +
    +    def __repr__(self):
    +        return representation.list_repr(self, indent=1)
    +
    +    # Include a backlink to the serializer class on return objects.
    +    # Allows renderers such as HTMLFormRenderer to get the full field info.
    +
    +    @property
    +    def data(self):
    +        ret = super(ListSerializer, self).data
    +        return ReturnList(ret, serializer=self)
    +
    +    @property
    +    def errors(self):
    +        ret = super(ListSerializer, self).errors
    +        if isinstance(ret, dict):
    +            return ReturnDict(ret, serializer=self)
    +        return ReturnList(ret, serializer=self)
    +
    +
    +# ModelSerializer & HyperlinkedModelSerializer
    +# --------------------------------------------
    +
    +class ModelSerializer(Serializer):
    +    """
    +    A `ModelSerializer` is just a regular `Serializer`, except that:
    +
    +    * A set of default fields are automatically populated.
    +    * A set of default validators are automatically populated.
    +    * Default `.create()` and `.update()` implementations are provided.
    +    """
    +    _field_mapping = ClassLookupDict({
    +        models.AutoField: IntegerField,
    +        models.BigIntegerField: IntegerField,
    +        models.BooleanField: BooleanField,
    +        models.CharField: CharField,
    +        models.CommaSeparatedIntegerField: CharField,
    +        models.DateField: DateField,
    +        models.DateTimeField: DateTimeField,
    +        models.DecimalField: DecimalField,
    +        models.EmailField: EmailField,
    +        models.Field: ModelField,
    +        models.FileField: FileField,
    +        models.FloatField: FloatField,
    +        models.ImageField: ImageField,
    +        models.IntegerField: IntegerField,
    +        models.NullBooleanField: NullBooleanField,
    +        models.PositiveIntegerField: IntegerField,
    +        models.PositiveSmallIntegerField: IntegerField,
    +        models.SlugField: SlugField,
    +        models.SmallIntegerField: IntegerField,
    +        models.TextField: CharField,
    +        models.TimeField: TimeField,
    +        models.URLField: URLField,
    +    })
    +    _related_class = PrimaryKeyRelatedField
    +
    +    def create(self, validated_attrs):
    +        # Check that the user isn't trying to handle a writable nested field.
    +        # If we don't do this explicitly they'd likely get a confusing
    +        # error at the point of calling `Model.objects.create()`.
    +        assert not any(
    +            isinstance(field, BaseSerializer) and not field.read_only
    +            for field in self.fields.values()
    +        ), (
    +            'The `.create()` method does not suport nested writable fields '
    +            'by default. Write an explicit `.create()` method for serializer '
    +            '`%s.%s`, or set `read_only=True` on nested serializer fields.' %
    +            (self.__class__.__module__, self.__class__.__name__)
    +        )
    +
    +        ModelClass = self.Meta.model
    +
    +        # Remove many-to-many relationships from validated_attrs.
    +        # They are not valid arguments to the default `.create()` method,
    +        # as they require that the instance has already been saved.
    +        info = model_meta.get_field_info(ModelClass)
    +        many_to_many = {}
    +        for field_name, relation_info in info.relations.items():
    +            if relation_info.to_many and (field_name in validated_attrs):
    +                many_to_many[field_name] = validated_attrs.pop(field_name)
    +
    +        instance = ModelClass.objects.create(**validated_attrs)
    +
    +        # Save many-to-many relationships after the instance is created.
    +        if many_to_many:
    +            for field_name, value in many_to_many.items():
    +                setattr(instance, field_name, value)
     
             return instance
     
    -    def from_native(self, data, files):
    -        """
    -        Override the default method to also include model field validation.
    -        """
    -        instance = super(ModelSerializer, self).from_native(data, files)
    -        if not self._errors:
    -            return self.full_clean(instance)
    +    def update(self, instance, validated_attrs):
    +        assert not any(
    +            isinstance(field, BaseSerializer) and not field.read_only
    +            for field in self.fields.values()
    +        ), (
    +            'The `.update()` method does not suport nested writable fields '
    +            'by default. Write an explicit `.update()` method for serializer '
    +            '`%s.%s`, or set `read_only=True` on nested serializer fields.' %
    +            (self.__class__.__module__, self.__class__.__name__)
    +        )
     
    -    def save_object(self, obj, **kwargs):
    -        """
    -        Save the deserialized object.
    -        """
    -        if getattr(obj, '_nested_forward_relations', None):
    -            # Nested relationships need to be saved before we can save the
    -            # parent instance.
    -            for field_name, sub_object in obj._nested_forward_relations.items():
    -                if sub_object:
    -                    self.save_object(sub_object)
    -                setattr(obj, field_name, sub_object)
    +        for attr, value in validated_attrs.items():
    +            setattr(instance, attr, value)
    +        instance.save()
    +        return instance
     
    -        obj.save(**kwargs)
    +    def get_validators(self):
    +        field_names = set([
    +            field.source for field in self.fields.values()
    +            if (field.source != '*') and ('.' not in field.source)
    +        ])
     
    -        if getattr(obj, '_m2m_data', None):
    -            for accessor_name, object_list in obj._m2m_data.items():
    -                setattr(obj, accessor_name, object_list)
    -            del(obj._m2m_data)
    +        validators = getattr(getattr(self, 'Meta', None), 'validators', [])
    +        model_class = self.Meta.model
     
    -        if getattr(obj, '_related_data', None):
    -            related_fields = dict([
    -                (field.get_accessor_name(), field)
    -                for field, model
    -                in obj._meta.get_all_related_objects_with_model()
    +        # Note that we make sure to check `unique_together` both on the
    +        # base model class, but also on any parent classes.
    +        for parent_class in [model_class] + list(model_class._meta.parents.keys()):
    +            for unique_together in parent_class._meta.unique_together:
    +                if field_names.issuperset(set(unique_together)):
    +                    validator = UniqueTogetherValidator(
    +                        queryset=parent_class._default_manager,
    +                        fields=unique_together
    +                    )
    +                    validators.append(validator)
    +
    +        # Add any unique_for_date/unique_for_month/unique_for_year constraints.
    +        info = model_meta.get_field_info(model_class)
    +        for field_name, field in info.fields_and_pk.items():
    +            if field.unique_for_date and field_name in field_names:
    +                validator = UniqueForDateValidator(
    +                    queryset=model_class._default_manager,
    +                    field=field_name,
    +                    date_field=field.unique_for_date
    +                )
    +                validators.append(validator)
    +
    +            if field.unique_for_month and field_name in field_names:
    +                validator = UniqueForMonthValidator(
    +                    queryset=model_class._default_manager,
    +                    field=field_name,
    +                    date_field=field.unique_for_month
    +                )
    +                validators.append(validator)
    +
    +            if field.unique_for_year and field_name in field_names:
    +                validator = UniqueForYearValidator(
    +                    queryset=model_class._default_manager,
    +                    field=field_name,
    +                    date_field=field.unique_for_year
    +                )
    +                validators.append(validator)
    +
    +        return validators
    +
    +    def get_fields(self):
    +        declared_fields = copy.deepcopy(self._declared_fields)
    +
    +        ret = OrderedDict()
    +        model = getattr(self.Meta, 'model')
    +        fields = getattr(self.Meta, 'fields', None)
    +        exclude = getattr(self.Meta, 'exclude', None)
    +        depth = getattr(self.Meta, 'depth', 0)
    +        extra_kwargs = getattr(self.Meta, 'extra_kwargs', {})
    +
    +        assert not (fields and exclude), "Cannot set both 'fields' and 'exclude'."
    +
    +        extra_kwargs = self._include_additional_options(extra_kwargs)
    +
    +        # Retrieve metadata about fields & relationships on the model class.
    +        info = model_meta.get_field_info(model)
    +
    +        # Use the default set of field names if none is supplied explicitly.
    +        if fields is None:
    +            fields = self._get_default_field_names(declared_fields, info)
    +            exclude = getattr(self.Meta, 'exclude', None)
    +            if exclude is not None:
    +                for field_name in exclude:
    +                    fields.remove(field_name)
    +
    +        # Determine the set of model fields, and the fields that they map to.
    +        # We actually only need this to deal with the slightly awkward case
    +        # of supporting `unique_for_date`/`unique_for_month`/`unique_for_year`.
    +        model_field_mapping = {}
    +        for field_name in fields:
    +            if field_name in declared_fields:
    +                field = declared_fields[field_name]
    +                source = field.source or field_name
    +            else:
    +                try:
    +                    source = extra_kwargs[field_name]['source']
    +                except KeyError:
    +                    source = field_name
    +            # Model fields will always have a simple source mapping,
    +            # they can't be nested attribute lookups.
    +            if '.' not in source and source != '*':
    +                model_field_mapping[source] = field_name
    +
    +        # Determine if we need any additional `HiddenField` or extra keyword
    +        # arguments to deal with `unique_for` dates that are required to
    +        # be in the input data in order to validate it.
    +        hidden_fields = {}
    +        unique_constraint_names = set()
    +
    +        for model_field_name, field_name in model_field_mapping.items():
    +            try:
    +                model_field = model._meta.get_field(model_field_name)
    +            except FieldDoesNotExist:
    +                continue
    +
    +            # Include each of the `unique_for_*` field names.
    +            unique_constraint_names |= set([
    +                model_field.unique_for_date,
    +                model_field.unique_for_month,
    +                model_field.unique_for_year
                 ])
    -            for accessor_name, related in obj._related_data.items():
    -                if isinstance(related, RelationsList):
    -                    # Nested reverse fk relationship
    -                    for related_item in related:
    -                        fk_field = related_fields[accessor_name].field.name
    -                        setattr(related_item, fk_field, obj)
    -                        self.save_object(related_item)
     
    -                    # Delete any removed objects
    -                    if related._deleted:
    -                        [self.delete_object(item) for item in related._deleted]
    +        unique_constraint_names -= set([None])
     
    -                elif isinstance(related, models.Model):
    -                    # Nested reverse one-one relationship
    -                    fk_field = obj._meta.get_field_by_name(accessor_name)[0].field.name
    -                    setattr(related, fk_field, obj)
    -                    self.save_object(related)
    +        # Include each of the `unique_together` field names,
    +        # so long as all the field names are included on the serializer.
    +        for parent_class in [model] + list(model._meta.parents.keys()):
    +            for unique_together_list in parent_class._meta.unique_together:
    +                if set(fields).issuperset(set(unique_together_list)):
    +                    unique_constraint_names |= set(unique_together_list)
    +
    +        # Now we have all the field names that have uniqueness constraints
    +        # applied, we can add the extra 'required=...' or 'default=...'
    +        # arguments that are appropriate to these fields, or add a `HiddenField` for it.
    +        for unique_constraint_name in unique_constraint_names:
    +            # Get the model field that is refered too.
    +            unique_constraint_field = model._meta.get_field(unique_constraint_name)
    +
    +            if getattr(unique_constraint_field, 'auto_now_add', None):
    +                default = CreateOnlyDefault(timezone.now)
    +            elif getattr(unique_constraint_field, 'auto_now', None):
    +                default = timezone.now
    +            elif unique_constraint_field.has_default():
    +                default = unique_constraint_field.default
    +            else:
    +                default = empty
    +
    +            if unique_constraint_name in model_field_mapping:
    +                # The corresponding field is present in the serializer
    +                if unique_constraint_name not in extra_kwargs:
    +                    extra_kwargs[unique_constraint_name] = {}
    +                if default is empty:
    +                    if 'required' not in extra_kwargs[unique_constraint_name]:
    +                        extra_kwargs[unique_constraint_name]['required'] = True
                     else:
    -                    # Reverse FK or reverse one-one
    -                    setattr(obj, accessor_name, related)
    -            del(obj._related_data)
    +                    if 'default' not in extra_kwargs[unique_constraint_name]:
    +                        extra_kwargs[unique_constraint_name]['default'] = default
    +            elif default is not empty:
    +                # The corresponding field is not present in the,
    +                # serializer. We have a default to use for it, so
    +                # add in a hidden field that populates it.
    +                hidden_fields[unique_constraint_name] = HiddenField(default=default)
     
    +        # Now determine the fields that should be included on the serializer.
    +        for field_name in fields:
    +            if field_name in declared_fields:
    +                # Field is explicitly declared on the class, use that.
    +                ret[field_name] = declared_fields[field_name]
    +                continue
     
    -class HyperlinkedModelSerializerOptions(ModelSerializerOptions):
    -    """
    -    Options for HyperlinkedModelSerializer
    -    """
    -    def __init__(self, meta):
    -        super(HyperlinkedModelSerializerOptions, self).__init__(meta)
    -        self.view_name = getattr(meta, 'view_name', None)
    -        self.lookup_field = getattr(meta, 'lookup_field', None)
    -        self.url_field_name = getattr(meta, 'url_field_name', api_settings.URL_FIELD_NAME)
    +            elif field_name in info.fields_and_pk:
    +                # Create regular model fields.
    +                model_field = info.fields_and_pk[field_name]
    +                field_cls = self._field_mapping[model_field]
    +                kwargs = get_field_kwargs(field_name, model_field)
    +                if 'choices' in kwargs:
    +                    # Fields with choices get coerced into `ChoiceField`
    +                    # instead of using their regular typed field.
    +                    field_cls = ChoiceField
    +                if not issubclass(field_cls, ModelField):
    +                    # `model_field` is only valid for the fallback case of
    +                    # `ModelField`, which is used when no other typed field
    +                    # matched to the model field.
    +                    kwargs.pop('model_field', None)
    +                if not issubclass(field_cls, CharField):
    +                    # `allow_blank` is only valid for textual fields.
    +                    kwargs.pop('allow_blank', None)
    +
    +            elif field_name in info.relations:
    +                # Create forward and reverse relationships.
    +                relation_info = info.relations[field_name]
    +                if depth:
    +                    field_cls = self._get_nested_class(depth, relation_info)
    +                    kwargs = get_nested_relation_kwargs(relation_info)
    +                else:
    +                    field_cls = self._related_class
    +                    kwargs = get_relation_kwargs(field_name, relation_info)
    +                    # `view_name` is only valid for hyperlinked relationships.
    +                    if not issubclass(field_cls, HyperlinkedRelatedField):
    +                        kwargs.pop('view_name', None)
    +
    +            elif hasattr(model, field_name):
    +                # Create a read only field for model methods and properties.
    +                field_cls = ReadOnlyField
    +                kwargs = {}
    +
    +            elif field_name == api_settings.URL_FIELD_NAME:
    +                # Create the URL field.
    +                field_cls = HyperlinkedIdentityField
    +                kwargs = get_url_kwargs(model)
    +
    +            else:
    +                raise ImproperlyConfigured(
    +                    'Field name `%s` is not valid for model `%s`.' %
    +                    (field_name, model.__class__.__name__)
    +                )
    +
    +            # Check that any fields declared on the class are
    +            # also explicity included in `Meta.fields`.
    +            missing_fields = set(declared_fields.keys()) - set(fields)
    +            if missing_fields:
    +                missing_field = list(missing_fields)[0]
    +                raise ImproperlyConfigured(
    +                    'Field `%s` has been declared on serializer `%s`, but '
    +                    'is missing from `Meta.fields`.' %
    +                    (missing_field, self.__class__.__name__)
    +                )
    +
    +            # Populate any kwargs defined in `Meta.extra_kwargs`
    +            extras = extra_kwargs.get(field_name, {})
    +            if extras.get('read_only', False):
    +                for attr in [
    +                    'required', 'default', 'allow_blank', 'allow_null',
    +                    'min_length', 'max_length', 'min_value', 'max_value',
    +                    'validators', 'queryset'
    +                ]:
    +                    kwargs.pop(attr, None)
    +
    +            if extras.get('default') and kwargs.get('required') is False:
    +                kwargs.pop('required')
    +
    +            kwargs.update(extras)
    +
    +            # Create the serializer field.
    +            ret[field_name] = field_cls(**kwargs)
    +
    +        for field_name, field in hidden_fields.items():
    +            ret[field_name] = field
    +
    +        return ret
    +
    +    def _include_additional_options(self, extra_kwargs):
    +        read_only_fields = getattr(self.Meta, 'read_only_fields', None)
    +        if read_only_fields is not None:
    +            for field_name in read_only_fields:
    +                kwargs = extra_kwargs.get(field_name, {})
    +                kwargs['read_only'] = True
    +                extra_kwargs[field_name] = kwargs
    +
    +        # These are all pending deprecation.
    +        write_only_fields = getattr(self.Meta, 'write_only_fields', None)
    +        if write_only_fields is not None:
    +            warnings.warn(
    +                "The `Meta.write_only_fields` option is pending deprecation. "
    +                "Use `Meta.extra_kwargs={: {'write_only': True}}` instead.",
    +                PendingDeprecationWarning,
    +                stacklevel=3
    +            )
    +            for field_name in write_only_fields:
    +                kwargs = extra_kwargs.get(field_name, {})
    +                kwargs['write_only'] = True
    +                extra_kwargs[field_name] = kwargs
    +
    +        view_name = getattr(self.Meta, 'view_name', None)
    +        if view_name is not None:
    +            warnings.warn(
    +                "The `Meta.view_name` option is pending deprecation. "
    +                "Use `Meta.extra_kwargs={'url': {'view_name': ...}}` instead.",
    +                PendingDeprecationWarning,
    +                stacklevel=3
    +            )
    +            kwargs = extra_kwargs.get(api_settings.URL_FIELD_NAME, {})
    +            kwargs['view_name'] = view_name
    +            extra_kwargs[api_settings.URL_FIELD_NAME] = kwargs
    +
    +        lookup_field = getattr(self.Meta, 'lookup_field', None)
    +        if lookup_field is not None:
    +            warnings.warn(
    +                "The `Meta.lookup_field` option is pending deprecation. "
    +                "Use `Meta.extra_kwargs={'url': {'lookup_field': ...}}` instead.",
    +                PendingDeprecationWarning,
    +                stacklevel=3
    +            )
    +            kwargs = extra_kwargs.get(api_settings.URL_FIELD_NAME, {})
    +            kwargs['lookup_field'] = lookup_field
    +            extra_kwargs[api_settings.URL_FIELD_NAME] = kwargs
    +
    +        return extra_kwargs
    +
    +    def _get_default_field_names(self, declared_fields, model_info):
    +        return (
    +            [model_info.pk.name] +
    +            list(declared_fields.keys()) +
    +            list(model_info.fields.keys()) +
    +            list(model_info.forward_relations.keys())
    +        )
    +
    +    def _get_nested_class(self, nested_depth, relation_info):
    +        class NestedSerializer(ModelSerializer):
    +            class Meta:
    +                model = relation_info.related
    +                depth = nested_depth
    +        return NestedSerializer
     
     
     class HyperlinkedModelSerializer(ModelSerializer):
         """
    -    A subclass of ModelSerializer that uses hyperlinked relationships,
    -    instead of primary key relationships.
    +    A type of `ModelSerializer` that uses hyperlinked relationships instead
    +    of primary key relationships. Specifically:
    +
    +    * A 'url' field is included instead of the 'id' field.
    +    * Relationships to other instances are hyperlinks, instead of primary keys.
         """
    -    _options_class = HyperlinkedModelSerializerOptions
    -    _default_view_name = '%(model_name)s-detail'
    -    _hyperlink_field_class = HyperlinkedRelatedField
    -    _hyperlink_identify_field_class = HyperlinkedIdentityField
    +    _related_class = HyperlinkedRelatedField
     
    -    def get_default_fields(self):
    -        fields = super(HyperlinkedModelSerializer, self).get_default_fields()
    +    def _get_default_field_names(self, declared_fields, model_info):
    +        return (
    +            [api_settings.URL_FIELD_NAME] +
    +            list(declared_fields.keys()) +
    +            list(model_info.fields.keys()) +
    +            list(model_info.forward_relations.keys())
    +        )
     
    -        if self.opts.view_name is None:
    -            self.opts.view_name = self._get_default_view_name(self.opts.model)
    -
    -        if self.opts.url_field_name not in fields:
    -            url_field = self._hyperlink_identify_field_class(
    -                view_name=self.opts.view_name,
    -                lookup_field=self.opts.lookup_field
    -            )
    -            ret = self._dict_class()
    -            ret[self.opts.url_field_name] = url_field
    -            ret.update(fields)
    -            fields = ret
    -
    -        return fields
    -
    -    def get_pk_field(self, model_field):
    -        if self.opts.fields and model_field.name in self.opts.fields:
    -            return self.get_field(model_field)
    -
    -    def get_related_field(self, model_field, related_model, to_many):
    -        """
    -        Creates a default instance of a flat relational field.
    -        """
    -        # TODO: filter queryset using:
    -        # .using(db).complex_filter(self.rel.limit_choices_to)
    -        kwargs = {
    -            'queryset': related_model._default_manager,
    -            'view_name': self._get_default_view_name(related_model),
    -            'many': to_many
    -        }
    -
    -        if model_field:
    -            kwargs['required'] = not(model_field.null or model_field.blank)
    -            if model_field.help_text is not None:
    -                kwargs['help_text'] = model_field.help_text
    -            if model_field.verbose_name is not None:
    -                kwargs['label'] = model_field.verbose_name
    -
    -        if self.opts.lookup_field:
    -            kwargs['lookup_field'] = self.opts.lookup_field
    -
    -        return self._hyperlink_field_class(**kwargs)
    -
    -    def get_identity(self, data):
    -        """
    -        This hook is required for bulk update.
    -        We need to override the default, to use the url as the identity.
    -        """
    -        try:
    -            return data.get(self.opts.url_field_name, None)
    -        except AttributeError:
    -            return None
    -
    -    def _get_default_view_name(self, model):
    -        """
    -        Return the view name to use if 'view_name' is not specified in 'Meta'
    -        """
    -        model_meta = model._meta
    -        format_kwargs = {
    -            'app_label': model_meta.app_label,
    -            'model_name': model_meta.object_name.lower()
    -        }
    -        return self._default_view_name % format_kwargs
    +    def _get_nested_class(self, nested_depth, relation_info):
    +        class NestedSerializer(HyperlinkedModelSerializer):
    +            class Meta:
    +                model = relation_info.related
    +                depth = nested_depth
    +        return NestedSerializer
    diff --git a/rest_framework/settings.py b/rest_framework/settings.py
    index 644751f87..1e8c27fc3 100644
    --- a/rest_framework/settings.py
    +++ b/rest_framework/settings.py
    @@ -45,6 +45,7 @@ DEFAULTS = {
         ),
         'DEFAULT_THROTTLE_CLASSES': (),
         'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
    +    'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
     
         # Genric view behavior
         'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.serializers.ModelSerializer',
    @@ -77,6 +78,7 @@ DEFAULTS = {
     
         # Exception handling
         'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
    +    'NON_FIELD_ERRORS_KEY': 'non_field_errors',
     
         # Testing
         'TEST_REQUEST_RENDERER_CLASSES': (
    @@ -96,24 +98,20 @@ DEFAULTS = {
         'URL_FIELD_NAME': 'url',
     
         # Input and output formats
    -    'DATE_INPUT_FORMATS': (
    -        ISO_8601,
    -    ),
    -    'DATE_FORMAT': None,
    +    'DATE_FORMAT': ISO_8601,
    +    'DATE_INPUT_FORMATS': (ISO_8601,),
     
    -    'DATETIME_INPUT_FORMATS': (
    -        ISO_8601,
    -    ),
    -    'DATETIME_FORMAT': None,
    +    'DATETIME_FORMAT': ISO_8601,
    +    'DATETIME_INPUT_FORMATS': (ISO_8601,),
     
    -    'TIME_INPUT_FORMATS': (
    -        ISO_8601,
    -    ),
    -    'TIME_FORMAT': None,
    -
    -    # Pending deprecation
    -    'FILTER_BACKEND': None,
    +    'TIME_FORMAT': ISO_8601,
    +    'TIME_INPUT_FORMATS': (ISO_8601,),
     
    +    # Encoding
    +    'UNICODE_JSON': True,
    +    'COMPACT_JSON': True,
    +    'COERCE_DECIMAL_TO_STRING': True,
    +    'UPLOADED_FILES_USE_URL': True
     }
     
     
    @@ -125,11 +123,11 @@ IMPORT_STRINGS = (
         'DEFAULT_PERMISSION_CLASSES',
         'DEFAULT_THROTTLE_CLASSES',
         'DEFAULT_CONTENT_NEGOTIATION_CLASS',
    +    'DEFAULT_METADATA_CLASS',
         'DEFAULT_MODEL_SERIALIZER_CLASS',
         'DEFAULT_PAGINATION_SERIALIZER_CLASS',
         'DEFAULT_FILTER_BACKENDS',
         'EXCEPTION_HANDLER',
    -    'FILTER_BACKEND',
         'TEST_REQUEST_RENDERER_CLASSES',
         'UNAUTHENTICATED_USER',
         'UNAUTHENTICATED_TOKEN',
    @@ -196,15 +194,9 @@ class APISettings(object):
             if val and attr in self.import_strings:
                 val = perform_import(val, attr)
     
    -        self.validate_setting(attr, val)
    -
             # Cache the result
             setattr(self, attr, val)
             return val
     
    -    def validate_setting(self, attr, val):
    -        if attr == 'FILTER_BACKEND' and val is not None:
    -            # Make sure we can initialize the class
    -            val()
     
     api_settings = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS)
    diff --git a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css
    index 6fa1e6cb5..36c7be481 100644
    --- a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css
    +++ b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css
    @@ -10,6 +10,12 @@ a single block in the template.
       background: transparent;
       border-top-color: transparent;
       padding-top: 0;
    +  text-align: right;
    +}
    +
    +#generic-content-form textarea {
    +  font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
    +  font-size: 80%;
     }
     
     .navbar-inverse .brand a {
    @@ -29,7 +35,7 @@ a single block in the template.
       z-index: 3;
     }
     
    -.navbar .navbar-inner {
    +.navbar {
       background: #2C2C2C;
       color: white;
       border: none;
    @@ -37,7 +43,7 @@ a single block in the template.
       border-radius: 0px;
     }
     
    -.navbar .navbar-inner .nav li, .navbar .navbar-inner .nav li a, .navbar .navbar-inner .brand:hover {
    +.navbar .nav li, .navbar .nav li a, .navbar .brand:hover {
       color: white;
     }
     
    @@ -45,11 +51,11 @@ a single block in the template.
       background: #2C2C2C;
     }
     
    -.navbar .navbar-inner .dropdown-menu li a, .navbar .navbar-inner .dropdown-menu li {
    +.navbar .dropdown-menu li a, .navbar .dropdown-menu li {
       color: #A30000;
     }
     
    -.navbar .navbar-inner .dropdown-menu li a:hover {
    +.navbar .dropdown-menu li a:hover {
       background: #EEEEEE;
       color: #C20000;
     }
    @@ -61,10 +67,10 @@ html {
       background: none;
     }
     
    -body, .navbar .navbar-inner .container-fluid {
    +/*body, .navbar .container-fluid {
       max-width: 1150px;
       margin: 0 auto;
    -}
    +}*/
     
     body {
       background: url("../img/grid.png") repeat-x;
    @@ -109,10 +115,6 @@ html, body {
       margin-bottom: 0;
     }
     
    -.well form .help-block {
    -  color: #999999;
    -}
    -
     .nav-tabs {
       border: 0;
     }
    @@ -167,7 +169,7 @@ footer a:hover {
     .page-header {
       border-bottom: none;
       padding-bottom: 0px;
    -  margin-bottom: 20px;
    +  margin: 0;
     }
     
     /* custom general page styles */
    diff --git a/rest_framework/static/rest_framework/css/bootstrap.min.css b/rest_framework/static/rest_framework/css/bootstrap.min.css
    index 373f4b430..a9f35ceed 100644
    --- a/rest_framework/static/rest_framework/css/bootstrap.min.css
    +++ b/rest_framework/static/rest_framework/css/bootstrap.min.css
    @@ -1,841 +1,5 @@
     /*!
    - * Bootstrap v2.1.1
    - *
    - * Copyright 2012 Twitter, Inc
    - * Licensed under the Apache License v2.0
    - * http://www.apache.org/licenses/LICENSE-2.0
    - *
    - * Designed and built with all the love in the world @twitter by @mdo and @fat.
    - */
    -.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
    -.clearfix:after{clear:both;}
    -.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
    -.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
    -article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
    -audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
    -audio:not([controls]){display:none;}
    -html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
    -a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
    -a:hover,a:active{outline:0;}
    -sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
    -sup{top:-0.5em;}
    -sub{bottom:-0.25em;}
    -img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}
    -#map_canvas img{max-width:none;}
    -button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
    -button,input{*overflow:visible;line-height:normal;}
    -button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
    -button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
    -input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}
    -input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
    -textarea{overflow:auto;vertical-align:top;}
    -body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;}
    -a{color:#0088cc;text-decoration:none;}
    -a:hover{color:#005580;text-decoration:underline;}
    -.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
    -.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);}
    -.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;}
    -.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;}
    -.row:after{clear:both;}
    -[class*="span"]{float:left;min-height:1px;margin-left:20px;}
    -.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
    -.span12{width:940px;}
    -.span11{width:860px;}
    -.span10{width:780px;}
    -.span9{width:700px;}
    -.span8{width:620px;}
    -.span7{width:540px;}
    -.span6{width:460px;}
    -.span5{width:380px;}
    -.span4{width:300px;}
    -.span3{width:220px;}
    -.span2{width:140px;}
    -.span1{width:60px;}
    -.offset12{margin-left:980px;}
    -.offset11{margin-left:900px;}
    -.offset10{margin-left:820px;}
    -.offset9{margin-left:740px;}
    -.offset8{margin-left:660px;}
    -.offset7{margin-left:580px;}
    -.offset6{margin-left:500px;}
    -.offset5{margin-left:420px;}
    -.offset4{margin-left:340px;}
    -.offset3{margin-left:260px;}
    -.offset2{margin-left:180px;}
    -.offset1{margin-left:100px;}
    -.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;}
    -.row-fluid:after{clear:both;}
    -.row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;}
    -.row-fluid [class*="span"]:first-child{margin-left:0;}
    -.row-fluid .span12{width:100%;*width:99.94680851063829%;}
    -.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;}
    -.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;}
    -.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;}
    -.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;}
    -.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;}
    -.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;}
    -.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;}
    -.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;}
    -.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;}
    -.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;}
    -.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;}
    -.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;}
    -.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;}
    -.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;}
    -.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;}
    -.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;}
    -.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;}
    -.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;}
    -.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;}
    -.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;}
    -.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;}
    -.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;}
    -.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;}
    -.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;}
    -.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;}
    -.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;}
    -.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;}
    -.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;}
    -.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;}
    -.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;}
    -.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;}
    -.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;}
    -.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;}
    -.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;}
    -.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;}
    -[class*="span"].hide,.row-fluid [class*="span"].hide{display:none;}
    -[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;}
    -.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;}
    -.container:after{clear:both;}
    -.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;}
    -.container-fluid:after{clear:both;}
    -p{margin:0 0 10px;}
    -.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;}
    -small{font-size:85%;}
    -strong{font-weight:bold;}
    -em{font-style:italic;}
    -cite{font-style:normal;}
    -.muted{color:#999999;}
    -.text-warning{color:#c09853;}
    -.text-error{color:#b94a48;}
    -.text-info{color:#3a87ad;}
    -.text-success{color:#468847;}
    -h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:1;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;}
    -h1{font-size:36px;line-height:40px;}
    -h2{font-size:30px;line-height:40px;}
    -h3{font-size:24px;line-height:40px;}
    -h4{font-size:18px;line-height:20px;}
    -h5{font-size:14px;line-height:20px;}
    -h6{font-size:12px;line-height:20px;}
    -h1 small{font-size:24px;}
    -h2 small{font-size:18px;}
    -h3 small{font-size:14px;}
    -h4 small{font-size:14px;}
    -.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;}
    -ul,ol{padding:0;margin:0 0 10px 25px;}
    -ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
    -li{line-height:20px;}
    -ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
    -dl{margin-bottom:20px;}
    -dt,dd{line-height:20px;}
    -dt{font-weight:bold;}
    -dd{margin-left:10px;}
    -.dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;}
    -.dl-horizontal:after{clear:both;}
    -.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
    -.dl-horizontal dd{margin-left:180px;}
    -hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
    -abbr[title]{cursor:help;border-bottom:1px dotted #999999;}
    -abbr.initialism{font-size:90%;text-transform:uppercase;}
    -blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px;}
    -blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
    -blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
    -blockquote.pull-right small:before{content:'';}
    -blockquote.pull-right small:after{content:'\00A0 \2014';}
    -q:before,q:after,blockquote:before,blockquote:after{content:"";}
    -address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;}
    -code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
    -code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
    -pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;}
    -pre code{padding:0;color:inherit;background-color:transparent;border:0;}
    -.pre-scrollable{max-height:340px;overflow-y:scroll;}
    -.label,.badge{font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;}
    -.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
    -.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}
    -a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}
    -.label-important,.badge-important{background-color:#b94a48;}
    -.label-important[href],.badge-important[href]{background-color:#953b39;}
    -.label-warning,.badge-warning{background-color:#f89406;}
    -.label-warning[href],.badge-warning[href]{background-color:#c67605;}
    -.label-success,.badge-success{background-color:#468847;}
    -.label-success[href],.badge-success[href]{background-color:#356635;}
    -.label-info,.badge-info{background-color:#3a87ad;}
    -.label-info[href],.badge-info[href]{background-color:#2d6987;}
    -.label-inverse,.badge-inverse{background-color:#333333;}
    -.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}
    -.btn .label,.btn .badge{position:relative;top:-1px;}
    -.btn-mini .label,.btn-mini .badge{top:0;}
    -table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}
    -.table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}
    -.table th{font-weight:bold;}
    -.table thead th{vertical-align:bottom;}
    -.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}
    -.table tbody+tbody{border-top:2px solid #dddddd;}
    -.table-condensed th,.table-condensed td{padding:4px 5px;}
    -.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
    -.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
    -.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}
    -.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}
    -.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;}
    -.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;}
    -.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}
    -.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topleft:4px;}
    -.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
    -.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5;}
    -table [class*=span],.row-fluid table [class*=span]{display:table-cell;float:none;margin-left:0;}
    -.table .span1{float:none;width:44px;margin-left:0;}
    -.table .span2{float:none;width:124px;margin-left:0;}
    -.table .span3{float:none;width:204px;margin-left:0;}
    -.table .span4{float:none;width:284px;margin-left:0;}
    -.table .span5{float:none;width:364px;margin-left:0;}
    -.table .span6{float:none;width:444px;margin-left:0;}
    -.table .span7{float:none;width:524px;margin-left:0;}
    -.table .span8{float:none;width:604px;margin-left:0;}
    -.table .span9{float:none;width:684px;margin-left:0;}
    -.table .span10{float:none;width:764px;margin-left:0;}
    -.table .span11{float:none;width:844px;margin-left:0;}
    -.table .span12{float:none;width:924px;margin-left:0;}
    -.table .span13{float:none;width:1004px;margin-left:0;}
    -.table .span14{float:none;width:1084px;margin-left:0;}
    -.table .span15{float:none;width:1164px;margin-left:0;}
    -.table .span16{float:none;width:1244px;margin-left:0;}
    -.table .span17{float:none;width:1324px;margin-left:0;}
    -.table .span18{float:none;width:1404px;margin-left:0;}
    -.table .span19{float:none;width:1484px;margin-left:0;}
    -.table .span20{float:none;width:1564px;margin-left:0;}
    -.table .span21{float:none;width:1644px;margin-left:0;}
    -.table .span22{float:none;width:1724px;margin-left:0;}
    -.table .span23{float:none;width:1804px;margin-left:0;}
    -.table .span24{float:none;width:1884px;margin-left:0;}
    -.table tbody tr.success td{background-color:#dff0d8;}
    -.table tbody tr.error td{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;}
    -form{margin:0 0 20px;}
    -fieldset{padding:0;margin:0;border:0;}
    -legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;}
    -label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;}
    -input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
    -label{display:block;margin-bottom:5px;}
    -select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:9px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
    -input,textarea,.uneditable-input{width:206px;}
    -textarea{height:auto;}
    -textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-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);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);}
    -input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;cursor:pointer;}
    -input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;}
    -select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;}
    -select{width:220px;border:1px solid #cccccc;background-color:#ffffff;}
    -select[multiple],select[size]{height:auto;}
    -select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
    -.uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
    -.uneditable-input{overflow:hidden;white-space:nowrap;}
    -.uneditable-textarea{width:auto;height:auto;}
    -input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;}
    -input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;}
    -input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;}
    -.radio,.checkbox{min-height:18px;padding-left:18px;}
    -.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
    -.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
    -.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
    -.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
    -.input-mini{width:60px;}
    -.input-small{width:90px;}
    -.input-medium{width:150px;}
    -.input-large{width:210px;}
    -.input-xlarge{width:270px;}
    -.input-xxlarge{width:530px;}
    -input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;}
    -.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;}
    -input,textarea,.uneditable-input{margin-left:0;}
    -.controls-row [class*="span"]+[class*="span"]{margin-left:20px;}
    -input.span12, textarea.span12, .uneditable-input.span12{width:926px;}
    -input.span11, textarea.span11, .uneditable-input.span11{width:846px;}
    -input.span10, textarea.span10, .uneditable-input.span10{width:766px;}
    -input.span9, textarea.span9, .uneditable-input.span9{width:686px;}
    -input.span8, textarea.span8, .uneditable-input.span8{width:606px;}
    -input.span7, textarea.span7, .uneditable-input.span7{width:526px;}
    -input.span6, textarea.span6, .uneditable-input.span6{width:446px;}
    -input.span5, textarea.span5, .uneditable-input.span5{width:366px;}
    -input.span4, textarea.span4, .uneditable-input.span4{width:286px;}
    -input.span3, textarea.span3, .uneditable-input.span3{width:206px;}
    -input.span2, textarea.span2, .uneditable-input.span2{width:126px;}
    -input.span1, textarea.span1, .uneditable-input.span1{width:46px;}
    -.controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;}
    -.controls-row:after{clear:both;}
    -.controls-row [class*="span"]{float:left;}
    -input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;}
    -input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;}
    -.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
    -.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.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 input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;}
    -.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
    -.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
    -.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.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 input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;}
    -.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
    -.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
    -.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.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 input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;}
    -.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;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{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
    -.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;}
    -.form-actions:after{clear:both;}
    -.help-block,.help-inline{color:#595959;}
    -.help-block{display:block;margin-bottom:10px;}
    -.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
    -.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;font-size:14px;vertical-align:top;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;}
    -.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;}
    -.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;}
    -.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
    -.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
    -.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;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;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
    -.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
    -.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
    -input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
    -.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
    -.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
    -.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
    -.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
    -.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;}
    -.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
    -.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;}
    -.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
    -.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
    -.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;}
    -.control-group{margin-bottom:10px;}
    -legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;}
    -.form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;}
    -.form-horizontal .control-group:after{clear:both;}
    -.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;}
    -.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;}
    -.form-horizontal .help-block{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:180px;}
    -.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 14px;margin-bottom:0;font-size:14px;line-height:20px;*line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #bbbbbb;*border:0;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}
    -.btn:active,.btn.active{background-color:#cccccc \9;}
    -.btn:first-child{*margin-left:0;}
    -.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
    -.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
    -.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);}
    -.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
    -.btn-large{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
    -.btn-large [class^="icon-"]{margin-top:2px;}
    -.btn-small{padding:3px 9px;font-size:12px;line-height:18px;}
    -.btn-small [class^="icon-"]{margin-top:0;}
    -.btn-mini{padding:2px 6px;font-size:11px;line-height:17px;}
    -.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
    -.btn-block+.btn-block{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,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
    -.btn{border-color:#c5c5c5;border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);}
    -.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}
    -.btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
    -.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}
    -.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
    -.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}
    -.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
    -.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}
    -.btn-success:active,.btn-success.active{background-color:#408140 \9;}
    -.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}
    -.btn-info:active,.btn-info.active{background-color:#24748c \9;}
    -.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}
    -.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
    -button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
    -button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
    -button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
    -button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
    -.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
    -.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent;}
    -.btn-link[disabled]:hover{color:#333333;text-decoration:none;}
    -[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px;}
    -.icon-white,.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-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png");}
    -.icon-glass{background-position:0 0;}
    -.icon-music{background-position:-24px 0;}
    -.icon-search{background-position:-48px 0;}
    -.icon-envelope{background-position:-72px 0;}
    -.icon-heart{background-position:-96px 0;}
    -.icon-star{background-position:-120px 0;}
    -.icon-star-empty{background-position:-144px 0;}
    -.icon-user{background-position:-168px 0;}
    -.icon-film{background-position:-192px 0;}
    -.icon-th-large{background-position:-216px 0;}
    -.icon-th{background-position:-240px 0;}
    -.icon-th-list{background-position:-264px 0;}
    -.icon-ok{background-position:-288px 0;}
    -.icon-remove{background-position:-312px 0;}
    -.icon-zoom-in{background-position:-336px 0;}
    -.icon-zoom-out{background-position:-360px 0;}
    -.icon-off{background-position:-384px 0;}
    -.icon-signal{background-position:-408px 0;}
    -.icon-cog{background-position:-432px 0;}
    -.icon-trash{background-position:-456px 0;}
    -.icon-home{background-position:0 -24px;}
    -.icon-file{background-position:-24px -24px;}
    -.icon-time{background-position:-48px -24px;}
    -.icon-road{background-position:-72px -24px;}
    -.icon-download-alt{background-position:-96px -24px;}
    -.icon-download{background-position:-120px -24px;}
    -.icon-upload{background-position:-144px -24px;}
    -.icon-inbox{background-position:-168px -24px;}
    -.icon-play-circle{background-position:-192px -24px;}
    -.icon-repeat{background-position:-216px -24px;}
    -.icon-refresh{background-position:-240px -24px;}
    -.icon-list-alt{background-position:-264px -24px;}
    -.icon-lock{background-position:-287px -24px;}
    -.icon-flag{background-position:-312px -24px;}
    -.icon-headphones{background-position:-336px -24px;}
    -.icon-volume-off{background-position:-360px -24px;}
    -.icon-volume-down{background-position:-384px -24px;}
    -.icon-volume-up{background-position:-408px -24px;}
    -.icon-qrcode{background-position:-432px -24px;}
    -.icon-barcode{background-position:-456px -24px;}
    -.icon-tag{background-position:0 -48px;}
    -.icon-tags{background-position:-25px -48px;}
    -.icon-book{background-position:-48px -48px;}
    -.icon-bookmark{background-position:-72px -48px;}
    -.icon-print{background-position:-96px -48px;}
    -.icon-camera{background-position:-120px -48px;}
    -.icon-font{background-position:-144px -48px;}
    -.icon-bold{background-position:-167px -48px;}
    -.icon-italic{background-position:-192px -48px;}
    -.icon-text-height{background-position:-216px -48px;}
    -.icon-text-width{background-position:-240px -48px;}
    -.icon-align-left{background-position:-264px -48px;}
    -.icon-align-center{background-position:-288px -48px;}
    -.icon-align-right{background-position:-312px -48px;}
    -.icon-align-justify{background-position:-336px -48px;}
    -.icon-list{background-position:-360px -48px;}
    -.icon-indent-left{background-position:-384px -48px;}
    -.icon-indent-right{background-position:-408px -48px;}
    -.icon-facetime-video{background-position:-432px -48px;}
    -.icon-picture{background-position:-456px -48px;}
    -.icon-pencil{background-position:0 -72px;}
    -.icon-map-marker{background-position:-24px -72px;}
    -.icon-adjust{background-position:-48px -72px;}
    -.icon-tint{background-position:-72px -72px;}
    -.icon-edit{background-position:-96px -72px;}
    -.icon-share{background-position:-120px -72px;}
    -.icon-check{background-position:-144px -72px;}
    -.icon-move{background-position:-168px -72px;}
    -.icon-step-backward{background-position:-192px -72px;}
    -.icon-fast-backward{background-position:-216px -72px;}
    -.icon-backward{background-position:-240px -72px;}
    -.icon-play{background-position:-264px -72px;}
    -.icon-pause{background-position:-288px -72px;}
    -.icon-stop{background-position:-312px -72px;}
    -.icon-forward{background-position:-336px -72px;}
    -.icon-fast-forward{background-position:-360px -72px;}
    -.icon-step-forward{background-position:-384px -72px;}
    -.icon-eject{background-position:-408px -72px;}
    -.icon-chevron-left{background-position:-432px -72px;}
    -.icon-chevron-right{background-position:-456px -72px;}
    -.icon-plus-sign{background-position:0 -96px;}
    -.icon-minus-sign{background-position:-24px -96px;}
    -.icon-remove-sign{background-position:-48px -96px;}
    -.icon-ok-sign{background-position:-72px -96px;}
    -.icon-question-sign{background-position:-96px -96px;}
    -.icon-info-sign{background-position:-120px -96px;}
    -.icon-screenshot{background-position:-144px -96px;}
    -.icon-remove-circle{background-position:-168px -96px;}
    -.icon-ok-circle{background-position:-192px -96px;}
    -.icon-ban-circle{background-position:-216px -96px;}
    -.icon-arrow-left{background-position:-240px -96px;}
    -.icon-arrow-right{background-position:-264px -96px;}
    -.icon-arrow-up{background-position:-289px -96px;}
    -.icon-arrow-down{background-position:-312px -96px;}
    -.icon-share-alt{background-position:-336px -96px;}
    -.icon-resize-full{background-position:-360px -96px;}
    -.icon-resize-small{background-position:-384px -96px;}
    -.icon-plus{background-position:-408px -96px;}
    -.icon-minus{background-position:-433px -96px;}
    -.icon-asterisk{background-position:-456px -96px;}
    -.icon-exclamation-sign{background-position:0 -120px;}
    -.icon-gift{background-position:-24px -120px;}
    -.icon-leaf{background-position:-48px -120px;}
    -.icon-fire{background-position:-72px -120px;}
    -.icon-eye-open{background-position:-96px -120px;}
    -.icon-eye-close{background-position:-120px -120px;}
    -.icon-warning-sign{background-position:-144px -120px;}
    -.icon-plane{background-position:-168px -120px;}
    -.icon-calendar{background-position:-192px -120px;}
    -.icon-random{background-position:-216px -120px;width:16px;}
    -.icon-comment{background-position:-240px -120px;}
    -.icon-magnet{background-position:-264px -120px;}
    -.icon-chevron-up{background-position:-288px -120px;}
    -.icon-chevron-down{background-position:-313px -119px;}
    -.icon-retweet{background-position:-336px -120px;}
    -.icon-shopping-cart{background-position:-360px -120px;}
    -.icon-folder-close{background-position:-384px -120px;}
    -.icon-folder-open{background-position:-408px -120px;width:16px;}
    -.icon-resize-vertical{background-position:-432px -119px;}
    -.icon-resize-horizontal{background-position:-456px -118px;}
    -.icon-hdd{background-position:0 -144px;}
    -.icon-bullhorn{background-position:-24px -144px;}
    -.icon-bell{background-position:-48px -144px;}
    -.icon-certificate{background-position:-72px -144px;}
    -.icon-thumbs-up{background-position:-96px -144px;}
    -.icon-thumbs-down{background-position:-120px -144px;}
    -.icon-hand-right{background-position:-144px -144px;}
    -.icon-hand-left{background-position:-168px -144px;}
    -.icon-hand-up{background-position:-192px -144px;}
    -.icon-hand-down{background-position:-216px -144px;}
    -.icon-circle-arrow-right{background-position:-240px -144px;}
    -.icon-circle-arrow-left{background-position:-264px -144px;}
    -.icon-circle-arrow-up{background-position:-288px -144px;}
    -.icon-circle-arrow-down{background-position:-312px -144px;}
    -.icon-globe{background-position:-336px -144px;}
    -.icon-wrench{background-position:-360px -144px;}
    -.icon-tasks{background-position:-384px -144px;}
    -.icon-filter{background-position:-408px -144px;}
    -.icon-briefcase{background-position:-432px -144px;}
    -.icon-fullscreen{background-position:-456px -144px;}
    -.btn-group{position:relative;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;}
    -.btn-group+.btn-group{margin-left:5px;}
    -.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
    -.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px;}
    -.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.btn-group>.btn+.btn{margin-left:-1px;}
    -.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px;}
    -.btn-group>.btn-mini{font-size:11px;}
    -.btn-group>.btn-small{font-size:12px;}
    -.btn-group>.btn-large{font-size:16px;}
    -.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
    -.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
    -.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
    -.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
    -.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}
    -.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
    -.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:5px;*padding-bottom:5px;}
    -.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;}
    -.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}
    -.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;}
    -.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);}
    -.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}
    -.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;}
    -.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}
    -.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}
    -.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}
    -.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}
    -.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}
    -.btn .caret{margin-top:8px;margin-left:0;}
    -.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px;}
    -.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;}
    -.dropup .btn-large .caret{border-bottom:5px solid #000000;border-top:0;}
    -.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
    -.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}
    -.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.btn-group-vertical .btn+.btn{margin-left:0;margin-top:-1px;}
    -.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
    -.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
    -.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;}
    -.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
    -.nav{margin-left:0;margin-bottom:20px;list-style:none;}
    -.nav>li>a{display:block;}
    -.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
    -.nav>.pull-right{float:right;}
    -.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
    -.nav li+.nav-header{margin-top:9px;}
    -.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
    -.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
    -.nav-list>li>a{padding:3px 15px;}
    -.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
    -.nav-list [class^="icon-"]{margin-right:2px;}
    -.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
    -.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;}
    -.nav-tabs:after,.nav-pills:after{clear:both;}
    -.nav-tabs>li,.nav-pills>li{float:left;}
    -.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
    -.nav-tabs{border-bottom:1px solid #ddd;}
    -.nav-tabs>li{margin-bottom:-1px;}
    -.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
    -.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
    -.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
    -.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;}
    -.nav-stacked>li{float:none;}
    -.nav-stacked>li>a{margin-right:0;}
    -.nav-tabs.nav-stacked{border-bottom:0;}
    -.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}
    -.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
    -.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
    -.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
    -.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
    -.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
    -.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
    -.nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}
    -.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;}
    -.nav-tabs .dropdown-toggle .caret{margin-top:8px;}
    -.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;}
    -.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}
    -.nav>.dropdown.active>a:hover{cursor:pointer;}
    -.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
    -.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
    -.tabs-stacked .open>a:hover{border-color:#999999;}
    -.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;}
    -.tabbable:after{clear:both;}
    -.tab-content{overflow:auto;}
    -.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;}
    -.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
    -.tab-content>.active,.pill-content>.active{display:block;}
    -.tabs-below>.nav-tabs{border-top:1px solid #ddd;}
    -.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;}
    -.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
    -.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd;}
    -.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;}
    -.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
    -.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
    -.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
    -.tabs-left>.nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
    -.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
    -.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
    -.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
    -.tabs-right>.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
    -.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
    -.nav>.disabled>a{color:#999999;}
    -.nav>.disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default;}
    -.navbar{overflow:visible;margin-bottom:20px;color:#777777;*position:relative;*z-index:2;}
    -.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-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);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;}
    -.navbar-inner:after{clear:both;}
    -.navbar .container{width:auto;}
    -.nav-collapse.collapse{height:auto;}
    -.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover{text-decoration:none;}
    -.navbar-text{margin-bottom:0;line-height:40px;}
    -.navbar-link{color:#777777;}.navbar-link:hover{color:#333333;}
    -.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;}
    -.navbar .btn,.navbar .btn-group{margin-top:5px;}
    -.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0;}
    -.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;}
    -.navbar-form:after{clear:both;}
    -.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
    -.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;}
    -.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
    -.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}
    -.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
    -.navbar-static-top{position:static;width:100%;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}
    -.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;}
    -.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;}
    -.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
    -.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
    -.navbar-fixed-top{top:0;}
    -.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);}
    -.navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1);}
    -.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
    -.navbar .nav.pull-right{float:right;margin-right:0;}
    -.navbar .nav>li{float:left;}
    -.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;}
    -.navbar .nav .dropdown-toggle .caret{margin-top:8px;}
    -.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;}
    -.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);}
    -.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;}
    -.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;}
    -.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
    -.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
    -.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
    -.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
    -.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;}
    -.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}
    -.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;}
    -.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;}
    -.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}
    -.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;}
    -.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;}
    -.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
    -.navbar-inverse{color:#999999;}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;}
    -.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#ffffff;}
    -.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;}
    -.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;}
    -.navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover{color:#ffffff;}
    -.navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;}
    -.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;}
    -.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;}
    -.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
    -.navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;}
    -.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;}
    -.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}
    -.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
    -.navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;}
    -.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;}
    -.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}
    -.breadcrumb .divider{padding:0 5px;color:#ccc;}
    -.breadcrumb .active{color:#999999;}
    -.pagination{height:40px;margin:20px 0;}
    -.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
    -.pagination ul>li{display:inline;}
    -.pagination ul>li>a,.pagination ul>li>span{float:left;padding:0 14px;line-height:38px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;}
    -.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;}
    -.pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;}
    -.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999999;background-color:transparent;cursor:default;}
    -.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 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;}
    -.pagination-centered{text-align:center;}
    -.pagination-right{text-align:right;}
    -.pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;}
    -.pager:after{clear:both;}
    -.pager li{display:inline;}
    -.pager a,.pager span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
    -.pager a:hover{text-decoration:none;background-color:#f5f5f5;}
    -.pager .next a,.pager .next span{float:right;}
    -.pager .previous a{float:left;}
    -.pager .disabled a,.pager .disabled a:hover,.pager .disabled span{color:#999999;background-color:#fff;cursor:default;}
    -.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;}
    -.thumbnails:after{clear:both;}
    -.row-fluid .thumbnails{margin-left:0;}
    -.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;}
    -.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}
    -a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
    -.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
    -.thumbnail .caption{padding:9px;color:#555555;}
    -.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;}
    -.alert h4{margin:0;}
    -.alert .close{position:relative;top:-2px;right:-21px;line-height:20px;}
    -.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
    -.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
    -.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
    -.alert-block{padding-top:14px;padding-bottom:14px;}
    -.alert-block>p,.alert-block>ul{margin-bottom:0;}
    -.alert-block p+p{margin-top:5px;}
    -@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
    -.progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
    -.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);}
    -.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
    -.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
    -.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);}
    -.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
    -.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);}
    -.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
    -.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);}
    -.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
    -.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);}
    -.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
    -.hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;}
    -.hero-unit p{font-size:18px;font-weight:200;line-height:30px;color:inherit;}
    -.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
    -.tooltip.top{margin-top:-3px;}
    -.tooltip.right{margin-left:3px;}
    -.tooltip.bottom{margin-top:3px;}
    -.tooltip.left{margin-left:-3px;}
    -.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
    -.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;}
    -.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;}
    -.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;}
    -.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;}
    -.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;}
    -.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);}.popover.top{margin-bottom:10px;}
    -.popover.right{margin-left:10px;}
    -.popover.bottom{margin-top:10px;}
    -.popover.left{margin-right:10px;}
    -.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}
    -.popover-content{padding:9px 14px;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}
    -.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid;}
    -.popover .arrow:after{content:"";z-index:-1;}
    -.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-width:10px 10px 0;border-top-color:#ffffff;}.popover.top .arrow:after{border-width:11px 11px 0;border-top-color:rgba(0, 0, 0, 0.25);bottom:-1px;left:-11px;}
    -.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-width:10px 10px 10px 0;border-right-color:#ffffff;}.popover.right .arrow:after{border-width:11px 11px 11px 0;border-right-color:rgba(0, 0, 0, 0.25);bottom:-11px;left:-1px;}
    -.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-width:0 10px 10px;border-bottom-color:#ffffff;}.popover.bottom .arrow:after{border-width:0 11px 11px;border-bottom-color:rgba(0, 0, 0, 0.25);top:-1px;left:-11px;}
    -.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-width:10px 0 10px 10px;border-left-color:#ffffff;}.popover.left .arrow:after{border-width:11px 0 11px 11px;border-left-color:rgba(0, 0, 0, 0.25);bottom:-11px;right:-1px;}
    -.modal-open .modal .dropdown-menu{z-index:2050;}
    -.modal-open .modal .dropdown.open{*z-index:2050;}
    -.modal-open .modal .popover{z-index:2060;}
    -.modal-open .modal .tooltip{z-index:2080;}
    -.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
    -.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
    -.modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
    -.modal.fade.in{top:50%;}
    -.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
    -.modal-header h3{margin:0;line-height:30px;}
    -.modal-body{overflow-y:auto;max-height:400px;padding:15px;}
    -.modal-form{margin-bottom:0;}
    -.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;}
    -.modal-footer:after{clear:both;}
    -.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
    -.modal-footer .btn-group .btn+.btn{margin-left:-1px;}
    -.dropup,.dropdown{position:relative;}
    -.dropdown-toggle{*margin-bottom:-3px;}
    -.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
    -.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";}
    -.dropdown .caret{margin-top:8px;margin-left:2px;}
    -.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;}
    -.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
    -.dropdown-menu a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;}
    -.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{text-decoration:none;color:#ffffff;background-color:#0088cc;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
    -.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;outline:0;background-color:#0088cc;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
    -.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999999;}
    -.dropdown-menu .disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default;}
    -.open{*z-index:1000;}.open >.dropdown-menu{display:block;}
    -.pull-right>.dropdown-menu{right:0;left:auto;}
    -.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";}
    -.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}
    -.dropdown-submenu{position:relative;}
    -.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
    -.dropdown-submenu:hover>.dropdown-menu{display:block;}
    -.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}
    -.dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
    -.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;}
    -.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
    -.accordion{margin-bottom:20px;}
    -.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
    -.accordion-heading{border-bottom:0;}
    -.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
    -.accordion-toggle{cursor:pointer;}
    -.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
    -.carousel{position:relative;margin-bottom:20px;line-height:1;}
    -.carousel-inner{overflow:hidden;width:100%;position:relative;}
    -.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
    -.carousel .item>img{display:block;line-height:1;}
    -.carousel .active,.carousel .next,.carousel .prev{display:block;}
    -.carousel .active{left:0;}
    -.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}
    -.carousel .next{left:100%;}
    -.carousel .prev{left:-100%;}
    -.carousel .next.left,.carousel .prev.right{left:0;}
    -.carousel .active.left{left:-100%;}
    -.carousel .active.right{left:100%;}
    -.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
    -.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
    -.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);}
    -.carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;}
    -.carousel-caption h4{margin:0 0 5px;}
    -.carousel-caption p{margin-bottom:0;}
    -.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
    -.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
    -.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
    -.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}
    -button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}
    -.pull-right{float:right;}
    -.pull-left{float:left;}
    -.hide{display:none;}
    -.show{display:block;}
    -.invisible{visibility:hidden;}
    -.affix{position:fixed;}
    -.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;}
    -.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;}
    -.hidden{display:none;visibility:hidden;}
    -.visible-phone{display:none !important;}
    -.visible-tablet{display:none !important;}
    -.hidden-desktop{display:none !important;}
    -.visible-desktop{display:inherit !important;}
    -@media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important ;} .visible-tablet{display:inherit !important;} .hidden-tablet{display:none !important;}}@media (max-width:767px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important;} .visible-phone{display:inherit !important;} .hidden-phone{display:none !important;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px;} .container-fluid{padding:0;} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left;} .dl-horizontal dd{margin-left:0;} .container{width:auto;} .row-fluid{width:100%;} .row,.thumbnails{margin-left:0;} .thumbnails>li{float:none;margin-left:0;} [class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto;} .controls-row [class*="span"]+[class*="span"]{margin-left:0;} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0;}.modal.fade.in{top:auto;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:20px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{top:10px;left:10px;right:10px;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12, textarea.span12, .uneditable-input.span12{width:710px;} input.span11, textarea.span11, .uneditable-input.span11{width:648px;} input.span10, textarea.span10, .uneditable-input.span10{width:586px;} input.span9, textarea.span9, .uneditable-input.span9{width:524px;} input.span8, textarea.span8, .uneditable-input.span8{width:462px;} input.span7, textarea.span7, .uneditable-input.span7{width:400px;} input.span6, textarea.span6, .uneditable-input.span6{width:338px;} input.span5, textarea.span5, .uneditable-input.span5{width:276px;} input.span4, textarea.span4, .uneditable-input.span4{width:214px;} input.span3, textarea.span3, .uneditable-input.span3{width:152px;} input.span2, textarea.span2, .uneditable-input.span2{width:90px;} input.span1, textarea.span1, .uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12, textarea.span12, .uneditable-input.span12{width:1156px;} input.span11, textarea.span11, .uneditable-input.span11{width:1056px;} input.span10, textarea.span10, .uneditable-input.span10{width:956px;} input.span9, textarea.span9, .uneditable-input.span9{width:856px;} input.span8, textarea.span8, .uneditable-input.span8{width:756px;} input.span7, textarea.span7, .uneditable-input.span7{width:656px;} input.span6, textarea.span6, .uneditable-input.span6{width:556px;} input.span5, textarea.span5, .uneditable-input.span5{width:456px;} input.span4, textarea.span4, .uneditable-input.span4{width:356px;} input.span3, textarea.span3, .uneditable-input.span3{width:256px;} input.span2, textarea.span2, .uneditable-input.span2{width:156px;} input.span1, textarea.span1, .uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:static;} .navbar-fixed-top{margin-bottom:20px;} .navbar-fixed-bottom{margin-top:20px;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .nav-collapse{clear:both;} .nav-collapse .nav{float:none;margin:0 0 10px;} .nav-collapse .nav>li{float:none;} .nav-collapse .nav>li>a{margin-bottom:2px;} .nav-collapse .nav>.divider-vertical{display:none;} .nav-collapse .nav .nav-header{color:#777777;text-shadow:none;} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px;} .nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2;} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111111;} .nav-collapse.in .btn-group{margin-top:5px;padding:0;} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none;} .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;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);-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;} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0;} .navbar .btn-navbar{display:block;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}}
    + * Bootstrap v3.2.0 (http://getbootstrap.com)
    + * Copyright 2011-2014 Twitter, Inc.
    + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
    + *//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;width:100% \9;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143 \0}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{position:absolute;z-index:-1;filter:alpha(opacity=0);opacity:0}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#777}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#777}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#777}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{min-width:30px;color:#777;background-color:transparent;background-image:none;-webkit-box-shadow:none;box-shadow:none}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate3d(0,-25%,0);-o-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0)}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
    \ No newline at end of file
    diff --git a/rest_framework/static/rest_framework/css/default.css b/rest_framework/static/rest_framework/css/default.css
    index 461cdfe5c..4f52cc566 100644
    --- a/rest_framework/static/rest_framework/css/default.css
    +++ b/rest_framework/static/rest_framework/css/default.css
    @@ -33,7 +33,11 @@ h2, h3 {
     }
     
     ul.breadcrumb {
    -  margin: 80px 0 0 0;
    +  margin: 70px 0 0 0;
    +}
    +
    +.breadcrumb li.active a {
    +  color: #777;
     }
     
     form select, form input, form textarea {
    @@ -67,5 +71,4 @@ pre {
     .page-header {
       border-bottom: none;
       padding-bottom: 0px;
    -  margin-bottom: 20px;
     }
    diff --git a/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot
    new file mode 100644
    index 000000000..4a4ca865d
    Binary files /dev/null and b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot differ
    diff --git a/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg
    new file mode 100644
    index 000000000..25691af8f
    --- /dev/null
    +++ b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.svg
    @@ -0,0 +1,229 @@
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file
    diff --git a/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf
    new file mode 100644
    index 000000000..67fa00bf8
    Binary files /dev/null and b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf differ
    diff --git a/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff
    new file mode 100644
    index 000000000..8c54182aa
    Binary files /dev/null and b/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff differ
    diff --git a/rest_framework/static/rest_framework/js/bootstrap.min.js b/rest_framework/static/rest_framework/js/bootstrap.min.js
    index e0b220f40..7c1561a8b 100644
    --- a/rest_framework/static/rest_framework/js/bootstrap.min.js
    +++ b/rest_framework/static/rest_framework/js/bootstrap.min.js
    @@ -1,7 +1,6 @@
    -/**
    -* Bootstrap.js by @fat & @mdo
    -* plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-scrollspy.js, bootstrap-tab.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-affix.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-carousel.js, bootstrap-typeahead.js
    -* Copyright 2012 Twitter, Inc.
    -* http://www.apache.org/licenses/LICENSE-2.0.txt
    -*/
    -!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1).focus(),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(a){this.$element.hide().trigger("hidden"),this.backdrop()},removeBackdrop:function(){this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('