Merge remote-tracking branch 'upstream/master'

This commit is contained in:
khamaileon 2014-08-10 19:33:42 +02:00
commit 8c1d93a166
80 changed files with 375 additions and 57 deletions

View File

@ -8,7 +8,7 @@ python:
- "3.4" - "3.4"
env: env:
- DJANGO="https://www.djangoproject.com/download/1.7.b4/tarball/" - DJANGO="https://www.djangoproject.com/download/1.7c2/tarball/"
- DJANGO="django==1.6.5" - DJANGO="django==1.6.5"
- DJANGO="django==1.5.8" - DJANGO="django==1.5.8"
- DJANGO="django==1.4.13" - DJANGO="django==1.4.13"
@ -16,15 +16,13 @@ env:
install: install:
- pip install $DJANGO - pip install $DJANGO
- pip install defusedxml==0.3 Pillow==2.3.0 - pip install defusedxml==0.3 Pillow==2.3.0 django-guardian==1.2.3
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.4; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.4; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-guardian==1.1.1; fi"
- "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi" - "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi"
- "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi" - "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} == '3' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7c2/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi"
- "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7.b4/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi"
- export PYTHONPATH=. - export PYTHONPATH=.
script: script:
@ -33,7 +31,7 @@ script:
matrix: matrix:
exclude: exclude:
- python: "2.6" - python: "2.6"
env: DJANGO="https://www.djangoproject.com/download/1.7.b4/tarball/" env: DJANGO="https://www.djangoproject.com/download/1.7c2/tarball/"
- python: "3.2" - python: "3.2"
env: DJANGO="django==1.4.13" env: DJANGO="django==1.4.13"
- python: "3.2" - python: "3.2"

View File

@ -1,3 +1,13 @@
---
#### Django REST framework 3 - Kickstarter announcement!
We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3.
If you want to help drive sustainable open-source development forward, then **please check out [the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.**
---
# Django REST framework # Django REST framework
[![build-status-image]][travis] [![build-status-image]][travis]
@ -136,6 +146,7 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 [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 [travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master
[twitter]: https://twitter.com/_tomchristie [twitter]: https://twitter.com/_tomchristie

View File

@ -347,7 +347,7 @@ As an example, let's create a field that can be used represent the class name of
""" """
Serialize the object's class name. Serialize the object's class name.
""" """
return obj.__class__ return obj.__class__.__name__
# Third party packages # Third party packages
@ -357,9 +357,20 @@ The following third party packages are also available.
The [drf-compound-fields][drf-compound-fields] package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the `many=True` option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type. The [drf-compound-fields][drf-compound-fields] package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the `many=True` option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type.
## DRF Extra Fields
The [drf-extra-fields][drf-extra-fields] package provides extra serializer fields for REST framework, including `Base64ImageField` and `PointField` classes.
## django-rest-framework-gis
The [django-rest-framework-gis][django-rest-framework-gis] package provides geographic addons for django rest framework like a `GeometryField` field and a GeoJSON serializer.
[cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data [cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data
[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS [FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS
[ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 [ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
[strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior [strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
[iso8601]: http://www.w3.org/TR/NOTE-datetime [iso8601]: http://www.w3.org/TR/NOTE-datetime
[drf-compound-fields]: http://drf-compound-fields.readthedocs.org [drf-compound-fields]: http://drf-compound-fields.readthedocs.org
[drf-extra-fields]: https://github.com/Hipo/drf-extra-fields
[django-rest-framework-gis]: https://github.com/djangonauts/django-rest-framework-gis

View File

@ -199,8 +199,7 @@ This enables us to make queries like:
http://example.com/api/products?manufacturer__name=foo http://example.com/api/products?manufacturer__name=foo
This is nice, but it shows underlying model structure in REST API, which may This is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the `FilterSet` class:
be undesired, but you can use:
import django_filters import django_filters
from myapp.models import Product from myapp.models import Product
@ -208,7 +207,6 @@ be undesired, but you can use:
from rest_framework import generics from rest_framework import generics
class ProductFilter(django_filters.FilterSet): class ProductFilter(django_filters.FilterSet):
manufacturer = django_filters.CharFilter(name="manufacturer__name") manufacturer = django_filters.CharFilter(name="manufacturer__name")
class Meta: class Meta:

View File

@ -36,6 +36,12 @@ For example:
self.check_object_permissions(self.request, obj) self.check_object_permissions(self.request, obj)
return obj return obj
#### Limitations of object level permissions
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
Often when you're using object level permissions you'll also want to [filter the queryset][filtering] appropriately, to ensure that users only have visibility onto instances that they are permitted to view.
## Setting the permission policy ## Setting the permission policy
The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example. The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example.
@ -237,7 +243,8 @@ The [REST Condition][rest-condition] package is another extension for building c
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html [cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
[authentication]: authentication.md [authentication]: authentication.md
[throttling]: throttling.md [throttling]: throttling.md
[contribauth]: https://docs.djangoproject.com/en/1.0/topics/auth/#permissions [filtering]: filtering.md
[contribauth]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-permissions
[objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions [objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions
[guardian]: https://github.com/lukaszb/django-guardian [guardian]: https://github.com/lukaszb/django-guardian
[get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user [get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user

View File

@ -179,7 +179,16 @@ The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (an
app.router.register_model(MyModel) app.router.register_model(MyModel)
## DRF-extensions
The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions-routers] for creating [nested viewsets][drf-extensions-nested-viewsets], [collection level controllers][drf-extensions-collection-level-controllers] with [customizable endpoint names][drf-extensions-customizable-endpoint-names].
[cite]: http://guides.rubyonrails.org/routing.html [cite]: http://guides.rubyonrails.org/routing.html
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
[wq.db]: http://wq.io/wq.db [wq.db]: http://wq.io/wq.db
[wq.db-router]: http://wq.io/docs/app.py [wq.db-router]: http://wq.io/docs/app.py
[drf-extensions]: http://chibisov.github.io/drf-extensions/docs/
[drf-extensions-routers]: http://chibisov.github.io/drf-extensions/docs/#routers
[drf-extensions-nested-viewsets]: http://chibisov.github.io/drf-extensions/docs/#nested-routes
[drf-extensions-collection-level-controllers]: http://chibisov.github.io/drf-extensions/docs/#collection-level-controllers
[drf-extensions-customizable-endpoint-names]: http://chibisov.github.io/drf-extensions/docs/#controller-endpoint-name

View File

@ -580,7 +580,21 @@ The following custom model serializer could be used as a base class for model se
def get_pk_field(self, model_field): def get_pk_field(self, model_field):
return None return None
---
# Third party packages
The following third party packages are also available.
## MongoengineModelSerializer
The [django-rest-framework-mongoengine][mongoengine] package provides a `MongoEngineModelSerializer` serializer class that supports using MongoDB as the storage layer for Django REST framework.
## GeoFeatureModelSerializer
The [django-rest-framework-gis][django-rest-framework-gis] package provides a `GeoFeatureModelSerializer` serializer class that supports GeoJSON both for read and write operations.
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion [cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
[relations]: relations.md [relations]: relations.md
[mongoengine]: https://github.com/umutbozkurt/django-rest-framework-mongoengine
[django-rest-framework-gis]: https://github.com/djangonauts/django-rest-framework-gis

View File

@ -58,7 +58,7 @@ using the `APIView` class based views.
Or, if you're using the `@api_view` decorator with function based views. Or, if you're using the `@api_view` decorator with function based views.
@api_view('GET') @api_view(['GET'])
@throttle_classes([UserRateThrottle]) @throttle_classes([UserRateThrottle])
def example_view(request, format=None): def example_view(request, format=None):
content = { content = {

View File

@ -307,3 +307,76 @@ table {
.side-nav { .side-nav {
overflow-y: scroll; overflow-y: scroll;
} }
ul.sponsor.diamond li a {
float: left;
width: 600px;
height: 20px;
text-align: center;
margin: 10px 70px;
padding: 300px 0 0 0;
background-position: 0 50%;
background-size: 600px auto;
background-repeat: no-repeat;
font-size: 200%;
}
@media (max-width: 1000px) {
ul.sponsor.diamond li a {
float: left;
width: 300px;
height: 20px;
text-align: center;
margin: 10px 40px;
padding: 300px 0 0 0;
background-position: 0 50%;
background-size: 280px auto;
background-repeat: no-repeat;
font-size: 150%;
}
}
ul.sponsor.platinum li a {
float: left;
width: 300px;
height: 20px;
text-align: center;
margin: 10px 40px;
padding: 300px 0 0 0;
background-position: 0 50%;
background-size: 280px auto;
background-repeat: no-repeat;
font-size: 150%;
}
ul.sponsor.gold li a {
float: left;
width: 130px;
height: 20px;
text-align: center;
margin: 10px 30px;
padding: 150px 0 0 0;
background-position: 0 50%;
background-size: 130px auto;
background-repeat: no-repeat;
font-size: 120%;
}
ul.sponsor.silver li a {
float: left;
width: 130px;
height: 20px;
text-align: center;
margin: 10px 30px;
padding: 150px 0 0 0;
background-position: 0 50%;
background-size: 130px auto;
background-repeat: no-repeat;
font-size: 120%;
}
ul.sponsor {
list-style: none;
display: block;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
docs/img/sponsors/2-sga.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
docs/img/sponsors/3-aba.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -9,6 +9,14 @@
--- ---
#### Django REST framework 3 - Kickstarter announcement!
We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3.
If you want to help drive sustainable open-source development **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.**
---
<p> <p>
<h1 style="position: absolute; <h1 style="position: absolute;
width: 1px; width: 1px;
@ -201,6 +209,7 @@ General guides to using REST framework.
* [2.0 Announcement][rest-framework-2-announcement] * [2.0 Announcement][rest-framework-2-announcement]
* [2.2 Announcement][2.2-announcement] * [2.2 Announcement][2.2-announcement]
* [2.3 Announcement][2.3-announcement] * [2.3 Announcement][2.3-announcement]
* [Kickstarter Announcement][kickstarter-announcement]
* [Release Notes][release-notes] * [Release Notes][release-notes]
* [Credits][credits] * [Credits][credits]
@ -325,6 +334,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[rest-framework-2-announcement]: topics/rest-framework-2-announcement.md [rest-framework-2-announcement]: topics/rest-framework-2-announcement.md
[2.2-announcement]: topics/2.2-announcement.md [2.2-announcement]: topics/2.2-announcement.md
[2.3-announcement]: topics/2.3-announcement.md [2.3-announcement]: topics/2.3-announcement.md
[kickstarter-announcement]: topics/kickstarter-announcement.md
[release-notes]: topics/release-notes.md [release-notes]: topics/release-notes.md
[credits]: topics/credits.md [credits]: topics/credits.md

View File

@ -33,6 +33,21 @@
})(); })();
</script> </script>
<style>
span.fusion-wrap a {
display: block;
margin-top: 10px;
color: black;
}
a.fusion-poweredby {
display: block;
margin-top: 10px;
}
@media (max-width: 767px) {
div.promo {display: none;}
}
</style>
</head> </head>
<body onload="prettyPrint()" class="{{ page_id }}-page"> <body onload="prettyPrint()" class="{{ page_id }}-page">
@ -106,6 +121,7 @@
<li><a href="{{ base_url }}/topics/rest-framework-2-announcement{{ suffix }}">2.0 Announcement</a></li> <li><a href="{{ base_url }}/topics/rest-framework-2-announcement{{ suffix }}">2.0 Announcement</a></li>
<li><a href="{{ base_url }}/topics/2.2-announcement{{ suffix }}">2.2 Announcement</a></li> <li><a href="{{ base_url }}/topics/2.2-announcement{{ suffix }}">2.2 Announcement</a></li>
<li><a href="{{ base_url }}/topics/2.3-announcement{{ suffix }}">2.3 Announcement</a></li> <li><a href="{{ base_url }}/topics/2.3-announcement{{ suffix }}">2.3 Announcement</a></li>
<li><a href="{{ base_url }}/topics/kickstarter-announcement{{ suffix }}">Kickstarter Announcement</a></li>
<li><a href="{{ base_url }}/topics/release-notes{{ suffix }}">Release Notes</a></li> <li><a href="{{ base_url }}/topics/release-notes{{ suffix }}">Release Notes</a></li>
<li><a href="{{ base_url }}/topics/credits{{ suffix }}">Credits</a></li> <li><a href="{{ base_url }}/topics/credits{{ suffix }}">Credits</a></li>
</ul> </ul>
@ -169,11 +185,9 @@
<div id="table-of-contents"> <div id="table-of-contents">
<ul class="nav nav-list side-nav well sidebar-nav-fixed"> <ul class="nav nav-list side-nav well sidebar-nav-fixed">
{{ toc }} {{ toc }}
<div> <div class="promo">
{{ ad_block }}
{{ ad_block }} </div>
</div>
</ul> </ul>
</div> </div>
@ -199,6 +213,7 @@
<script src="{{ base_url }}/js/jquery-1.8.1-min.js"></script> <script src="{{ base_url }}/js/jquery-1.8.1-min.js"></script>
<script src="{{ base_url }}/js/prettify-1.0.js"></script> <script src="{{ base_url }}/js/prettify-1.0.js"></script>
<script src="{{ base_url }}/js/bootstrap-2.1.1-min.js"></script> <script src="{{ base_url }}/js/bootstrap-2.1.1-min.js"></script>
<script> <script>
//$('.side-nav').scrollspy() //$('.side-nav').scrollspy()
var shiftWindow = function() { scrollBy(0, -50) }; var shiftWindow = function() { scrollBy(0, -50) };

View File

@ -167,10 +167,10 @@ You can now add the `autocomplete_light.ChoiceWidget` widget to the serializer f
[bootstrap]: http://getbootstrap.com [bootstrap]: http://getbootstrap.com
[cerulean]: ../img/cerulean.png [cerulean]: ../img/cerulean.png
[slate]: ../img/slate.png [slate]: ../img/slate.png
[bcustomize]: http://twitter.github.com/bootstrap/customize.html#variables [bcustomize]: http://getbootstrap.com/2.3.2/customize.html
[bswatch]: http://bootswatch.com/ [bswatch]: http://bootswatch.com/
[bcomponents]: http://twitter.github.com/bootstrap/components.html [bcomponents]: http://getbootstrap.com/2.3.2/components.html
[bcomponentsnav]: http://twitter.github.com/bootstrap/components.html#navbar [bcomponentsnav]: http://getbootstrap.com/2.3.2/components.html#navbar
[autocomplete-packages]: https://www.djangopackages.com/grids/g/auto-complete/ [autocomplete-packages]: https://www.djangopackages.com/grids/g/auto-complete/
[django-autocomplete-light]: https://github.com/yourlabs/django-autocomplete-light [django-autocomplete-light]: https://github.com/yourlabs/django-autocomplete-light
[django-autocomplete-light-install]: http://django-autocomplete-light.readthedocs.org/en/latest/#install [django-autocomplete-light-install]: http://django-autocomplete-light.readthedocs.org/en/latest/#install

View File

@ -0,0 +1,143 @@
# Kickstarting Django REST framework 3
---
<iframe width="480" height="360" src="https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3/widget/video.html" frameborder="0" scrolling="no"> </iframe>
---
In order to continue to drive the project forward, I'm launching a Kickstarter campaign to help fund the development of a major new release - Django REST framework 3.
## Project details
This new release will allow us to comprehensively address some of the shortcomings of the framework, and will aim to include the following:
* Faster, simpler and easier-to-use serializers.
* An alternative admin-style interface for the browsable API.
* Search and filtering controls made accessible in the browsable API.
* Alternative API pagination styles.
* Documentation around API versioning.
* Triage of outstanding tickets.
* Improving the ongoing quality and maintainability of the project.
Full details are available now on the [project page](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).
If you're interested in helping make sustainable open source development a reality please [visit the Kickstarter page](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding the project.
I can't wait to see where this takes us!
Many thanks to everyone for your support so far,
Tom Christie :)
---
## Sponsors
We've now blazed way past all our goals, with a staggering £30,000 (~$50,000), meaning I'll be in a position to work on the project significantly beyond what we'd originally planned for. I owe a huge debt of gratitude to all the wonderful companies and individuals who have been backing the project so generously, and making this possible.
---
### Platinum sponsors
Our platinum sponsors have each made a hugely substantial contribution to the future development of Django REST framework, and I simply can't thank them enough.
<ul class="sponsor diamond">
<li><a href="https://www.eventbrite.com/" rel="nofollow" style="background-image:url(../img/sponsors/0-eventbrite.png);">Eventbrite</a></li>
</ul>
<ul class="sponsor platinum">
<li><a href="https://www.divio.ch/" rel="nofollow" style="background-image:url(../img/sponsors/1-divio.png);">Divio</a></li>
<li><a href="http://company.onlulu.com/en/" rel="nofollow" style="background-image:url(../img/sponsors/1-lulu.png);">Lulu</a></li>
<li><a href="https://p.ota.to/" rel="nofollow" style="background-image:url(../img/sponsors/1-potato.png);">Potato</a></li>
<li><a href="http://www.wiredrive.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-wiredrive.png);">Wiredrive</a></li>
<li><a href="http://www.cyaninc.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-cyan.png);">Cyan</a></li>
<li><a href="https://www.runscope.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-runscope.png);">Runscope</a></li>
<li><a href="http://simpleenergy.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-simple-energy.png);">Simple Energy</a></li>
<li><a href="http://vokalinteractive.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-vokal_interactive.png);">VOKAL Interactive</a></li>
<li><a href="http://www.purplebit.com/" rel="nofollow" style="background-image:url(../img/sponsors/1-purplebit.png);">Purple Bit</a></li>
<li><a href="http://www.kuwaitnet.net/" rel="nofollow" style="background-image:url(../img/sponsors/1-kuwaitnet.png);">KuwaitNET</a></li>
</ul>
<div style="clear: both"></div>
---
### Gold sponsors
Our gold sponsors include companies large and small. Many thanks for their significant funding of the project and their commitment to sustainable open-source development.
<ul class="sponsor gold">
<li><a href="https://laterpay.net/" rel="nofollow" style="background-image:url(../img/sponsors/2-laterpay.png);">LaterPay</a></li>
<li><a href="https://www.schubergphilis.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-schuberg_philis.png);">Schuberg Philis</a></li>
<li><a href="http://prorenata.se/" rel="nofollow" style="background-image:url(../img/sponsors/2-prorenata.png);">ProReNata AB</a></li>
<li><a href="https://www.sgawebsites.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-sga.png);">SGA Websites</a></li>
<li><a href="http://www.sirono.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-sirono.png);">Sirono</a></li>
<li><a href="http://www.vinta.com.br/" rel="nofollow" style="background-image:url(../img/sponsors/2-vinta.png);">Vinta Software Studio</a></li>
<li><a href="http://www.rapasso.nl/index.php/en" rel="nofollow" style="background-image:url(../img/sponsors/2-rapasso.png);">Rapasso</a></li>
<li><a href="https://mirusresearch.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-mirus_research.png);">Mirus Research</a></li>
<li><a href="http://hipolabs.com" rel="nofollow" style="background-image:url(../img/sponsors/2-hipo.png);">Hipo</a></li>
<li><a href="http://www.byte.nl" rel="nofollow" style="background-image:url(../img/sponsors/2-byte.png);">Byte</a></li>
<li><a href="http://lightningkite.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-lightning_kite.png);">Lightning Kite</a></li>
<li><a href="https://opbeat.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-opbeat.png);">Opbeat</a></li>
<li><a href="https://koordinates.com" rel="nofollow" style="background-image:url(../img/sponsors/2-koordinates.png);">Koordinates</a></li>
<!--Xitij-->
<!--Howard-->
<li><a href="https://www.heroku.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-heroku.png);">Heroku</a></li>
<li><a href="https://www.galileo-press.de/" rel="nofollow" style="background-image:url(../img/sponsors/2-galileo_press.png);">Galileo Press</a></li>
<li><a href="http://www.securitycompass.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-security_compass.png);">Security Compass</a></li>
<li><a href="https://www.djangoproject.com/foundation/" rel="nofollow" style="background-image:url(../img/sponsors/2-django.png);">Django Software Foundation</a></li>
<li><a href="http://www.hipflaskapp.com" rel="nofollow" style="background-image:url(../img/sponsors/2-hipflask.png);">Hipflask</a></li>
<li><a href="http://www.crate.io/" rel="nofollow" style="background-image:url(../img/sponsors/2-crate.png);">Crate</a></li>
<li><a href="http://crypticocorp.com/" rel="nofollow" style="background-image:url(../img/sponsors/2-cryptico.png);">Cryptico Corp</a></li>
<li><a href="http://envisionlinux.org/blog" rel="nofollow">Envision Linux</a></li>
</ul>
<!--Name: Envision Linux text-->
<div style="clear: both;"></div>
---
### Silver sponsors
The serious financial contribution that our silver sponsors have made is very much appreciated. I'd like to say a particular thank&nbsp;you to individuals who have choosen to privately support the project at this level.
<ul class="sponsor silver">
<li><a href="http://www.imtapps.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-imt_computer_services.png);">IMT Computer Services</a></li>
<li><a href="http://wildfish.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-wildfish.png);">Wildfish</a></li>
<li><a href="http://www.thermondo.de/" rel="nofollow" style="background-image:url(../img/sponsors/3-thermondo-gmbh.png);">Thermondo GmbH</a></li>
<li><a href="http://providenz.fr/" rel="nofollow" style="background-image:url(../img/sponsors/3-providenz.png);">Providenz</a></li>
<li><a href="https://www.alwaysdata.com" rel="nofollow" style="background-image:url(../img/sponsors/3-alwaysdata.png);">alwaysdata.com</a></li>
<li><a href="http://www.triggeredmessaging.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-triggered_messaging.png);">Triggered Messaging</a></li>
<!--Markus-->
<li><a href="https://garfo.io/" rel="nofollow" style="background-image:url(../img/sponsors/3-garfo.png);">Garfo</a></li>
<li><a href="https://goshippo.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-shippo.png);">Shippo</a></li>
<!--Dylan-->
<li><a href="http://www.gizmag.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-gizmag.png);">Gizmag</a></li>
<li><a href="http://www.tivix.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-tivix.png);">Tivix</a></li>
<li><a href="http://www.safaribooksonline.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-safari.png);">Safari</a></li>
<li><a href="http://brightloop.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-brightloop.png);">Bright Loop</a></li>
<li><a href="http://www.aba-systems.com.au/" rel="nofollow" style="background-image:url(../img/sponsors/3-aba.png);">ABA Systems</a></li>
<li><a href="http://beefarm.ru/" rel="nofollow" style="background-image:url(../img/sponsors/3-beefarm.png);">beefarm.ru</a></li>
<li><a href="http://www.vzzual.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-vzzual.png);">Vzzual.com</a></li>
<!--Vzzual-->
<!--Linovia-->
<li><a href="http://infinite-code.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-infinite_code.png);">Infinite Code</a></li>
<!--Jon-->
<li><a href="https://www.pkgfarm.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-pkgfarm.png);">PkgFarm</a></li>
<li><a href="http://life.tl/" rel="nofollow" style="background-image:url(../img/sponsors/3-life_the_game.png);">Life. The Game.</a></li>
<li><a href="http://blimp.io/" rel="nofollow" style="background-image:url(../img/sponsors/3-blimp.png);">Blimp</a></li>
<li><a href="http://pathwright.com" rel="nofollow" style="background-image:url(../img/sponsors/3-pathwright.png);">Pathwright</a></li>
<li><a href="http://fluxility.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-fluxility.png);">Fluxility</a></li>
<li><a href="http://trackmaven.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-trackmaven.png);">TrackMaven</a></li>
<li><a href="http://www.nephila.co.uk/" rel="nofollow" style="background-image:url(../img/sponsors/3-nephila.png);">Nephila</a></li>
<!--Haris-->
<li><a href="http://www.aditium.com/" rel="nofollow" style="background-image:url(../img/sponsors/3-aditium.png);">Aditium</a></li>
<!--Craig-->
</ul>
<div style="clear: both; padding-bottom: 20px;"></div>
**Individual contributions**: Paul Hallet, <a href="http://www.paulwhippconsulting.com/">Paul Whipp</a>, Jannis Leidel, <a href="http://spielmannsolutions.com/">Johannes Spielmann</a>, <a href="http://chrisheisel.com/">Chris Heisel</a>, Marwan Alsabbagh.

View File

@ -29,7 +29,7 @@ Unlike all our other API endpoints, we don't want to use JSON, but instead just
The other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance. The other thing we need to consider when creating the code highlight view is that there's no existing concrete generic view that we can use. We're not returning an object instance, but instead a property of an object instance.
Instead of using a concrete generic view, we'll use the base class for representing instances, and create our own `.get()` method. In your snippets.views add: Instead of using a concrete generic view, we'll use the base class for representing instances, and create our own `.get()` method. In your `snippets.views` add:
from rest_framework import renderers from rest_framework import renderers
from rest_framework.response import Response from rest_framework.response import Response

View File

@ -162,8 +162,8 @@ for (dirpath, dirnames, filenames) in os.walk(docs_dir):
output = output.replace('{{ canonical_url }}', canonical_url) output = output.replace('{{ canonical_url }}', canonical_url)
if filename =='index.md': if filename =='index.md':
output = output.replace('{{ ad_block }}', """<hr><p><strong>The team behind REST framework is launching a new API service.</strong></p> output = output.replace('{{ ad_block }}', """<hr/>
<p>If you want to be first in line when we start issuing invitations, please <a href="http://brightapi.com">sign up here</a>.</p>""") <script type="text/javascript" src="//cdn.fusionads.net/fusion.js?zoneid=1332&serve=C6SDP2Y&placement=djangorestframework" id="_fusionads_js"></script>""")
else: else:
output = output.replace('{{ ad_block }}', '') output = output.replace('{{ ad_block }}', '')

View File

@ -310,6 +310,13 @@ class OAuth2Authentication(BaseAuthentication):
auth = get_authorization_header(request).split() auth = get_authorization_header(request).split()
if len(auth) == 1:
msg = 'Invalid bearer header. No credentials provided.'
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = 'Invalid bearer header. Token string should not contain spaces.'
raise exceptions.AuthenticationFailed(msg)
if auth and auth[0].lower() == b'bearer': if auth and auth[0].lower() == b'bearer':
access_token = auth[1] access_token = auth[1]
elif 'access_token' in request.POST: elif 'access_token' in request.POST:
@ -319,13 +326,6 @@ class OAuth2Authentication(BaseAuthentication):
else: else:
return None return None
if len(auth) == 1:
msg = 'Invalid bearer header. No credentials provided.'
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = 'Invalid bearer header. Token string should not contain spaces.'
raise exceptions.AuthenticationFailed(msg)
return self.authenticate_credentials(request, access_token) return self.authenticate_credentials(request, access_token)
def authenticate_credentials(self, request, access_token): def authenticate_credentials(self, request, access_token):

View File

@ -48,12 +48,15 @@ try:
except ImportError: except ImportError:
django_filters = None django_filters = None
# guardian is optional # Django-guardian is optional. Import only if guardian is in INSTALLED_APPS
try: # Fixes (#1712). We keep the try/except for the test suite.
guardian = None
if 'guardian' in settings.INSTALLED_APPS:
try:
import guardian import guardian
import guardian.shortcuts # Fixes #1624 import guardian.shortcuts # Fixes #1624
except ImportError: except ImportError:
guardian = None pass
# cStringIO only if it's available, otherwise StringIO # cStringIO only if it's available, otherwise StringIO

View File

@ -187,7 +187,7 @@ class Field(object):
def field_to_native(self, obj, field_name): def field_to_native(self, obj, field_name):
""" """
Given and object and a field name, returns the value that should be Given an object and a field name, returns the value that should be
serialized for that field. serialized for that field.
""" """
if obj is None: if obj is None:
@ -474,8 +474,12 @@ class CharField(WritableField):
self.validators.append(validators.MaxLengthValidator(max_length)) self.validators.append(validators.MaxLengthValidator(max_length))
def from_native(self, value): def from_native(self, value):
if isinstance(value, six.string_types) or value is None: if isinstance(value, six.string_types):
return value return value
if value is None:
return ''
return smart_text(value) return smart_text(value)

View File

@ -116,6 +116,10 @@ class OrderingFilter(BaseFilterBackend):
def get_ordering(self, request): def get_ordering(self, request):
""" """
Ordering is set by a comma delimited ?ordering=... query parameter. Ordering is set by a comma delimited ?ordering=... query parameter.
The `ordering` query parameter can be overridden by setting
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: if params:

View File

@ -5,6 +5,7 @@ it is initialized with unrendered data, instead of a pre-rendered string.
The appropriate renderer is called during Django's template response rendering. The appropriate renderer is called during Django's template response rendering.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
import django
from django.core.handlers.wsgi import STATUS_CODE_TEXT from django.core.handlers.wsgi import STATUS_CODE_TEXT
from django.template.response import SimpleTemplateResponse from django.template.response import SimpleTemplateResponse
from rest_framework.compat import six from rest_framework.compat import six
@ -15,6 +16,9 @@ class Response(SimpleTemplateResponse):
An HttpResponse that allows its data to be rendered into An HttpResponse that allows its data to be rendered into
arbitrary media types. arbitrary media types.
""" """
# TODO: remove that once Django 1.3 isn't supported
if django.VERSION >= (1, 4):
rendering_attrs = SimpleTemplateResponse.rendering_attrs + ['_closable_objects']
def __init__(self, data=None, status=200, def __init__(self, data=None, status=200,
template_name=None, headers=None, template_name=None, headers=None,

View File

@ -93,7 +93,7 @@
{% endif %} {% endif %}
{% if options_form %} {% if options_form %}
<form class="button-form" action="{{ request.get_full_path }}" method="POST" class="pull-right"> <form class="button-form" action="{{ request.get_full_path }}" method="POST">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="{{ api_settings.FORM_METHOD_OVERRIDE }}" value="OPTIONS" /> <input type="hidden" name="{{ api_settings.FORM_METHOD_OVERRIDE }}" value="OPTIONS" />
<button class="btn btn-primary js-tooltip" title="Make an OPTIONS request on the {{ name }} resource">OPTIONS</button> <button class="btn btn-primary js-tooltip" title="Make an OPTIONS request on the {{ name }} resource">OPTIONS</button>
@ -101,7 +101,7 @@
{% endif %} {% endif %}
{% if delete_form %} {% if delete_form %}
<form class="button-form" action="{{ request.get_full_path }}" method="POST" class="pull-right"> <form class="button-form" action="{{ request.get_full_path }}" method="POST">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="{{ api_settings.FORM_METHOD_OVERRIDE }}" value="DELETE" /> <input type="hidden" name="{{ api_settings.FORM_METHOD_OVERRIDE }}" value="DELETE" />
<button class="btn btn-danger js-tooltip" title="Make a DELETE request on the {{ name }} resource">DELETE</button> <button class="btn btn-danger js-tooltip" title="Make a DELETE request on the {{ name }} resource">DELETE</button>

View File

@ -105,6 +105,7 @@ class Album(RESTFrameworkModel):
title = models.CharField(max_length=100, unique=True) title = models.CharField(max_length=100, unique=True)
ref = models.CharField(max_length=10, unique=True, null=True, blank=True) ref = models.CharField(max_length=10, unique=True, null=True, blank=True)
class Photo(RESTFrameworkModel): class Photo(RESTFrameworkModel):
description = models.TextField() description = models.TextField()
album = models.ForeignKey(Album) album = models.ForeignKey(Album)
@ -112,7 +113,8 @@ class Photo(RESTFrameworkModel):
# Model for issue #324 # Model for issue #324
class BlankFieldModel(RESTFrameworkModel): class BlankFieldModel(RESTFrameworkModel):
title = models.CharField(max_length=100, blank=True, null=False) title = models.CharField(max_length=100, blank=True, null=False,
default="title")
# Model for issue #380 # Model for issue #380

View File

@ -549,6 +549,15 @@ class OAuth2Tests(TestCase):
response = self.csrf_client.get('/oauth2-test/', HTTP_AUTHORIZATION=auth) response = self.csrf_client.get('/oauth2-test/', HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 401) self.assertEqual(response.status_code, 401)
@unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed')
def test_get_form_with_wrong_authorization_header_token_missing(self):
"""Ensure that a missing token lead to the correct HTTP error status code"""
auth = "Bearer"
response = self.csrf_client.get('/oauth2-test/', {}, HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 401)
response = self.csrf_client.get('/oauth2-test/', HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 401)
@unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed') @unittest.skipUnless(oauth2_provider, 'django-oauth2-provider not installed')
def test_get_form_passing_auth(self): def test_get_form_passing_auth(self):
"""Ensure GETing form over OAuth with correct client credentials succeed""" """Ensure GETing form over OAuth with correct client credentials succeed"""

View File

@ -1236,6 +1236,9 @@ class BlankFieldTests(TestCase):
def test_create_model_null_field(self): def test_create_model_null_field(self):
serializer = self.model_serializer_class(data={'title': None}) serializer = self.model_serializer_class(data={'title': None})
self.assertEqual(serializer.is_valid(), True) self.assertEqual(serializer.is_valid(), True)
serializer.save()
self.assertIsNot(serializer.object.pk, None)
self.assertEqual(serializer.object.title, '')
def test_create_not_blank_field(self): def test_create_not_blank_field(self):
""" """

32
tox.ini
View File

@ -12,34 +12,34 @@ commands = {envpython} rest_framework/runtests/runtests.py
[testenv:py3.4-django1.7] [testenv:py3.4-django1.7]
basepython = python3.4 basepython = python3.4
deps = https://www.djangoproject.com/download/1.7b2/tarball/ deps = https://www.djangoproject.com/download/1.7c2/tarball/
django-filter==0.7 django-filter==0.7
defusedxml==0.3 defusedxml==0.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py3.3-django1.7] [testenv:py3.3-django1.7]
basepython = python3.3 basepython = python3.3
deps = https://www.djangoproject.com/download/1.7b2/tarball/ deps = https://www.djangoproject.com/download/1.7c2/tarball/
django-filter==0.7 django-filter==0.7
defusedxml==0.3 defusedxml==0.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py3.2-django1.7] [testenv:py3.2-django1.7]
basepython = python3.2 basepython = python3.2
deps = https://www.djangoproject.com/download/1.7b2/tarball/ deps = https://www.djangoproject.com/download/1.7c2/tarball/
django-filter==0.7 django-filter==0.7
defusedxml==0.3 defusedxml==0.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.7-django1.7] [testenv:py2.7-django1.7]
basepython = python2.7 basepython = python2.7
deps = https://www.djangoproject.com/download/1.7b2/tarball/ deps = https://www.djangoproject.com/download/1.7c2/tarball/
django-filter==0.7 django-filter==0.7
defusedxml==0.3 defusedxml==0.3
django-oauth-plus==2.2.1 # django-oauth-plus==2.2.1
oauth2==1.5.211 # oauth2==1.5.211
django-oauth2-provider==0.2.4 # django-oauth2-provider==0.2.4
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py3.4-django1.6] [testenv:py3.4-django1.6]
@ -71,7 +71,7 @@ deps = Django==1.6.3
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.4 django-oauth2-provider==0.2.4
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.6-django1.6] [testenv:py2.6-django1.6]
@ -82,7 +82,7 @@ deps = Django==1.6.3
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.4 django-oauth2-provider==0.2.4
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py3.4-django1.5] [testenv:py3.4-django1.5]
@ -114,7 +114,7 @@ deps = django==1.5.6
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.6-django1.5] [testenv:py2.6-django1.5]
@ -125,7 +125,7 @@ deps = django==1.5.6
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.7-django1.4] [testenv:py2.7-django1.4]
@ -136,7 +136,7 @@ deps = django==1.4.11
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.6-django1.4] [testenv:py2.6-django1.4]
@ -147,7 +147,7 @@ deps = django==1.4.11
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.7-django1.3] [testenv:py2.7-django1.3]
@ -158,7 +158,7 @@ deps = django==1.3.5
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0
[testenv:py2.6-django1.3] [testenv:py2.6-django1.3]
@ -169,5 +169,5 @@ deps = django==1.3.5
django-oauth-plus==2.2.1 django-oauth-plus==2.2.1
oauth2==1.5.211 oauth2==1.5.211
django-oauth2-provider==0.2.3 django-oauth2-provider==0.2.3
django-guardian==1.1.1 django-guardian==1.2.3
Pillow==2.3.0 Pillow==2.3.0