├── schema-support ├── tests ├── __init__.py ├── browsable_api │ ├── __init__.py │ ├── no_auth_urls.py │ ├── auth_urls.py │ ├── views.py │ ├── test_browsable_nested_api.py │ ├── test_form_rendering.py │ └── test_browsable_api.py ├── urls.py ├── test_exceptions.py ├── test_write_only_fields.py ├── test_status.py ├── test_middleware.py ├── test_viewsets.py ├── test_settings.py ├── utils.py ├── test_reverse.py ├── conftest.py ├── test_negotiation.py ├── test_multitable_inheritance.py ├── test_encoders.py ├── models.py ├── test_relations_generic.py └── test_description.py ├── rest_framework ├── utils │ ├── __init__.py │ ├── urls.py │ ├── humanize_datetime.py │ ├── breadcrumbs.py │ ├── html.py │ ├── formatting.py │ ├── encoders.py │ ├── mediatypes.py │ └── representation.py ├── templatetags │ └── __init__.py ├── authtoken │ ├── migrations │ │ ├── __init__.py │ │ ├── 0001_initial.py │ │ └── 0002_auto_20160226_1747.py │ ├── __init__.py │ ├── apps.py │ ├── admin.py │ ├── views.py │ ├── serializers.py │ └── models.py ├── templates │ └── rest_framework │ │ ├── admin │ │ ├── dict_value.html │ │ ├── simple_list_value.html │ │ ├── list_value.html │ │ ├── detail.html │ │ └── list.html │ │ ├── inline │ │ ├── list_fieldset.html │ │ ├── form.html │ │ ├── fieldset.html │ │ ├── checkbox.html │ │ ├── textarea.html │ │ ├── input.html │ │ ├── checkbox_multiple.html │ │ ├── radio.html │ │ ├── select.html │ │ └── select_multiple.html │ │ ├── api.html │ │ ├── login.html │ │ ├── filters │ │ ├── django_filter_crispyforms.html │ │ ├── django_filter.html │ │ ├── search.html │ │ ├── ordering.html │ │ └── base.html │ │ ├── horizontal │ │ ├── form.html │ │ ├── list_fieldset.html │ │ ├── fieldset.html │ │ ├── checkbox.html │ │ ├── textarea.html │ │ ├── input.html │ │ ├── checkbox_multiple.html │ │ ├── select.html │ │ ├── select_multiple.html │ │ └── radio.html │ │ ├── vertical │ │ ├── form.html │ │ ├── list_fieldset.html │ │ ├── fieldset.html │ │ ├── checkbox.html │ │ ├── textarea.html │ │ ├── input.html │ │ ├── select.html │ │ ├── checkbox_multiple.html │ │ ├── select_multiple.html │ │ └── radio.html │ │ ├── raw_data_form.html │ │ ├── pagination │ │ ├── previous_and_next.html │ │ └── numbers.html │ │ └── login_base.html ├── models.py ├── locale │ ├── ach │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ar │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── be │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ca │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── cs │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── da │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── de │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── el │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── en │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── es │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── et │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fa │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fi │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fr │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── gl │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── hu │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── id │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── it │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ja │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── mk │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── nb │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── nl │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── nn │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── no │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── pl │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── pt │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ro │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ru │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── sk │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── sv │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── tr │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── uk │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── vi │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ca_ES │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── da_DK │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── el_GR │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── en_AU │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── en_CA │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── en_US │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fa_IR │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── fr_CA │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── gl_ES │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── he_IL │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── ko_KR │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── pt_BR │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── pt_PT │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── tr_TR │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── zh_CN │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── zh_TW │ │ └── LC_MESSAGES │ │ │ └── django.mo │ ├── zh_Hans │ │ └── LC_MESSAGES │ │ │ └── django.mo │ └── zh_Hant │ │ └── LC_MESSAGES │ │ └── django.mo ├── static │ └── rest_framework │ │ ├── img │ │ ├── grid.png │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── css │ │ ├── prettify.css │ │ └── default.css │ │ └── js │ │ ├── default.js │ │ ├── csrf.js │ │ └── ajax-form.js ├── __init__.py ├── urls.py ├── reverse.py ├── status.py ├── urlpatterns.py ├── mixins.py └── response.py ├── docs ├── CNAME ├── img │ ├── logo.png │ ├── admin.png │ ├── apiary.png │ ├── drfdocs.png │ ├── inline.png │ ├── rover.png │ ├── slate.png │ ├── cerulean.png │ ├── vertical.png │ ├── horizontal.png │ ├── quickstart.png │ ├── django-filter.png │ ├── search-filter.png │ ├── sponsors │ │ ├── 2-sga.png │ │ ├── 3-aba.png │ │ ├── 3-isl.png │ │ ├── 1-cyan.png │ │ ├── 1-divio.png │ │ ├── 1-lulu.png │ │ ├── 1-potato.png │ │ ├── 2-byte.png │ │ ├── 2-crate.png │ │ ├── 2-django.png │ │ ├── 2-heroku.png │ │ ├── 2-hipo.png │ │ ├── 2-opbeat.png │ │ ├── 2-sirono.png │ │ ├── 2-vinta.png │ │ ├── 3-blimp.png │ │ ├── 3-garfo.png │ │ ├── 3-gizmag.png │ │ ├── 3-holvi.png │ │ ├── 3-phurba.png │ │ ├── 3-safari.png │ │ ├── 3-shippo.png │ │ ├── 3-tivix.png │ │ ├── 3-vzzual.png │ │ ├── 1-runscope.png │ │ ├── 2-compile.png │ │ ├── 2-cryptico.png │ │ ├── 2-hipflask.png │ │ ├── 2-laterpay.png │ │ ├── 2-nexthub.png │ │ ├── 2-rapasso.png │ │ ├── 2-wusawork.png │ │ ├── 3-aditium.png │ │ ├── 3-beefarm.png │ │ ├── 3-cantemo.gif │ │ ├── 3-nephila.png │ │ ├── 3-openeye.png │ │ ├── 3-pkgfarm.png │ │ ├── 3-teonite.png │ │ ├── 3-wildfish.png │ │ ├── 0-eventbrite.png │ │ ├── 1-kuwaitnet.png │ │ ├── 1-purplebit.png │ │ ├── 1-wiredrive.png │ │ ├── 2-koordinates.png │ │ ├── 2-prorenata.png │ │ ├── 2-pulsecode.png │ │ ├── 3-alwaysdata.png │ │ ├── 3-brightloop.png │ │ ├── 3-fluxility.png │ │ ├── 3-ipushpull.png │ │ ├── 3-makespace.png │ │ ├── 3-pathwright.png │ │ ├── 3-providenz.png │ │ ├── 3-trackmaven.png │ │ ├── 3-transcode.png │ │ ├── 1-simple-energy.png │ │ ├── 2-singing-horse.png │ │ ├── 3-ax_semantics.png │ │ ├── 3-infinite_code.png │ │ ├── 3-life_the_game.png │ │ ├── 2-lightning_kite.png │ │ ├── 2-mirus_research.png │ │ ├── 2-rheinwerk_verlag.png │ │ ├── 2-schuberg_philis.png │ │ ├── 2-security_compass.png │ │ ├── 3-crosswordtracker.png │ │ ├── 3-thermondo-gmbh.png │ │ ├── 1-vokal_interactive.png │ │ ├── 3-imt_computer_services.png │ │ └── 3-triggered_messaging.png │ ├── travis-status.png │ ├── corejson-format.png │ ├── cursor-pagination.png │ ├── filter-controls.png │ ├── ordering-filter.png │ ├── pages-pagination.png │ ├── self-describing.png │ ├── django-rest-swagger.png │ ├── labels-and-milestones.png │ ├── link-header-pagination.png │ └── premium │ │ ├── rover-readme.png │ │ ├── sentry-readme.png │ │ ├── stream-readme.png │ │ └── machinalis-readme.png ├── topics │ ├── writable-nested-serializers.md │ ├── ajax-csrf-cors.md │ ├── rest-hypermedia-hateoas.md │ └── 3.3-announcement.md └── api-guide │ └── reverse.md ├── setup.cfg ├── requirements ├── requirements-documentation.txt ├── requirements-testing.txt ├── requirements-codestyle.txt ├── requirements-optionals.txt └── requirements-packaging.txt ├── docs_theme ├── img │ ├── grid.png │ ├── favicon.ico │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png ├── 404.html ├── css │ └── prettify.css ├── js │ └── theme.js └── nav.html ├── .isort.cfg ├── .gitignore ├── MANIFEST.in ├── .tx └── config ├── PULL_REQUEST_TEMPLATE.md ├── requirements.txt ├── ISSUE_TEMPLATE.md ├── .travis.yml ├── tox.ini ├── LICENSE.md ├── mkdocs.yml ├── runtests.py └── setup.py /schema-support: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rest_framework/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/browsable_api/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rest_framework/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | www.django-rest-framework.org 2 | -------------------------------------------------------------------------------- /rest_framework/authtoken/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/admin/dict_value.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rest_framework/models.py: -------------------------------------------------------------------------------- 1 | # Just to keep things like ./manage.py test happy 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | 4 | [metadata] 5 | license_file = LICENSE.md 6 | -------------------------------------------------------------------------------- /docs/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/logo.png -------------------------------------------------------------------------------- /requirements/requirements-documentation.txt: -------------------------------------------------------------------------------- 1 | # MkDocs to build our documentation. 2 | mkdocs==0.15.3 3 | -------------------------------------------------------------------------------- /tests/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | Blank URLConf just to keep the test suite happy 3 | """ 4 | urlpatterns = [] 5 | -------------------------------------------------------------------------------- /docs/img/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/admin.png -------------------------------------------------------------------------------- /docs/img/apiary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/apiary.png -------------------------------------------------------------------------------- /docs/img/drfdocs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/drfdocs.png -------------------------------------------------------------------------------- /docs/img/inline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/inline.png -------------------------------------------------------------------------------- /docs/img/rover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/rover.png -------------------------------------------------------------------------------- /docs/img/slate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/slate.png -------------------------------------------------------------------------------- /docs/img/cerulean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/cerulean.png -------------------------------------------------------------------------------- /docs/img/vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/vertical.png -------------------------------------------------------------------------------- /rest_framework/authtoken/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'rest_framework.authtoken.apps.AuthTokenConfig' 2 | -------------------------------------------------------------------------------- /docs/img/horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/horizontal.png -------------------------------------------------------------------------------- /docs/img/quickstart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/quickstart.png -------------------------------------------------------------------------------- /docs_theme/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs_theme/img/grid.png -------------------------------------------------------------------------------- /docs/img/django-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/django-filter.png -------------------------------------------------------------------------------- /docs/img/search-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/search-filter.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-sga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-sga.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-aba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-aba.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-isl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-isl.png -------------------------------------------------------------------------------- /docs/img/travis-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/travis-status.png -------------------------------------------------------------------------------- /docs_theme/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs_theme/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/corejson-format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/corejson-format.png -------------------------------------------------------------------------------- /docs/img/cursor-pagination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/cursor-pagination.png -------------------------------------------------------------------------------- /docs/img/filter-controls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/filter-controls.png -------------------------------------------------------------------------------- /docs/img/ordering-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/ordering-filter.png -------------------------------------------------------------------------------- /docs/img/pages-pagination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/pages-pagination.png -------------------------------------------------------------------------------- /docs/img/self-describing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/self-describing.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-cyan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-cyan.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-divio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-divio.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-lulu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-lulu.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-potato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-potato.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-byte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-byte.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-crate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-crate.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-django.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-django.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-heroku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-heroku.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-hipo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-hipo.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-opbeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-opbeat.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-sirono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-sirono.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-vinta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-vinta.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-blimp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-blimp.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-garfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-garfo.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-gizmag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-gizmag.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-holvi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-holvi.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-phurba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-phurba.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-safari.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-shippo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-shippo.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-tivix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-tivix.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-vzzual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-vzzual.png -------------------------------------------------------------------------------- /docs/img/django-rest-swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/django-rest-swagger.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-runscope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-runscope.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-compile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-compile.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-cryptico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-cryptico.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-hipflask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-hipflask.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-laterpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-laterpay.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-nexthub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-nexthub.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-rapasso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-rapasso.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-wusawork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-wusawork.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-aditium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-aditium.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-beefarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-beefarm.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-cantemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-cantemo.gif -------------------------------------------------------------------------------- /docs/img/sponsors/3-nephila.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-nephila.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-openeye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-openeye.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-pkgfarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-pkgfarm.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-teonite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-teonite.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-wildfish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-wildfish.png -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/list_fieldset.html: -------------------------------------------------------------------------------- 1 | Lists are not currently supported in HTML input. 2 | -------------------------------------------------------------------------------- /docs/img/labels-and-milestones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/labels-and-milestones.png -------------------------------------------------------------------------------- /docs/img/link-header-pagination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/link-header-pagination.png -------------------------------------------------------------------------------- /docs/img/premium/rover-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/premium/rover-readme.png -------------------------------------------------------------------------------- /docs/img/premium/sentry-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/premium/sentry-readme.png -------------------------------------------------------------------------------- /docs/img/premium/stream-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/premium/stream-readme.png -------------------------------------------------------------------------------- /docs/img/sponsors/0-eventbrite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/0-eventbrite.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-kuwaitnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-kuwaitnet.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-purplebit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-purplebit.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-wiredrive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-wiredrive.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-koordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-koordinates.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-prorenata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-prorenata.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-pulsecode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-pulsecode.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-alwaysdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-alwaysdata.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-brightloop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-brightloop.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-fluxility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-fluxility.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-ipushpull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-ipushpull.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-makespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-makespace.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-pathwright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-pathwright.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-providenz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-providenz.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-trackmaven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-trackmaven.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-transcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-transcode.png -------------------------------------------------------------------------------- /requirements/requirements-testing.txt: -------------------------------------------------------------------------------- 1 | # PyTest for running the tests. 2 | pytest==2.9.1 3 | pytest-django==2.9.1 4 | pytest-cov==1.8.1 5 | -------------------------------------------------------------------------------- /docs/img/sponsors/1-simple-energy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-simple-energy.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-singing-horse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-singing-horse.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-ax_semantics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-ax_semantics.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-infinite_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-infinite_code.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-life_the_game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-life_the_game.png -------------------------------------------------------------------------------- /docs/img/premium/machinalis-readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/premium/machinalis-readme.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-lightning_kite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-lightning_kite.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-mirus_research.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-mirus_research.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-rheinwerk_verlag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-rheinwerk_verlag.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-schuberg_philis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-schuberg_philis.png -------------------------------------------------------------------------------- /docs/img/sponsors/2-security_compass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/2-security_compass.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-crosswordtracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-crosswordtracker.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-thermondo-gmbh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-thermondo-gmbh.png -------------------------------------------------------------------------------- /docs_theme/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs_theme/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/img/sponsors/1-vokal_interactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/1-vokal_interactive.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-imt_computer_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-imt_computer_services.png -------------------------------------------------------------------------------- /docs/img/sponsors/3-triggered_messaging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs/img/sponsors/3-triggered_messaging.png -------------------------------------------------------------------------------- /docs_theme/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/docs_theme/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /rest_framework/locale/ach/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ach/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ar/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ar/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/be/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/be/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ca/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ca/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/cs/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/cs/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/da/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/da/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/de/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/de/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/el/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/el/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/en/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/en/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/es/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/es/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/et/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/et/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/fa/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/fa/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/fi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/fi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/fr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/fr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/gl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/gl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/hu/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/hu/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/id/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/id/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/it/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/it/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ja/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ja/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/mk/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/mk/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/nb/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/nb/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/nl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/nl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/nn/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/nn/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/no/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/no/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/pl/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/pl/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/pt/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/pt/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ro/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ro/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ru/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ru/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/sk/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/sk/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/sv/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/sv/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/tr/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/tr/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/uk/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/uk/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/vi/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/vi/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ca_ES/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ca_ES/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/da_DK/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/da_DK/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/el_GR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/el_GR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/en_AU/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/en_AU/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/en_CA/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/en_CA/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/en_US/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/en_US/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/fa_IR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/fa_IR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/fr_CA/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/fr_CA/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/gl_ES/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/gl_ES/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/he_IL/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/he_IL/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/ko_KR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/ko_KR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/pt_BR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/pt_BR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/pt_PT/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/pt_PT/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/tr_TR/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/tr_TR/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/zh_CN/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/zh_CN/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/zh_TW/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/zh_TW/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/img/grid.png -------------------------------------------------------------------------------- /rest_framework/locale/zh_Hans/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/zh_Hans/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /rest_framework/locale/zh_Hant/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/locale/zh_Hant/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /requirements/requirements-codestyle.txt: -------------------------------------------------------------------------------- 1 | # PEP8 code linting, which we run on all commits. 2 | flake8==2.4.0 3 | pep8==1.5.7 4 | 5 | # Sort and lint imports 6 | isort==4.2.5 7 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/api.html: -------------------------------------------------------------------------------- 1 | {% extends "rest_framework/base.html" %} 2 | 3 | {# Override this template in your own templates directory to customize #} 4 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | skip=.tox 3 | atomic=true 4 | multi_line_output=5 5 | known_standard_library=types 6 | known_third_party=pytest,django 7 | known_first_party=rest_framework 8 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/login.html: -------------------------------------------------------------------------------- 1 | {% extends "rest_framework/login_base.html" %} 2 | 3 | {# Override this template in your own templates directory to customize #} 4 | -------------------------------------------------------------------------------- /requirements/requirements-optionals.txt: -------------------------------------------------------------------------------- 1 | # Optional packages which may be used with REST framework. 2 | markdown==2.6.4 3 | django-guardian==1.4.3 4 | django-filter==0.13.0 5 | coreapi==1.32.0 6 | -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/admin/simple_list_value.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {% for item in value %}{% if not forloop.first%},{% endif %} {{item|format_value}}{% endfor %} 3 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/filters/django_filter_crispyforms.html: -------------------------------------------------------------------------------- 1 | {% load crispy_forms_tags %} 2 | {% load i18n %} 3 | 4 |

{% trans "Field filters" %}

5 | {% crispy filter.form %} 6 | -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/variable/django-rest-framework/master/rest_framework/static/rest_framework/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/form.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {% for field in form %} 3 | {% if not field.read_only %} 4 | {% render_field field style=style %} 5 | {% endif %} 6 | {% endfor %} 7 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/form.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {% for field in form %} 3 | {% if not field.read_only %} 4 | {% render_field field style=style %} 5 | {% endif %} 6 | {% endfor %} 7 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/form.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {% for field in form %} 3 | {% if not field.read_only %} 4 | {% render_field field style=style %} 5 | {% endif %} 6 | {% endfor %} 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.db 3 | *~ 4 | .* 5 | 6 | /site/ 7 | /htmlcov/ 8 | /coverage/ 9 | /build/ 10 | /dist/ 11 | /*.egg-info/ 12 | /env/ 13 | MANIFEST 14 | coverage.* 15 | 16 | !.gitignore 17 | !.travis.yml 18 | !.isort.cfg 19 | -------------------------------------------------------------------------------- /tests/browsable_api/no_auth_urls.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf.urls import url 4 | 5 | from .views import MockView 6 | 7 | urlpatterns = [ 8 | url(r'^$', MockView.as_view()), 9 | ] 10 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/fieldset.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {% for nested_field in field %} 3 | {% if not nested_field.read_only %} 4 | {% render_field nested_field style=style %} 5 | {% endif %} 6 | {% endfor %} 7 | -------------------------------------------------------------------------------- /rest_framework/authtoken/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | 5 | class AuthTokenConfig(AppConfig): 6 | name = 'rest_framework.authtoken' 7 | verbose_name = _("Auth Token") 8 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE.md 3 | recursive-include rest_framework/static *.js *.css *.png *.eot *.svg *.ttf *.woff 4 | recursive-include rest_framework/templates *.html 5 | recursive-exclude * __pycache__ 6 | recursive-exclude * *.py[co] 7 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/filters/django_filter.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{% trans "Field filters" %}

3 |
4 | {{ filter.form.as_p }} 5 | 6 |
7 | -------------------------------------------------------------------------------- /requirements/requirements-packaging.txt: -------------------------------------------------------------------------------- 1 | # Wheel for PyPI installs. 2 | wheel==0.29.0 3 | 4 | # Twine for secured PyPI uploads. 5 | twine==1.6.5 6 | 7 | # Transifex client for managing translation resources. 8 | transifex-client==0.11 9 | 10 | # Pandoc to have a nice pypi page 11 | pypandoc 12 | -------------------------------------------------------------------------------- /tests/browsable_api/auth_urls.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf.urls import include, url 4 | 5 | from .views import MockView 6 | 7 | urlpatterns = [ 8 | url(r'^$', MockView.as_view()), 9 | url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')), 10 | ] 11 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/list_fieldset.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 4 | {{ field.label }} 5 | 6 | {% endif %} 7 | 8 |

Lists are not currently supported in HTML input.

9 |
10 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | lang_map = sr@latin:sr_Latn, zh-Hans:zh_Hans, zh-Hant:zh_Hant 4 | 5 | [django-rest-framework.djangopo] 6 | file_filter = rest_framework/locale//LC_MESSAGES/django.po 7 | source_file = rest_framework/locale/en_US/LC_MESSAGES/django.po 8 | source_lang = en_US 9 | type = PO 10 | 11 | -------------------------------------------------------------------------------- /rest_framework/authtoken/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from rest_framework.authtoken.models import Token 4 | 5 | 6 | class TokenAdmin(admin.ModelAdmin): 7 | list_display = ('key', 'user', 'created') 8 | fields = ('user',) 9 | ordering = ('-created',) 10 | 11 | 12 | admin.site.register(Token, TokenAdmin) 13 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/admin/list_value.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 | 4 | {% for item in value %} 5 | 6 | 7 | 8 | 9 | {% endfor %} 10 | 11 |
{{ forloop.counter0 }}{{ item|format_value }}
12 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/checkbox.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 |
9 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/admin/detail.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 | 4 | {% for key, value in results.items %} 5 | {% if key in details %} 6 | 7 | {% endif %} 8 | {% endfor %} 9 | 10 |
{{ key|capfirst }}{{ value|format_value }}
11 | -------------------------------------------------------------------------------- /docs_theme/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 | 5 |

404

6 |

Page not found

7 |

Try the homepage, or search the documentation.

8 | 9 | {% endblock %} 10 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Note*: Before submitting this pull request, please review our [contributing guidelines](https://github.com/tomchristie/django-rest-framework/blob/master/CONTRIBUTING.md#pull-requests). 2 | 3 | ## Description 4 | 5 | Please describe your pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. When linking to an issue, please use `refs #...` in the description of the pull request. 6 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/raw_data_form.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {{ form.non_field_errors }} 3 | {% for field in form %} 4 |
5 | {{ field.label_tag|add_class:"col-sm-2 control-label" }} 6 |
7 | {{ field|add_class:"form-control" }} 8 | {{ field.help_text|safe }} 9 |
10 |
11 | {% endfor %} 12 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/textarea.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 6 | {% endif %} 7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/fieldset.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 6 | {{ field.label }} 7 | 8 | {% endif %} 9 | 10 | {% for nested_field in field %} 11 | {% if not nested_field.read_only %} 12 | {% render_field nested_field style=style %} 13 | {% endif %} 14 | {% endfor %} 15 |
16 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/list_fieldset.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 |
6 | 7 | {{ field.label }} 8 | 9 |
10 | {% endif %} 11 | 12 |

Lists are not currently supported in HTML input.

13 |
14 | -------------------------------------------------------------------------------- /tests/browsable_api/views.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from rest_framework import authentication, renderers 4 | from rest_framework.response import Response 5 | from rest_framework.views import APIView 6 | 7 | 8 | class MockView(APIView): 9 | authentication_classes = (authentication.SessionAuthentication,) 10 | renderer_classes = (renderers.BrowsableAPIRenderer, renderers.JSONRenderer) 11 | 12 | def get(self, request): 13 | return Response({'a': 1, 'b': 2, 'c': 3}) 14 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/input.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 6 | {% endif %} 7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/filters/search.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{% trans "Search" %}

3 |
4 |
5 |
6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/fieldset.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 |
3 | {% if field.label %} 4 |
5 | 6 | {{ field.label }} 7 | 8 |
9 | {% endif %} 10 | 11 | {% for nested_field in field %} 12 | {% if not nested_field.read_only %} 13 | {% render_field nested_field style=style %} 14 | {% endif %} 15 | {% endfor %} 16 |
17 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/checkbox_multiple.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 6 | {% endif %} 7 | 8 | {% for key, text in field.choices.items %} 9 |
10 | 14 |
15 | {% endfor %} 16 |
17 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/pagination/previous_and_next.html: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # The base set of requirements for REST framework is actually 2 | # just Django, but for the purposes of development and testing 3 | # there are a number of packages that are useful to install. 4 | 5 | # Laying these out as seperate requirements files, allows us to 6 | # only included the relevent sets when running tox, and ensures 7 | # we are only ever declaring our dependencies in one place. 8 | 9 | -r requirements/requirements-optionals.txt 10 | -r requirements/requirements-testing.txt 11 | -r requirements/requirements-documentation.txt 12 | -r requirements/requirements-codestyle.txt 13 | -r requirements/requirements-packaging.txt 14 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/filters/ordering.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | {% load i18n %} 3 |

{% trans "Ordering" %}

4 |
5 | {% for key, label in options %} 6 | {% if key == current %} 7 | 8 | {{ label }} 9 | 10 | {% else %} 11 | {{ label }} 12 | {% endif %} 13 | {% endfor %} 14 |
15 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/checkbox.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 | 9 | {% if field.errors %} 10 | {% for error in field.errors %} 11 | {{ error }} 12 | {% endfor %} 13 | {% endif %} 14 | 15 | {% if field.help_text %} 16 | {{ field.help_text|safe }} 17 | {% endif %} 18 |
19 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/filters/base.html: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/admin/list.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 | 4 | {% for column in columns%}{% endfor %} 5 | 6 | 7 | {% for row in results %} 8 | 9 | {% for key, value in row.items %} 10 | {% if key in columns %} 11 | 14 | {% endif %} 15 | {% endfor %} 16 | 19 | 20 | {% endfor %} 21 | 22 |
{{ column|capfirst }}
12 | {{ value|format_value }} 13 | 17 | 18 |
23 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/checkbox.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 6 | {% endif %} 7 | 8 |
9 | 10 | 11 | {% if field.errors %} 12 | {% for error in field.errors %} 13 | {{ error }} 14 | {% endfor %} 15 | {% endif %} 16 | 17 | {% if field.help_text %} 18 | {{ field.help_text|safe }} 19 | {% endif %} 20 |
21 |
22 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/textarea.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 6 | {% endif %} 7 | 8 | 9 | 10 | {% if field.errors %} 11 | {% for error in field.errors %}{{ error }}{% endfor %} 12 | {% endif %} 13 | 14 | {% if field.help_text %} 15 | {{ field.help_text|safe }} 16 | {% endif %} 17 |
18 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/input.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 4 | {% endif %} 5 | 6 | 7 | 8 | {% if field.errors %} 9 | {% for error in field.errors %} 10 | {{ error }} 11 | {% endfor %} 12 | {% endif %} 13 | 14 | {% if field.help_text %} 15 | {{ field.help_text|safe }} 16 | {% endif %} 17 |
18 | -------------------------------------------------------------------------------- /tests/test_exceptions.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.test import TestCase 4 | from django.utils.translation import ugettext_lazy as _ 5 | 6 | from rest_framework.exceptions import _force_text_recursive 7 | 8 | 9 | class ExceptionTestCase(TestCase): 10 | 11 | def test_force_text_recursive(self): 12 | 13 | s = "sfdsfggiuytraetfdlklj" 14 | self.assertEqual(_force_text_recursive(_(s)), s) 15 | self.assertEqual(type(_force_text_recursive(_(s))), type(s)) 16 | 17 | self.assertEqual(_force_text_recursive({'a': _(s)})['a'], s) 18 | self.assertEqual(type(_force_text_recursive({'a': _(s)})['a']), type(s)) 19 | 20 | self.assertEqual(_force_text_recursive([[_(s)]])[0][0], s) 21 | self.assertEqual(type(_force_text_recursive([[_(s)]])[0][0]), type(s)) 22 | -------------------------------------------------------------------------------- /rest_framework/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | ______ _____ _____ _____ __ 3 | | ___ \ ___/ ___|_ _| / _| | | 4 | | |_/ / |__ \ `--. | | | |_ _ __ __ _ _ __ ___ _____ _____ _ __| |__ 5 | | /| __| `--. \ | | | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / 6 | | |\ \| |___/\__/ / | | | | | | | (_| | | | | | | __/\ V V / (_) | | | < 7 | \_| \_\____/\____/ \_/ |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_| 8 | """ 9 | 10 | __title__ = 'Django REST framework' 11 | __version__ = '3.4.7' 12 | __author__ = 'Tom Christie' 13 | __license__ = 'BSD 2-Clause' 14 | __copyright__ = 'Copyright 2011-2016 Tom Christie' 15 | 16 | # Version synonym 17 | VERSION = __version__ 18 | 19 | # Header encoding (see RFC5987) 20 | HTTP_HEADER_ENCODING = 'iso-8859-1' 21 | 22 | # Default datetime input and output formats 23 | ISO_8601 = 'iso-8601' 24 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Checklist 2 | 3 | - [ ] I have verified that that issue exists against the `master` branch of Django REST framework. 4 | - [ ] I have searched for similar issues in both open and closed tickets and cannot find a duplicate. 5 | - [ ] This is not a usage question. (Those should be directed to the [discussion group](https://groups.google.com/forum/#!forum/django-rest-framework) instead.) 6 | - [ ] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](http://www.django-rest-framework.org/topics/third-party-resources/#about-third-party-packages) where possible.) 7 | - [ ] I have reduced the issue to the simplest possible case. 8 | - [ ] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.) 9 | 10 | ## Steps to reproduce 11 | 12 | ## Expected behavior 13 | 14 | ## Actual behavior 15 | -------------------------------------------------------------------------------- /rest_framework/authtoken/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Token', 17 | fields=[ 18 | ('key', models.CharField(primary_key=True, serialize=False, max_length=40)), 19 | ('created', models.DateTimeField(auto_now_add=True)), 20 | ('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, related_name='auth_token', on_delete=models.CASCADE)), 21 | ], 22 | options={ 23 | }, 24 | bases=(models.Model,), 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/textarea.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 6 | {% endif %} 7 | 8 |
9 | 10 | 11 | {% if field.errors %} 12 | {% for error in field.errors %} 13 | {{ error }} 14 | {% endfor %} 15 | {% endif %} 16 | 17 | {% if field.help_text %} 18 | {{ field.help_text|safe }} 19 | {% endif %} 20 |
21 |
22 | -------------------------------------------------------------------------------- /rest_framework/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | Login and logout views for the browsable API. 3 | 4 | Add these to your root URLconf if you're using the browsable API and 5 | your API requires authentication: 6 | 7 | urlpatterns = [ 8 | ... 9 | url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')) 10 | ] 11 | 12 | In Django versions older than 1.9, the urls must be namespaced as 'rest_framework', 13 | and you should make sure your authentication settings include `SessionAuthentication`. 14 | """ 15 | from __future__ import unicode_literals 16 | 17 | from django.conf.urls import url 18 | from django.contrib.auth import views 19 | 20 | template_name = {'template_name': 'rest_framework/login.html'} 21 | 22 | app_name = 'rest_framework' 23 | urlpatterns = [ 24 | url(r'^login/$', views.login, template_name, name='login'), 25 | url(r'^logout/$', views.logout, template_name, name='logout'), 26 | ] 27 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/input.html: -------------------------------------------------------------------------------- 1 |
2 | {% if field.label %} 3 | 6 | {% endif %} 7 | 8 |
9 | 10 | 11 | {% if field.errors %} 12 | {% for error in field.errors %} 13 | {{ error }} 14 | {% endfor %} 15 | {% endif %} 16 | 17 | {% if field.help_text %} 18 | {{ field.help_text|safe }} 19 | {% endif %} 20 |
21 |
22 | -------------------------------------------------------------------------------- /docs_theme/css/prettify.css: -------------------------------------------------------------------------------- 1 | .com { color: #93a1a1; } 2 | .lit { color: #195f91; } 3 | .pun, .opn, .clo { color: #93a1a1; } 4 | .fun { color: #dc322f; } 5 | .str, .atv { color: #D14; } 6 | .kwd, .prettyprint .tag { color: #1e347b; } 7 | .typ, .atn, .dec, .var { color: teal; } 8 | .pln { color: #48484c; } 9 | 10 | .prettyprint { 11 | padding: 8px; 12 | background-color: #f7f7f9; 13 | border: 1px solid #e1e1e8; 14 | } 15 | .prettyprint.linenums { 16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 19 | } 20 | 21 | /* Specify class=linenums on a pre to get line numbering */ 22 | ol.linenums { 23 | margin: 0 0 0 33px; /* IE indents via margin-left */ 24 | } 25 | ol.linenums li { 26 | padding-left: 12px; 27 | color: #bebec5; 28 | line-height: 20px; 29 | text-shadow: 0 1px 0 #fff; 30 | } -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/radio.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load rest_framework %} 3 | {% trans "None" as none_choice %} 4 | 5 |
6 | {% if field.label %} 7 | 10 | {% endif %} 11 | 12 | {% if field.allow_null or field.allow_blank %} 13 |
14 | 18 |
19 | {% endif %} 20 | 21 | {% for key, text in field.choices.items %} 22 |
23 | 27 |
28 | {% endfor %} 29 |
30 | -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/css/prettify.css: -------------------------------------------------------------------------------- 1 | .com { color: #93a1a1; } 2 | .lit { color: #195f91; } 3 | .pun, .opn, .clo { color: #93a1a1; } 4 | .fun { color: #dc322f; } 5 | .str, .atv { color: #D14; } 6 | .kwd, .prettyprint .tag { color: #1e347b; } 7 | .typ, .atn, .dec, .var { color: teal; } 8 | .pln { color: #48484c; } 9 | 10 | .prettyprint { 11 | padding: 8px; 12 | background-color: #f7f7f9; 13 | border: 1px solid #e1e1e8; 14 | } 15 | .prettyprint.linenums { 16 | -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 17 | -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 18 | box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; 19 | } 20 | 21 | /* Specify class=linenums on a pre to get line numbering */ 22 | ol.linenums { 23 | margin: 0 0 0 33px; /* IE indents via margin-left */ 24 | } 25 | ol.linenums li { 26 | padding-left: 12px; 27 | color: #bebec5; 28 | line-height: 20px; 29 | text-shadow: 0 1px 0 #fff; 30 | } -------------------------------------------------------------------------------- /rest_framework/authtoken/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import parsers, renderers 2 | from rest_framework.authtoken.models import Token 3 | from rest_framework.authtoken.serializers import AuthTokenSerializer 4 | from rest_framework.response import Response 5 | from rest_framework.views import APIView 6 | 7 | 8 | class ObtainAuthToken(APIView): 9 | throttle_classes = () 10 | permission_classes = () 11 | parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) 12 | renderer_classes = (renderers.JSONRenderer,) 13 | serializer_class = AuthTokenSerializer 14 | 15 | def post(self, request, *args, **kwargs): 16 | serializer = self.serializer_class(data=request.data) 17 | serializer.is_valid(raise_exception=True) 18 | user = serializer.validated_data['user'] 19 | token, created = Token.objects.get_or_create(user=user) 20 | return Response({'token': token.key}) 21 | 22 | 23 | obtain_auth_token = ObtainAuthToken.as_view() 24 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/select.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 8 | {% endif %} 9 | 10 | 24 |
25 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/inline/select_multiple.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load rest_framework %} 3 | {% trans "No items to select." as no_items %} 4 | 5 |
6 | {% if field.label %} 7 | 10 | {% endif %} 11 | 12 | 25 |
26 | -------------------------------------------------------------------------------- /docs_theme/js/theme.js: -------------------------------------------------------------------------------- 1 | var getSearchTerm = function() { 2 | var sPageURL = window.location.search.substring(1); 3 | var sURLVariables = sPageURL.split('&'); 4 | for (var i = 0; i < sURLVariables.length; i++) { 5 | var sParameterName = sURLVariables[i].split('='); 6 | if (sParameterName[0] === 'q') { 7 | return sParameterName[1]; 8 | } 9 | } 10 | }; 11 | 12 | var initilizeSearch = function() { 13 | require.config({ baseUrl: '/mkdocs/js' }); 14 | require(['search']); 15 | }; 16 | 17 | $(function() { 18 | var searchTerm = getSearchTerm(), 19 | $searchModal = $('#mkdocs_search_modal'), 20 | $searchQuery = $searchModal.find('#mkdocs-search-query'), 21 | $searchResults = $searchModal.find('#mkdocs-search-results'); 22 | 23 | $('pre code').parent().addClass('prettyprint well'); 24 | 25 | if (searchTerm) { 26 | $searchQuery.val(searchTerm); 27 | $searchResults.text('Searching...'); 28 | $searchModal.modal(); 29 | } 30 | 31 | $searchModal.on('shown', function() { 32 | $searchQuery.focus(); 33 | initilizeSearch(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "3.5" 5 | 6 | sudo: false 7 | 8 | env: 9 | - TOX_ENV=py27-lint 10 | - TOX_ENV=py27-docs 11 | - TOX_ENV=py35-django19 12 | - TOX_ENV=py34-django19 13 | - TOX_ENV=py27-django19 14 | - TOX_ENV=py35-django18 15 | - TOX_ENV=py34-django18 16 | - TOX_ENV=py33-django18 17 | - TOX_ENV=py32-django18 18 | - TOX_ENV=py27-django18 19 | - TOX_ENV=py27-django110 20 | - TOX_ENV=py35-django110 21 | - TOX_ENV=py34-django110 22 | - TOX_ENV=py27-djangomaster 23 | - TOX_ENV=py34-djangomaster 24 | - TOX_ENV=py35-djangomaster 25 | 26 | matrix: 27 | fast_finish: true 28 | allow_failures: 29 | - env: TOX_ENV=py27-djangomaster 30 | - env: TOX_ENV=py34-djangomaster 31 | - env: TOX_ENV=py35-djangomaster 32 | 33 | install: 34 | # Virtualenv < 14 is required to keep the Python 3.2 builds running. 35 | - pip install tox "virtualenv<14" 36 | 37 | script: 38 | - tox -e $TOX_ENV 39 | 40 | after_success: 41 | - pip install codecov 42 | - codecov -e TOX_ENV 43 | 44 | notifications: 45 | email: false 46 | -------------------------------------------------------------------------------- /rest_framework/utils/urls.py: -------------------------------------------------------------------------------- 1 | from django.utils.six.moves.urllib import parse as urlparse 2 | 3 | 4 | def replace_query_param(url, key, val): 5 | """ 6 | Given a URL and a key/val pair, set or replace an item in the query 7 | parameters of the URL, and return the new URL. 8 | """ 9 | (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) 10 | query_dict = urlparse.parse_qs(query, keep_blank_values=True) 11 | query_dict[key] = [val] 12 | query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) 13 | return urlparse.urlunsplit((scheme, netloc, path, query, fragment)) 14 | 15 | 16 | def remove_query_param(url, key): 17 | """ 18 | Given a URL and a key/val pair, remove an item in the query 19 | parameters of the URL, and return the new URL. 20 | """ 21 | (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) 22 | query_dict = urlparse.parse_qs(query, keep_blank_values=True) 23 | query_dict.pop(key, None) 24 | query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) 25 | return urlparse.urlunsplit((scheme, netloc, path, query, fragment)) 26 | -------------------------------------------------------------------------------- /tests/test_write_only_fields.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from rest_framework import serializers 4 | 5 | 6 | class WriteOnlyFieldTests(TestCase): 7 | def setUp(self): 8 | class ExampleSerializer(serializers.Serializer): 9 | email = serializers.EmailField() 10 | password = serializers.CharField(write_only=True) 11 | 12 | def create(self, attrs): 13 | return attrs 14 | 15 | self.Serializer = ExampleSerializer 16 | 17 | def write_only_fields_are_present_on_input(self): 18 | data = { 19 | 'email': 'foo@example.com', 20 | 'password': '123' 21 | } 22 | serializer = self.Serializer(data=data) 23 | self.assertTrue(serializer.is_valid()) 24 | self.assertEqual(serializer.validated_data, data) 25 | 26 | def write_only_fields_are_not_present_on_output(self): 27 | instance = { 28 | 'email': 'foo@example.com', 29 | 'password': '123' 30 | } 31 | serializer = self.Serializer(instance) 32 | self.assertEqual(serializer.data, {'email': 'foo@example.com'}) 33 | -------------------------------------------------------------------------------- /rest_framework/authtoken/serializers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | from rest_framework import serializers 5 | 6 | 7 | class AuthTokenSerializer(serializers.Serializer): 8 | username = serializers.CharField(label=_("Username")) 9 | password = serializers.CharField(label=_("Password"), style={'input_type': 'password'}) 10 | 11 | def validate(self, attrs): 12 | username = attrs.get('username') 13 | password = attrs.get('password') 14 | 15 | if username and password: 16 | user = authenticate(username=username, password=password) 17 | 18 | if user: 19 | if not user.is_active: 20 | msg = _('User account is disabled.') 21 | raise serializers.ValidationError(msg) 22 | else: 23 | msg = _('Unable to log in with provided credentials.') 24 | raise serializers.ValidationError(msg) 25 | else: 26 | msg = _('Must include "username" and "password".') 27 | raise serializers.ValidationError(msg) 28 | 29 | attrs['user'] = user 30 | return attrs 31 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts=--tb=short 3 | 4 | [tox] 5 | envlist = 6 | py27-{lint,docs}, 7 | {py27,py32,py33,py34,py35}-django18, 8 | {py27,py34,py35}-django19, 9 | {py27,py34,py35}-django110, 10 | {py27,py34,py35}-django{master} 11 | 12 | [testenv] 13 | commands = ./runtests.py --fast {posargs} --coverage -rw 14 | setenv = 15 | PYTHONDONTWRITEBYTECODE=1 16 | PYTHONWARNINGS=once 17 | deps = 18 | django18: Django==1.8.15 19 | django19: Django==1.9.10 20 | django110: Django==1.10.2 21 | djangomaster: https://github.com/django/django/archive/master.tar.gz 22 | -rrequirements/requirements-testing.txt 23 | -rrequirements/requirements-optionals.txt 24 | basepython = 25 | py35: python3.5 26 | py34: python3.4 27 | py33: python3.3 28 | py32: python3.2 29 | py27: python2.7 30 | 31 | [testenv:py27-lint] 32 | commands = ./runtests.py --lintonly 33 | deps = 34 | -rrequirements/requirements-codestyle.txt 35 | -rrequirements/requirements-testing.txt 36 | 37 | [testenv:py27-docs] 38 | commands = mkdocs build 39 | deps = 40 | -rrequirements/requirements-testing.txt 41 | -rrequirements/requirements-documentation.txt 42 | -------------------------------------------------------------------------------- /rest_framework/authtoken/migrations/0002_auto_20160226_1747.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.conf import settings 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('authtoken', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='token', 17 | options={'verbose_name_plural': 'Tokens', 'verbose_name': 'Token'}, 18 | ), 19 | migrations.AlterField( 20 | model_name='token', 21 | name='created', 22 | field=models.DateTimeField(verbose_name='Created', auto_now_add=True), 23 | ), 24 | migrations.AlterField( 25 | model_name='token', 26 | name='key', 27 | field=models.CharField(verbose_name='Key', max_length=40, primary_key=True, serialize=False), 28 | ), 29 | migrations.AlterField( 30 | model_name='token', 31 | name='user', 32 | field=models.OneToOneField(to=settings.AUTH_USER_MODEL, verbose_name='User', related_name='auth_token', on_delete=models.CASCADE), 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /tests/test_status.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.test import TestCase 4 | 5 | from rest_framework.status import ( 6 | is_client_error, is_informational, is_redirect, is_server_error, 7 | is_success 8 | ) 9 | 10 | 11 | class TestStatus(TestCase): 12 | def test_status_categories(self): 13 | self.assertFalse(is_informational(99)) 14 | self.assertTrue(is_informational(100)) 15 | self.assertTrue(is_informational(199)) 16 | self.assertFalse(is_informational(200)) 17 | 18 | self.assertFalse(is_success(199)) 19 | self.assertTrue(is_success(200)) 20 | self.assertTrue(is_success(299)) 21 | self.assertFalse(is_success(300)) 22 | 23 | self.assertFalse(is_redirect(299)) 24 | self.assertTrue(is_redirect(300)) 25 | self.assertTrue(is_redirect(399)) 26 | self.assertFalse(is_redirect(400)) 27 | 28 | self.assertFalse(is_client_error(399)) 29 | self.assertTrue(is_client_error(400)) 30 | self.assertTrue(is_client_error(499)) 31 | self.assertFalse(is_client_error(500)) 32 | 33 | self.assertFalse(is_server_error(499)) 34 | self.assertTrue(is_server_error(500)) 35 | self.assertTrue(is_server_error(599)) 36 | self.assertFalse(is_server_error(600)) 37 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/select.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 8 | {% endif %} 9 | 10 | 24 | 25 | {% if field.errors %} 26 | {% for error in field.errors %} 27 | {{ error }} 28 | {% endfor %} 29 | {% endif %} 30 | 31 | {% if field.help_text %} 32 | {{ field.help_text|safe }} 33 | {% endif %} 34 |
35 | -------------------------------------------------------------------------------- /tests/test_middleware.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.contrib.auth.models import User 3 | from django.test import override_settings 4 | 5 | from rest_framework.authentication import TokenAuthentication 6 | from rest_framework.authtoken.models import Token 7 | from rest_framework.test import APITestCase 8 | from rest_framework.views import APIView 9 | 10 | urlpatterns = [ 11 | url(r'^$', APIView.as_view(authentication_classes=(TokenAuthentication,))), 12 | ] 13 | 14 | 15 | class MyMiddleware(object): 16 | 17 | def process_response(self, request, response): 18 | assert hasattr(request, 'user'), '`user` is not set on request' 19 | assert request.user.is_authenticated(), '`user` is not authenticated' 20 | return response 21 | 22 | 23 | @override_settings(ROOT_URLCONF='tests.test_middleware') 24 | class TestMiddleware(APITestCase): 25 | def test_middleware_can_access_user_when_processing_response(self): 26 | user = User.objects.create_user('john', 'john@example.com', 'password') 27 | key = 'abcd1234' 28 | Token.objects.create(key=key, user=user) 29 | 30 | with self.settings( 31 | MIDDLEWARE_CLASSES=('tests.test_middleware.MyMiddleware',) 32 | ): 33 | auth = 'Token ' + key 34 | self.client.get('/', HTTP_AUTHORIZATION=auth) 35 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/checkbox_multiple.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 6 | {% endif %} 7 | 8 | {% if style.inline %} 9 |
10 | {% for key, text in field.choices.items %} 11 | 15 | {% endfor %} 16 |
17 | {% else %} 18 | {% for key, text in field.choices.items %} 19 |
20 | 24 |
25 | {% endfor %} 26 | {% endif %} 27 | 28 | {% if field.errors %} 29 | {% for error in field.errors %} 30 | {{ error }} 31 | {% endfor %} 32 | {% endif %} 33 | 34 | {% if field.help_text %} 35 | {{ field.help_text|safe }} 36 | {% endif %} 37 |
38 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/select_multiple.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load rest_framework %} 3 | {% trans "No items to select." as no_items %} 4 | 5 |
6 | {% if field.label %} 7 | 10 | {% endif %} 11 | 12 | 25 | 26 | {% if field.errors %} 27 | {% for error in field.errors %}{{ error }}{% endfor %} 28 | {% endif %} 29 | 30 | {% if field.help_text %} 31 | {{ field.help_text|safe }} 32 | {% endif %} 33 |
34 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | Copyright (c) 2011-2016, Tom Christie 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /tests/test_viewsets.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from rest_framework import status 4 | from rest_framework.response import Response 5 | from rest_framework.test import APIRequestFactory 6 | from rest_framework.viewsets import GenericViewSet 7 | 8 | factory = APIRequestFactory() 9 | 10 | 11 | class BasicViewSet(GenericViewSet): 12 | def list(self, request, *args, **kwargs): 13 | return Response({'ACTION': 'LIST'}) 14 | 15 | 16 | class InitializeViewSetsTestCase(TestCase): 17 | def test_initialize_view_set_with_actions(self): 18 | request = factory.get('/', '', content_type='application/json') 19 | my_view = BasicViewSet.as_view(actions={ 20 | 'get': 'list', 21 | }) 22 | 23 | response = my_view(request) 24 | self.assertEqual(response.status_code, status.HTTP_200_OK) 25 | self.assertEqual(response.data, {'ACTION': 'LIST'}) 26 | 27 | def test_initialize_view_set_with_empty_actions(self): 28 | try: 29 | BasicViewSet.as_view() 30 | except TypeError as e: 31 | self.assertEqual(str(e), "The `actions` argument must be provided " 32 | "when calling `.as_view()` on a ViewSet. " 33 | "For example `.as_view({'get': 'list'})`") 34 | else: 35 | self.fail("actions must not be empty.") 36 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/checkbox_multiple.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 8 | {% endif %} 9 | 10 |
11 | {% if style.inline %} 12 | {% for key, text in field.choices.items %} 13 | 17 | {% endfor %} 18 | {% else %} 19 | {% for key, text in field.choices.items %} 20 |
21 | 25 |
26 | {% endfor %} 27 | {% endif %} 28 | 29 | {% if field.errors %} 30 | {% for error in field.errors %} 31 | {{ error }} 32 | {% endfor %} 33 | {% endif %} 34 | 35 | {% if field.help_text %} 36 | {{ field.help_text|safe }} 37 | {% endif %} 38 |
39 |
40 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/select.html: -------------------------------------------------------------------------------- 1 | {% load rest_framework %} 2 | 3 |
4 | {% if field.label %} 5 | 8 | {% endif %} 9 | 10 |
11 | 25 | 26 | {% if field.errors %} 27 | {% for error in field.errors %} 28 | {{ error }} 29 | {% endfor %} 30 | {% endif %} 31 | 32 | {% if field.help_text %} 33 | {{ field.help_text|safe }} 34 | {% endif %} 35 |
36 |
37 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/pagination/numbers.html: -------------------------------------------------------------------------------- 1 | 48 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/select_multiple.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load rest_framework %} 3 | 4 | {% trans "No items to select." as no_items %} 5 | 6 |
7 | {% if field.label %} 8 | 11 | {% endif %} 12 | 13 |
14 | 27 | 28 | {% if field.errors %} 29 | {% for error in field.errors %} 30 | {{ error }} 31 | {% endfor %} 32 | {% endif %} 33 | 34 | {% if field.help_text %} 35 | {{ field.help_text|safe }} 36 | {% endif %} 37 |
38 |
39 | -------------------------------------------------------------------------------- /tests/test_settings.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.test import TestCase 4 | 5 | from rest_framework.settings import APISettings 6 | 7 | 8 | class TestSettings(TestCase): 9 | def test_import_error_message_maintained(self): 10 | """ 11 | Make sure import errors are captured and raised sensibly. 12 | """ 13 | settings = APISettings({ 14 | 'DEFAULT_RENDERER_CLASSES': [ 15 | 'tests.invalid_module.InvalidClassName' 16 | ] 17 | }) 18 | with self.assertRaises(ImportError): 19 | settings.DEFAULT_RENDERER_CLASSES 20 | 21 | def test_warning_raised_on_removed_setting(self): 22 | """ 23 | Make sure user is alerted with an error when a removed setting 24 | is set. 25 | """ 26 | with self.assertRaises(RuntimeError): 27 | APISettings({ 28 | 'MAX_PAGINATE_BY': 100 29 | }) 30 | 31 | 32 | class TestSettingTypes(TestCase): 33 | def test_settings_consistently_coerced_to_list(self): 34 | settings = APISettings({ 35 | 'DEFAULT_THROTTLE_CLASSES': ('rest_framework.throttling.BaseThrottle',) 36 | }) 37 | self.assertTrue(isinstance(settings.DEFAULT_THROTTLE_CLASSES, list)) 38 | 39 | settings = APISettings({ 40 | 'DEFAULT_THROTTLE_CLASSES': () 41 | }) 42 | self.assertTrue(isinstance(settings.DEFAULT_THROTTLE_CLASSES, list)) 43 | -------------------------------------------------------------------------------- /rest_framework/authtoken/models.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | import os 3 | 4 | from django.conf import settings 5 | from django.db import models 6 | from django.utils.encoding import python_2_unicode_compatible 7 | from django.utils.translation import ugettext_lazy as _ 8 | 9 | 10 | @python_2_unicode_compatible 11 | class Token(models.Model): 12 | """ 13 | The default authorization token model. 14 | """ 15 | key = models.CharField(_("Key"), max_length=40, primary_key=True) 16 | user = models.OneToOneField( 17 | settings.AUTH_USER_MODEL, related_name='auth_token', 18 | on_delete=models.CASCADE, verbose_name=_("User") 19 | ) 20 | created = models.DateTimeField(_("Created"), auto_now_add=True) 21 | 22 | class Meta: 23 | # Work around for a bug in Django: 24 | # https://code.djangoproject.com/ticket/19422 25 | # 26 | # Also see corresponding ticket: 27 | # https://github.com/tomchristie/django-rest-framework/issues/705 28 | abstract = 'rest_framework.authtoken' not in settings.INSTALLED_APPS 29 | verbose_name = _("Token") 30 | verbose_name_plural = _("Tokens") 31 | 32 | def save(self, *args, **kwargs): 33 | if not self.key: 34 | self.key = self.generate_key() 35 | return super(Token, self).save(*args, **kwargs) 36 | 37 | def generate_key(self): 38 | return binascii.hexlify(os.urandom(20)).decode() 39 | 40 | def __str__(self): 41 | return self.key 42 | -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/js/default.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // JSON highlighting. 3 | prettyPrint(); 4 | 5 | // Bootstrap tooltips. 6 | $('.js-tooltip').tooltip({ 7 | delay: 1000, 8 | container: 'body' 9 | }); 10 | 11 | // Deal with rounded tab styling after tab clicks. 12 | $('a[data-toggle="tab"]:first').on('shown', function(e) { 13 | $(e.target).parents('.tabbable').addClass('first-tab-active'); 14 | }); 15 | 16 | $('a[data-toggle="tab"]:not(:first)').on('shown', function(e) { 17 | $(e.target).parents('.tabbable').removeClass('first-tab-active'); 18 | }); 19 | 20 | $('a[data-toggle="tab"]').click(function() { 21 | document.cookie = "tabstyle=" + this.name + "; path=/"; 22 | }); 23 | 24 | // Store tab preference in cookies & display appropriate tab on load. 25 | var selectedTab = null; 26 | var selectedTabName = getCookie('tabstyle'); 27 | 28 | if (selectedTabName) { 29 | selectedTabName = selectedTabName.replace(/[^a-z-]/g, ''); 30 | } 31 | 32 | if (selectedTabName) { 33 | selectedTab = $('.form-switcher a[name=' + selectedTabName + ']'); 34 | } 35 | 36 | if (selectedTab && selectedTab.length > 0) { 37 | // Display whichever tab is selected. 38 | selectedTab.tab('show'); 39 | } else { 40 | // If no tab selected, display rightmost tab. 41 | $('.form-switcher a:first').tab('show'); 42 | } 43 | 44 | $(window).load(function() { 45 | $('#errorModal').modal('show'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /rest_framework/utils/humanize_datetime.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helper functions that convert strftime formats into more readable representations. 3 | """ 4 | from rest_framework import ISO_8601 5 | 6 | 7 | def datetime_formats(formats): 8 | format = ', '.join(formats).replace( 9 | ISO_8601, 10 | 'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z]' 11 | ) 12 | return humanize_strptime(format) 13 | 14 | 15 | def date_formats(formats): 16 | format = ', '.join(formats).replace(ISO_8601, 'YYYY[-MM[-DD]]') 17 | return humanize_strptime(format) 18 | 19 | 20 | def time_formats(formats): 21 | format = ', '.join(formats).replace(ISO_8601, 'hh:mm[:ss[.uuuuuu]]') 22 | return humanize_strptime(format) 23 | 24 | 25 | def humanize_strptime(format_string): 26 | # Note that we're missing some of the locale specific mappings that 27 | # don't really make sense. 28 | mapping = { 29 | "%Y": "YYYY", 30 | "%y": "YY", 31 | "%m": "MM", 32 | "%b": "[Jan-Dec]", 33 | "%B": "[January-December]", 34 | "%d": "DD", 35 | "%H": "hh", 36 | "%I": "hh", # Requires '%p' to differentiate from '%H'. 37 | "%M": "mm", 38 | "%S": "ss", 39 | "%f": "uuuuuu", 40 | "%a": "[Mon-Sun]", 41 | "%A": "[Monday-Sunday]", 42 | "%p": "[AM|PM]", 43 | "%z": "[+HHMM|-HHMM]" 44 | } 45 | for key, val in mapping.items(): 46 | format_string = format_string.replace(key, val) 47 | return format_string 48 | -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/css/default.css: -------------------------------------------------------------------------------- 1 | 2 | /* The navbar is fixed at >= 980px wide, so add padding to the body to prevent 3 | content running up underneath it. */ 4 | 5 | h1 { 6 | font-weight: 300; 7 | } 8 | 9 | h2, h3 { 10 | font-weight: 300; 11 | } 12 | 13 | .resource-description, .response-info { 14 | margin-bottom: 2em; 15 | } 16 | 17 | .version:before { 18 | content: "v"; 19 | opacity: 0.6; 20 | padding-right: 0.25em; 21 | } 22 | 23 | .version { 24 | font-size: 70%; 25 | } 26 | 27 | .format-option { 28 | font-family: Menlo, Consolas, "Andale Mono", "Lucida Console", monospace; 29 | } 30 | 31 | .button-form { 32 | float: right; 33 | margin-right: 1em; 34 | } 35 | 36 | td.nested { 37 | padding: 0 !important; 38 | } 39 | 40 | td.nested > table { 41 | margin: 0; 42 | } 43 | 44 | form select, form input, form textarea { 45 | width: 90%; 46 | } 47 | 48 | form select[multiple] { 49 | height: 150px; 50 | } 51 | 52 | /* To allow tooltips to work on disabled elements */ 53 | .disabled-tooltip-shield { 54 | position: absolute; 55 | top: 0; 56 | right: 0; 57 | bottom: 0; 58 | left: 0; 59 | } 60 | 61 | .errorlist { 62 | margin-top: 0.5em; 63 | } 64 | 65 | pre { 66 | overflow: auto; 67 | word-wrap: normal; 68 | white-space: pre; 69 | font-size: 12px; 70 | } 71 | 72 | .page-header { 73 | border-bottom: none; 74 | padding-bottom: 0px; 75 | } 76 | 77 | #filtersModal form input[type=submit] { 78 | width: auto; 79 | } 80 | 81 | #filtersModal .modal-body h2 { 82 | margin-top: 0 83 | } 84 | -------------------------------------------------------------------------------- /tests/browsable_api/test_browsable_nested_api.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf.urls import url 4 | from django.test import TestCase 5 | from django.test.utils import override_settings 6 | 7 | from rest_framework import serializers 8 | from rest_framework.generics import ListCreateAPIView 9 | from rest_framework.renderers import BrowsableAPIRenderer 10 | 11 | 12 | class NestedSerializer(serializers.Serializer): 13 | one = serializers.IntegerField(max_value=10) 14 | two = serializers.IntegerField(max_value=10) 15 | 16 | 17 | class NestedSerializerTestSerializer(serializers.Serializer): 18 | nested = NestedSerializer() 19 | 20 | 21 | class NestedSerializersView(ListCreateAPIView): 22 | renderer_classes = (BrowsableAPIRenderer, ) 23 | serializer_class = NestedSerializerTestSerializer 24 | queryset = [{'nested': {'one': 1, 'two': 2}}] 25 | 26 | 27 | urlpatterns = [ 28 | url(r'^api/$', NestedSerializersView.as_view(), name='api'), 29 | ] 30 | 31 | 32 | class DropdownWithAuthTests(TestCase): 33 | """Tests correct dropdown behaviour with Auth views enabled.""" 34 | 35 | @override_settings(ROOT_URLCONF='tests.browsable_api.test_browsable_nested_api') 36 | def test_login(self): 37 | response = self.client.get('/api/') 38 | self.assertEqual(200, response.status_code) 39 | content = response.content.decode('utf-8') 40 | self.assertIn('form action="/api/"', content) 41 | self.assertIn('input name="nested.one"', content) 42 | self.assertIn('input name="nested.two"', content) 43 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | from django.core.exceptions import ObjectDoesNotExist 2 | from django.core.urlresolvers import NoReverseMatch 3 | 4 | 5 | class MockObject(object): 6 | def __init__(self, **kwargs): 7 | self._kwargs = kwargs 8 | for key, val in kwargs.items(): 9 | setattr(self, key, val) 10 | 11 | def __str__(self): 12 | kwargs_str = ', '.join([ 13 | '%s=%s' % (key, value) 14 | for key, value in sorted(self._kwargs.items()) 15 | ]) 16 | return '' % kwargs_str 17 | 18 | 19 | class MockQueryset(object): 20 | def __init__(self, iterable): 21 | self.items = iterable 22 | 23 | def get(self, **lookup): 24 | for item in self.items: 25 | if all([ 26 | getattr(item, key, None) == value 27 | for key, value in lookup.items() 28 | ]): 29 | return item 30 | raise ObjectDoesNotExist() 31 | 32 | 33 | class BadType(object): 34 | """ 35 | When used as a lookup with a `MockQueryset`, these objects 36 | will raise a `TypeError`, as occurs in Django when making 37 | queryset lookups with an incorrect type for the lookup value. 38 | """ 39 | def __eq__(self): 40 | raise TypeError() 41 | 42 | 43 | def mock_reverse(view_name, args=None, kwargs=None, request=None, format=None): 44 | args = args or [] 45 | kwargs = kwargs or {} 46 | value = (args + list(kwargs.values()) + ['-'])[0] 47 | prefix = 'http://example.org' if request else '' 48 | suffix = ('.' + format) if (format is not None) else '' 49 | return '%s/%s/%s%s/' % (prefix, view_name, value, suffix) 50 | 51 | 52 | def fail_reverse(view_name, args=None, kwargs=None, request=None, format=None): 53 | raise NoReverseMatch() 54 | -------------------------------------------------------------------------------- /tests/test_reverse.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf.urls import url 4 | from django.core.urlresolvers import NoReverseMatch 5 | from django.test import TestCase, override_settings 6 | 7 | from rest_framework.reverse import reverse 8 | from rest_framework.test import APIRequestFactory 9 | 10 | factory = APIRequestFactory() 11 | 12 | 13 | def null_view(request): 14 | pass 15 | 16 | urlpatterns = [ 17 | url(r'^view$', null_view, name='view'), 18 | ] 19 | 20 | 21 | class MockVersioningScheme(object): 22 | 23 | def __init__(self, raise_error=False): 24 | self.raise_error = raise_error 25 | 26 | def reverse(self, *args, **kwargs): 27 | if self.raise_error: 28 | raise NoReverseMatch() 29 | 30 | return 'http://scheme-reversed/view' 31 | 32 | 33 | @override_settings(ROOT_URLCONF='tests.test_reverse') 34 | class ReverseTests(TestCase): 35 | """ 36 | Tests for fully qualified URLs when using `reverse`. 37 | """ 38 | def test_reversed_urls_are_fully_qualified(self): 39 | request = factory.get('/view') 40 | url = reverse('view', request=request) 41 | self.assertEqual(url, 'http://testserver/view') 42 | 43 | def test_reverse_with_versioning_scheme(self): 44 | request = factory.get('/view') 45 | request.versioning_scheme = MockVersioningScheme() 46 | 47 | url = reverse('view', request=request) 48 | self.assertEqual(url, 'http://scheme-reversed/view') 49 | 50 | def test_reverse_with_versioning_scheme_fallback_to_default_on_error(self): 51 | request = factory.get('/view') 52 | request.versioning_scheme = MockVersioningScheme(raise_error=True) 53 | 54 | url = reverse('view', request=request) 55 | self.assertEqual(url, 'http://testserver/view') 56 | -------------------------------------------------------------------------------- /docs/topics/writable-nested-serializers.md: -------------------------------------------------------------------------------- 1 | > To save HTTP requests, it may be convenient to send related documents along with the request. 2 | > 3 | > — [JSON API specification for Ember Data][cite]. 4 | 5 | # Writable nested serializers 6 | 7 | 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. 8 | 9 | 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. 10 | 11 | ## One-to-many data structures 12 | 13 | *Example of a **read-only** nested serializer. Nothing complex to worry about here.* 14 | 15 | class ToDoItemSerializer(serializers.ModelSerializer): 16 | class Meta: 17 | model = ToDoItem 18 | fields = ('text', 'is_completed') 19 | 20 | class ToDoListSerializer(serializers.ModelSerializer): 21 | items = ToDoItemSerializer(many=True, read_only=True) 22 | 23 | class Meta: 24 | model = ToDoList 25 | fields = ('title', 'items') 26 | 27 | Some example output from our serializer. 28 | 29 | { 30 | 'title': 'Leaving party preperations', 31 | 'items': [ 32 | {'text': 'Compile playlist', 'is_completed': True}, 33 | {'text': 'Send invites', 'is_completed': False}, 34 | {'text': 'Clean house', 'is_completed': False} 35 | ] 36 | } 37 | 38 | Let's take a look at updating our nested one-to-many data structure. 39 | 40 | ### Validation errors 41 | 42 | ### Adding and removing items 43 | 44 | ### Making PATCH requests 45 | 46 | 47 | [cite]: http://jsonapi.org/format/#url-based-json-api 48 | -------------------------------------------------------------------------------- /rest_framework/static/rest_framework/js/csrf.js: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | var cookieValue = null; 3 | 4 | if (document.cookie && document.cookie != '') { 5 | var cookies = document.cookie.split(';'); 6 | 7 | for (var i = 0; i < cookies.length; i++) { 8 | var cookie = jQuery.trim(cookies[i]); 9 | 10 | // Does this cookie string begin with the name we want? 11 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 12 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 13 | break; 14 | } 15 | } 16 | } 17 | 18 | return cookieValue; 19 | } 20 | 21 | function csrfSafeMethod(method) { 22 | // these HTTP methods do not require CSRF protection 23 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 24 | } 25 | 26 | function sameOrigin(url) { 27 | // test that a given url is a same-origin URL 28 | // url could be relative or scheme relative or absolute 29 | var host = document.location.host; // host + port 30 | var protocol = document.location.protocol; 31 | var sr_origin = '//' + host; 32 | var origin = protocol + sr_origin; 33 | 34 | // Allow absolute or scheme relative URLs to same origin 35 | return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || 36 | (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || 37 | // or any other URL that isn't scheme relative or absolute i.e relative. 38 | !(/^(\/\/|http:|https:).*/.test(url)); 39 | } 40 | 41 | var csrftoken = getCookie(window.drf.csrfCookieName); 42 | 43 | $.ajaxSetup({ 44 | beforeSend: function(xhr, settings) { 45 | if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { 46 | // Send the token to same-origin, relative URLs only. 47 | // Send the token only if the method warrants CSRF protection 48 | // Using the CSRFToken value acquired earlier 49 | xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken); 50 | } 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /tests/browsable_api/test_form_rendering.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | from rest_framework import generics, renderers, serializers, status 4 | from rest_framework.response import Response 5 | from rest_framework.test import APIRequestFactory 6 | from tests.models import BasicModel 7 | 8 | factory = APIRequestFactory() 9 | 10 | 11 | class BasicSerializer(serializers.ModelSerializer): 12 | class Meta: 13 | model = BasicModel 14 | 15 | 16 | class ManyPostView(generics.GenericAPIView): 17 | queryset = BasicModel.objects.all() 18 | serializer_class = BasicSerializer 19 | renderer_classes = (renderers.BrowsableAPIRenderer, renderers.JSONRenderer) 20 | 21 | def post(self, request, *args, **kwargs): 22 | serializer = self.get_serializer(self.get_queryset(), many=True) 23 | return Response(serializer.data, status.HTTP_200_OK) 24 | 25 | 26 | class TestManyPostView(TestCase): 27 | def setUp(self): 28 | """ 29 | Create 3 BasicModel instances. 30 | """ 31 | items = ['foo', 'bar', 'baz'] 32 | for item in items: 33 | BasicModel(text=item).save() 34 | self.objects = BasicModel.objects 35 | self.data = [ 36 | {'id': obj.id, 'text': obj.text} 37 | for obj in self.objects.all() 38 | ] 39 | self.view = ManyPostView.as_view() 40 | 41 | def test_post_many_post_view(self): 42 | """ 43 | POST request to a view that returns a list of objects should 44 | still successfully return the browsable API with a rendered form. 45 | 46 | Regression test for https://github.com/tomchristie/django-rest-framework/pull/3164 47 | """ 48 | data = {} 49 | request = factory.post('/', data, format='json') 50 | with self.assertNumQueries(1): 51 | response = self.view(request).render() 52 | self.assertEqual(response.status_code, status.HTTP_200_OK) 53 | self.assertEqual(len(response.data), 3) 54 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/horizontal/radio.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load rest_framework %} 3 | 4 | {% trans "None" as none_choice %} 5 | 6 |
7 | {% if field.label %} 8 | 11 | {% endif %} 12 | 13 |
14 | {% if style.inline %} 15 | {% if field.allow_null or field.allow_blank %} 16 | 20 | {% endif %} 21 | 22 | {% for key, text in field.choices.items %} 23 | 27 | {% endfor %} 28 | {% else %} 29 | {% if field.allow_null or field.allow_blank %} 30 |
31 | 35 |
36 | {% endif %} 37 | {% for key, text in field.choices.items %} 38 |
39 | 43 |
44 | {% endfor %} 45 | {% endif %} 46 | 47 | {% if field.errors %} 48 | {% for error in field.errors %} 49 | {{ error }} 50 | {% endfor %} 51 | {% endif %} 52 | 53 | {% if field.help_text %} 54 | {{ field.help_text|safe }} 55 | {% endif %} 56 |
57 |
58 | -------------------------------------------------------------------------------- /rest_framework/templates/rest_framework/vertical/radio.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load rest_framework %} 3 | {% trans "None" as none_choice %} 4 | 5 |
6 | {% if field.label %} 7 | 10 | {% endif %} 11 | 12 | {% if style.inline %} 13 |
14 | {% if field.allow_null or field.allow_blank %} 15 | 19 | {% endif %} 20 | 21 | {% for key, text in field.choices.items %} 22 | 26 | {% endfor %} 27 |
28 | {% else %} 29 | {% if field.allow_null or field.allow_blank %} 30 |
31 | 35 |
36 | {% endif %} 37 | 38 | {% for key, text in field.choices.items %} 39 |
40 | 44 |
45 | {% endfor %} 46 | {% endif %} 47 | 48 | {% if field.errors %} 49 | {% for error in field.errors %} 50 | {{ error }} 51 | {% endfor %} 52 | {% endif %} 53 | 54 | {% if field.help_text %} 55 | {{ field.help_text|safe }} 56 | {% endif %} 57 |
58 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | def pytest_configure(): 2 | from django.conf import settings 3 | 4 | settings.configure( 5 | DEBUG_PROPAGATE_EXCEPTIONS=True, 6 | DATABASES={ 7 | 'default': { 8 | 'ENGINE': 'django.db.backends.sqlite3', 9 | 'NAME': ':memory:' 10 | } 11 | }, 12 | SITE_ID=1, 13 | SECRET_KEY='not very secret in tests', 14 | USE_I18N=True, 15 | USE_L10N=True, 16 | STATIC_URL='/static/', 17 | ROOT_URLCONF='tests.urls', 18 | TEMPLATES=[ 19 | { 20 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 21 | 'APP_DIRS': True, 22 | }, 23 | ], 24 | MIDDLEWARE_CLASSES=( 25 | 'django.middleware.common.CommonMiddleware', 26 | 'django.contrib.sessions.middleware.SessionMiddleware', 27 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 28 | 'django.contrib.messages.middleware.MessageMiddleware', 29 | ), 30 | INSTALLED_APPS=( 31 | 'django.contrib.auth', 32 | 'django.contrib.contenttypes', 33 | 'django.contrib.sessions', 34 | 'django.contrib.sites', 35 | 'django.contrib.staticfiles', 36 | 'rest_framework', 37 | 'rest_framework.authtoken', 38 | 'tests', 39 | ), 40 | PASSWORD_HASHERS=( 41 | 'django.contrib.auth.hashers.MD5PasswordHasher', 42 | ), 43 | ) 44 | 45 | # guardian is optional 46 | try: 47 | import guardian # NOQA 48 | except ImportError: 49 | pass 50 | else: 51 | settings.ANONYMOUS_USER_ID = -1 52 | settings.AUTHENTICATION_BACKENDS = ( 53 | 'django.contrib.auth.backends.ModelBackend', 54 | 'guardian.backends.ObjectPermissionBackend', 55 | ) 56 | settings.INSTALLED_APPS += ( 57 | 'guardian', 58 | ) 59 | 60 | try: 61 | import django 62 | django.setup() 63 | except AttributeError: 64 | pass 65 | -------------------------------------------------------------------------------- /rest_framework/utils/breadcrumbs.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.core.urlresolvers import get_script_prefix, resolve 4 | 5 | 6 | def get_breadcrumbs(url, request=None): 7 | """ 8 | Given a url returns a list of breadcrumbs, which are each a 9 | tuple of (name, url). 10 | """ 11 | from rest_framework.reverse import preserve_builtin_query_params 12 | from rest_framework.views import APIView 13 | 14 | def breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen): 15 | """ 16 | Add tuples of (name, url) to the breadcrumbs list, 17 | progressively chomping off parts of the url. 18 | """ 19 | try: 20 | (view, unused_args, unused_kwargs) = resolve(url) 21 | except Exception: 22 | pass 23 | else: 24 | # Check if this is a REST framework view, 25 | # and if so add it to the breadcrumbs 26 | cls = getattr(view, 'cls', None) 27 | if cls is not None and issubclass(cls, APIView): 28 | # Don't list the same view twice in a row. 29 | # Probably an optional trailing slash. 30 | if not seen or seen[-1] != view: 31 | name = cls().get_view_name() 32 | insert_url = preserve_builtin_query_params(prefix + url, request) 33 | breadcrumbs_list.insert(0, (name, insert_url)) 34 | seen.append(view) 35 | 36 | if url == '': 37 | # All done 38 | return breadcrumbs_list 39 | 40 | elif url.endswith('/'): 41 | # Drop trailing slash off the end and continue to try to 42 | # resolve more breadcrumbs 43 | url = url.rstrip('/') 44 | return breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen) 45 | 46 | # Drop trailing non-slash off the end and continue to try to 47 | # resolve more breadcrumbs 48 | url = url[:url.rfind('/') + 1] 49 | return breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen) 50 | 51 | prefix = get_script_prefix().rstrip('/') 52 | url = url[len(prefix):] 53 | return breadcrumbs_recursive(url, [], prefix, []) 54 | -------------------------------------------------------------------------------- /tests/test_negotiation.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.test import TestCase 4 | 5 | from rest_framework.negotiation import DefaultContentNegotiation 6 | from rest_framework.renderers import BaseRenderer 7 | from rest_framework.request import Request 8 | from rest_framework.test import APIRequestFactory 9 | 10 | factory = APIRequestFactory() 11 | 12 | 13 | class MockOpenAPIRenderer(BaseRenderer): 14 | media_type = 'application/openapi+json;version=2.0' 15 | format = 'swagger' 16 | 17 | 18 | class MockJSONRenderer(BaseRenderer): 19 | media_type = 'application/json' 20 | 21 | 22 | class MockHTMLRenderer(BaseRenderer): 23 | media_type = 'text/html' 24 | 25 | 26 | class NoCharsetSpecifiedRenderer(BaseRenderer): 27 | media_type = 'my/media' 28 | 29 | 30 | class TestAcceptedMediaType(TestCase): 31 | def setUp(self): 32 | self.renderers = [MockJSONRenderer(), MockHTMLRenderer(), MockOpenAPIRenderer()] 33 | self.negotiator = DefaultContentNegotiation() 34 | 35 | def select_renderer(self, request): 36 | return self.negotiator.select_renderer(request, self.renderers) 37 | 38 | def test_client_without_accept_use_renderer(self): 39 | request = Request(factory.get('/')) 40 | accepted_renderer, accepted_media_type = self.select_renderer(request) 41 | self.assertEqual(accepted_media_type, 'application/json') 42 | 43 | def test_client_underspecifies_accept_use_renderer(self): 44 | request = Request(factory.get('/', HTTP_ACCEPT='*/*')) 45 | accepted_renderer, accepted_media_type = self.select_renderer(request) 46 | self.assertEqual(accepted_media_type, 'application/json') 47 | 48 | def test_client_overspecifies_accept_use_client(self): 49 | request = Request(factory.get('/', HTTP_ACCEPT='application/json; indent=8')) 50 | accepted_renderer, accepted_media_type = self.select_renderer(request) 51 | self.assertEqual(accepted_media_type, 'application/json; indent=8') 52 | 53 | def test_client_specifies_parameter(self): 54 | request = Request(factory.get('/', HTTP_ACCEPT='application/openapi+json;version=2.0')) 55 | accepted_renderer, accepted_media_type = self.select_renderer(request) 56 | self.assertEqual(accepted_media_type, 'application/openapi+json;version=2.0') 57 | self.assertEqual(accepted_renderer.format, 'swagger') 58 | -------------------------------------------------------------------------------- /rest_framework/utils/html.py: -------------------------------------------------------------------------------- 1 | """ 2 | Helpers for dealing with HTML input. 3 | """ 4 | import re 5 | 6 | from django.utils.datastructures import MultiValueDict 7 | 8 | 9 | def is_html_input(dictionary): 10 | # MultiDict type datastructures are used to represent HTML form input, 11 | # which may have more than one value for each key. 12 | return hasattr(dictionary, 'getlist') 13 | 14 | 15 | def parse_html_list(dictionary, prefix=''): 16 | """ 17 | Used to support list values in HTML forms. 18 | Supports lists of primitives and/or dictionaries. 19 | 20 | * List of primitives. 21 | 22 | { 23 | '[0]': 'abc', 24 | '[1]': 'def', 25 | '[2]': 'hij' 26 | } 27 | --> 28 | [ 29 | 'abc', 30 | 'def', 31 | 'hij' 32 | ] 33 | 34 | * List of dictionaries. 35 | 36 | { 37 | '[0]foo': 'abc', 38 | '[0]bar': 'def', 39 | '[1]foo': 'hij', 40 | '[1]bar': 'klm', 41 | } 42 | --> 43 | [ 44 | {'foo': 'abc', 'bar': 'def'}, 45 | {'foo': 'hij', 'bar': 'klm'} 46 | ] 47 | """ 48 | ret = {} 49 | regex = re.compile(r'^%s\[([0-9]+)\](.*)$' % re.escape(prefix)) 50 | for field, value in dictionary.items(): 51 | match = regex.match(field) 52 | if not match: 53 | continue 54 | index, key = match.groups() 55 | index = int(index) 56 | if not key: 57 | ret[index] = value 58 | elif isinstance(ret.get(index), dict): 59 | ret[index][key] = value 60 | else: 61 | ret[index] = MultiValueDict({key: [value]}) 62 | return [ret[item] for item in sorted(ret.keys())] 63 | 64 | 65 | def parse_html_dict(dictionary, prefix=''): 66 | """ 67 | Used to support dictionary values in HTML forms. 68 | 69 | { 70 | 'profile.username': 'example', 71 | 'profile.email': 'example@example.com', 72 | } 73 | --> 74 | { 75 | 'profile': { 76 | 'username': 'example', 77 | 'email': 'example@example.com' 78 | } 79 | } 80 | """ 81 | ret = MultiValueDict() 82 | regex = re.compile(r'^%s\.(.+)$' % re.escape(prefix)) 83 | for field in dictionary: 84 | match = regex.match(field) 85 | if not match: 86 | continue 87 | key = match.groups()[0] 88 | value = dictionary.getlist(field) 89 | ret.setlist(key, value) 90 | 91 | return ret 92 | -------------------------------------------------------------------------------- /tests/test_multitable_inheritance.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.db import models 4 | from django.test import TestCase 5 | 6 | from rest_framework import serializers 7 | from tests.models import RESTFrameworkModel 8 | 9 | 10 | # Models 11 | class ParentModel(RESTFrameworkModel): 12 | name1 = models.CharField(max_length=100) 13 | 14 | 15 | class ChildModel(ParentModel): 16 | name2 = models.CharField(max_length=100) 17 | 18 | 19 | class AssociatedModel(RESTFrameworkModel): 20 | ref = models.OneToOneField(ParentModel, primary_key=True, on_delete=models.CASCADE) 21 | name = models.CharField(max_length=100) 22 | 23 | 24 | # Serializers 25 | class DerivedModelSerializer(serializers.ModelSerializer): 26 | class Meta: 27 | model = ChildModel 28 | fields = '__all__' 29 | 30 | 31 | class AssociatedModelSerializer(serializers.ModelSerializer): 32 | class Meta: 33 | model = AssociatedModel 34 | fields = '__all__' 35 | 36 | 37 | # Tests 38 | class InheritedModelSerializationTests(TestCase): 39 | 40 | def test_multitable_inherited_model_fields_as_expected(self): 41 | """ 42 | Assert that the parent pointer field is not included in the fields 43 | serialized fields 44 | """ 45 | child = ChildModel(name1='parent name', name2='child name') 46 | serializer = DerivedModelSerializer(child) 47 | self.assertEqual(set(serializer.data.keys()), 48 | set(['name1', 'name2', 'id'])) 49 | 50 | def test_onetoone_primary_key_model_fields_as_expected(self): 51 | """ 52 | Assert that a model with a onetoone field that is the primary key is 53 | not treated like a derived model 54 | """ 55 | parent = ParentModel.objects.create(name1='parent name') 56 | associate = AssociatedModel.objects.create(name='hello', ref=parent) 57 | serializer = AssociatedModelSerializer(associate) 58 | self.assertEqual(set(serializer.data.keys()), 59 | set(['name', 'ref'])) 60 | 61 | def test_data_is_valid_without_parent_ptr(self): 62 | """ 63 | Assert that the pointer to the parent table is not a required field 64 | for input data 65 | """ 66 | data = { 67 | 'name1': 'parent name', 68 | 'name2': 'child name', 69 | } 70 | serializer = DerivedModelSerializer(data=data) 71 | self.assertEqual(serializer.is_valid(), True) 72 | -------------------------------------------------------------------------------- /rest_framework/reverse.py: -------------------------------------------------------------------------------- 1 | """ 2 | Provide urlresolver functions that return fully qualified URLs or view names 3 | """ 4 | from __future__ import unicode_literals 5 | 6 | from django.core.urlresolvers import reverse as django_reverse 7 | from django.core.urlresolvers import NoReverseMatch 8 | from django.utils import six 9 | from django.utils.functional import lazy 10 | 11 | from rest_framework.settings import api_settings 12 | from rest_framework.utils.urls import replace_query_param 13 | 14 | 15 | def preserve_builtin_query_params(url, request=None): 16 | """ 17 | Given an incoming request, and an outgoing URL representation, 18 | append the value of any built-in query parameters. 19 | """ 20 | if request is None: 21 | return url 22 | 23 | overrides = [ 24 | api_settings.URL_FORMAT_OVERRIDE, 25 | ] 26 | 27 | for param in overrides: 28 | if param and (param in request.GET): 29 | value = request.GET[param] 30 | url = replace_query_param(url, param, value) 31 | 32 | return url 33 | 34 | 35 | def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra): 36 | """ 37 | If versioning is being used then we pass any `reverse` calls through 38 | to the versioning scheme instance, so that the resulting URL 39 | can be modified if needed. 40 | """ 41 | scheme = getattr(request, 'versioning_scheme', None) 42 | if scheme is not None: 43 | try: 44 | url = scheme.reverse(viewname, args, kwargs, request, format, **extra) 45 | except NoReverseMatch: 46 | # In case the versioning scheme reversal fails, fallback to the 47 | # default implementation 48 | url = _reverse(viewname, args, kwargs, request, format, **extra) 49 | else: 50 | url = _reverse(viewname, args, kwargs, request, format, **extra) 51 | 52 | return preserve_builtin_query_params(url, request) 53 | 54 | 55 | def _reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra): 56 | """ 57 | Same as `django.core.urlresolvers.reverse`, but optionally takes a request 58 | and returns a fully qualified URL, using the request to get the base URL. 59 | """ 60 | if format is not None: 61 | kwargs = kwargs or {} 62 | kwargs['format'] = format 63 | url = django_reverse(viewname, args=args, kwargs=kwargs, **extra) 64 | if request: 65 | return request.build_absolute_uri(url) 66 | return url 67 | 68 | 69 | reverse_lazy = lazy(reverse, six.text_type) 70 | -------------------------------------------------------------------------------- /tests/test_encoders.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime, timedelta, tzinfo 2 | from decimal import Decimal 3 | from uuid import uuid4 4 | 5 | from django.test import TestCase 6 | 7 | from rest_framework.utils.encoders import JSONEncoder 8 | 9 | 10 | class JSONEncoderTests(TestCase): 11 | """ 12 | Tests the JSONEncoder method 13 | """ 14 | 15 | def setUp(self): 16 | self.encoder = JSONEncoder() 17 | 18 | def test_encode_decimal(self): 19 | """ 20 | Tests encoding a decimal 21 | """ 22 | d = Decimal(3.14) 23 | self.assertEqual(d, float(d)) 24 | 25 | def test_encode_datetime(self): 26 | """ 27 | Tests encoding a datetime object 28 | """ 29 | current_time = datetime.now() 30 | self.assertEqual(self.encoder.default(current_time), current_time.isoformat()) 31 | 32 | def test_encode_time(self): 33 | """ 34 | Tests encoding a timezone 35 | """ 36 | current_time = datetime.now().time() 37 | self.assertEqual(self.encoder.default(current_time), current_time.isoformat()[:12]) 38 | 39 | def test_encode_time_tz(self): 40 | """ 41 | Tests encoding a timezone aware timestamp 42 | """ 43 | 44 | class UTC(tzinfo): 45 | """ 46 | Class extending tzinfo to mimic UTC time 47 | """ 48 | def utcoffset(self, dt): 49 | return timedelta(0) 50 | 51 | def tzname(self, dt): 52 | return "UTC" 53 | 54 | def dst(self, dt): 55 | return timedelta(0) 56 | 57 | current_time = datetime.now().time() 58 | current_time = current_time.replace(tzinfo=UTC()) 59 | with self.assertRaises(ValueError): 60 | self.encoder.default(current_time) 61 | 62 | def test_encode_date(self): 63 | """ 64 | Tests encoding a date object 65 | """ 66 | current_date = date.today() 67 | self.assertEqual(self.encoder.default(current_date), current_date.isoformat()) 68 | 69 | def test_encode_timedelta(self): 70 | """ 71 | Tests encoding a timedelta object 72 | """ 73 | delta = timedelta(hours=1) 74 | self.assertEqual(self.encoder.default(delta), str(delta.total_seconds())) 75 | 76 | def test_encode_uuid(self): 77 | """ 78 | Tests encoding a UUID object 79 | """ 80 | unique_id = uuid4() 81 | self.assertEqual(self.encoder.default(unique_id), str(unique_id)) 82 | -------------------------------------------------------------------------------- /rest_framework/status.py: -------------------------------------------------------------------------------- 1 | """ 2 | Descriptive HTTP status codes, for code readability. 3 | 4 | See RFC 2616 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 5 | And RFC 6585 - http://tools.ietf.org/html/rfc6585 6 | And RFC 4918 - https://tools.ietf.org/html/rfc4918 7 | """ 8 | from __future__ import unicode_literals 9 | 10 | 11 | def is_informational(code): 12 | return code >= 100 and code <= 199 13 | 14 | 15 | def is_success(code): 16 | return code >= 200 and code <= 299 17 | 18 | 19 | def is_redirect(code): 20 | return code >= 300 and code <= 399 21 | 22 | 23 | def is_client_error(code): 24 | return code >= 400 and code <= 499 25 | 26 | 27 | def is_server_error(code): 28 | return code >= 500 and code <= 599 29 | 30 | 31 | HTTP_100_CONTINUE = 100 32 | HTTP_101_SWITCHING_PROTOCOLS = 101 33 | HTTP_200_OK = 200 34 | HTTP_201_CREATED = 201 35 | HTTP_202_ACCEPTED = 202 36 | HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 37 | HTTP_204_NO_CONTENT = 204 38 | HTTP_205_RESET_CONTENT = 205 39 | HTTP_206_PARTIAL_CONTENT = 206 40 | HTTP_207_MULTI_STATUS = 207 41 | HTTP_300_MULTIPLE_CHOICES = 300 42 | HTTP_301_MOVED_PERMANENTLY = 301 43 | HTTP_302_FOUND = 302 44 | HTTP_303_SEE_OTHER = 303 45 | HTTP_304_NOT_MODIFIED = 304 46 | HTTP_305_USE_PROXY = 305 47 | HTTP_306_RESERVED = 306 48 | HTTP_307_TEMPORARY_REDIRECT = 307 49 | HTTP_400_BAD_REQUEST = 400 50 | HTTP_401_UNAUTHORIZED = 401 51 | HTTP_402_PAYMENT_REQUIRED = 402 52 | HTTP_403_FORBIDDEN = 403 53 | HTTP_404_NOT_FOUND = 404 54 | HTTP_405_METHOD_NOT_ALLOWED = 405 55 | HTTP_406_NOT_ACCEPTABLE = 406 56 | HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407 57 | HTTP_408_REQUEST_TIMEOUT = 408 58 | HTTP_409_CONFLICT = 409 59 | HTTP_410_GONE = 410 60 | HTTP_411_LENGTH_REQUIRED = 411 61 | HTTP_412_PRECONDITION_FAILED = 412 62 | HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413 63 | HTTP_414_REQUEST_URI_TOO_LONG = 414 64 | HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415 65 | HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416 66 | HTTP_417_EXPECTATION_FAILED = 417 67 | HTTP_422_UNPROCESSABLE_ENTITY = 422 68 | HTTP_423_LOCKED = 423 69 | HTTP_424_FAILED_DEPENDENCY = 424 70 | HTTP_428_PRECONDITION_REQUIRED = 428 71 | HTTP_429_TOO_MANY_REQUESTS = 429 72 | HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 73 | HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 74 | HTTP_500_INTERNAL_SERVER_ERROR = 500 75 | HTTP_501_NOT_IMPLEMENTED = 501 76 | HTTP_502_BAD_GATEWAY = 502 77 | HTTP_503_SERVICE_UNAVAILABLE = 503 78 | HTTP_504_GATEWAY_TIMEOUT = 504 79 | HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505 80 | HTTP_507_INSUFFICIENT_STORAGE = 507 81 | HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 82 | -------------------------------------------------------------------------------- /docs_theme/nav.html: -------------------------------------------------------------------------------- 1 | 47 | -------------------------------------------------------------------------------- /rest_framework/utils/formatting.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility functions to return a formatted name and description for a given view. 3 | """ 4 | from __future__ import unicode_literals 5 | 6 | import re 7 | 8 | from django.utils.encoding import force_text 9 | from django.utils.html import escape 10 | from django.utils.safestring import mark_safe 11 | 12 | from rest_framework.compat import apply_markdown 13 | 14 | 15 | def remove_trailing_string(content, trailing): 16 | """ 17 | Strip trailing component `trailing` from `content` if it exists. 18 | Used when generating names from view classes. 19 | """ 20 | if content.endswith(trailing) and content != trailing: 21 | return content[:-len(trailing)] 22 | return content 23 | 24 | 25 | def dedent(content): 26 | """ 27 | Remove leading indent from a block of text. 28 | Used when generating descriptions from docstrings. 29 | 30 | Note that python's `textwrap.dedent` doesn't quite cut it, 31 | as it fails to dedent multiline docstrings that include 32 | unindented text on the initial line. 33 | """ 34 | content = force_text(content) 35 | whitespace_counts = [ 36 | len(line) - len(line.lstrip(' ')) 37 | for line in content.splitlines()[1:] if line.lstrip() 38 | ] 39 | tab_counts = [ 40 | len(line) - len(line.lstrip('\t')) 41 | for line in content.splitlines()[1:] if line.lstrip() 42 | ] 43 | 44 | # unindent the content if needed 45 | if whitespace_counts: 46 | whitespace_pattern = '^' + (' ' * min(whitespace_counts)) 47 | content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content) 48 | elif tab_counts: 49 | whitespace_pattern = '^' + ('\t' * min(whitespace_counts)) 50 | content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content) 51 | 52 | return content.strip() 53 | 54 | 55 | def camelcase_to_spaces(content): 56 | """ 57 | Translate 'CamelCaseNames' to 'Camel Case Names'. 58 | Used when generating names from view classes. 59 | """ 60 | camelcase_boundry = '(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))' 61 | content = re.sub(camelcase_boundry, ' \\1', content).strip() 62 | return ' '.join(content.split('_')).title() 63 | 64 | 65 | def markup_description(description): 66 | """ 67 | Apply HTML markup to the given description. 68 | """ 69 | if apply_markdown: 70 | description = apply_markdown(description) 71 | else: 72 | description = escape(description).replace('\n', '
') 73 | description = '

' + description + '

' 74 | return mark_safe(description) 75 | -------------------------------------------------------------------------------- /rest_framework/urlpatterns.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.conf.urls import include, url 4 | from django.core.urlresolvers import RegexURLResolver 5 | 6 | from rest_framework.settings import api_settings 7 | 8 | 9 | def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required): 10 | ret = [] 11 | for urlpattern in urlpatterns: 12 | if isinstance(urlpattern, RegexURLResolver): 13 | # Set of included URL patterns 14 | regex = urlpattern.regex.pattern 15 | namespace = urlpattern.namespace 16 | app_name = urlpattern.app_name 17 | kwargs = urlpattern.default_kwargs 18 | # Add in the included patterns, after applying the suffixes 19 | patterns = apply_suffix_patterns(urlpattern.url_patterns, 20 | suffix_pattern, 21 | suffix_required) 22 | ret.append(url(regex, include(patterns, namespace, app_name), kwargs)) 23 | 24 | else: 25 | # Regular URL pattern 26 | regex = urlpattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern 27 | view = urlpattern.callback 28 | kwargs = urlpattern.default_args 29 | name = urlpattern.name 30 | # Add in both the existing and the new urlpattern 31 | if not suffix_required: 32 | ret.append(urlpattern) 33 | ret.append(url(regex, view, kwargs, name)) 34 | 35 | return ret 36 | 37 | 38 | def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None): 39 | """ 40 | Supplement existing urlpatterns with corresponding patterns that also 41 | include a '.format' suffix. Retains urlpattern ordering. 42 | 43 | urlpatterns: 44 | A list of URL patterns. 45 | 46 | suffix_required: 47 | If `True`, only suffixed URLs will be generated, and non-suffixed 48 | URLs will not be used. Defaults to `False`. 49 | 50 | allowed: 51 | An optional tuple/list of allowed suffixes. eg ['json', 'api'] 52 | Defaults to `None`, which allows any suffix. 53 | """ 54 | suffix_kwarg = api_settings.FORMAT_SUFFIX_KWARG 55 | if allowed: 56 | if len(allowed) == 1: 57 | allowed_pattern = allowed[0] 58 | else: 59 | allowed_pattern = '(%s)' % '|'.join(allowed) 60 | suffix_pattern = r'\.(?P<%s>%s)/?$' % (suffix_kwarg, allowed_pattern) 61 | else: 62 | suffix_pattern = r'\.(?P<%s>[a-z0-9]+)/?$' % suffix_kwarg 63 | 64 | return apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required) 65 | -------------------------------------------------------------------------------- /docs/api-guide/reverse.md: -------------------------------------------------------------------------------- 1 | source: reverse.py 2 | 3 | # Returning URLs 4 | 5 | > The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components. 6 | > 7 | > — Roy Fielding, [Architectural Styles and the Design of Network-based Software Architectures][cite] 8 | 9 | As a rule, it's probably better practice to return absolute URIs from your Web APIs, such as `http://example.com/foobar`, rather than returning relative URIs, such as `/foobar`. 10 | 11 | The advantages of doing so are: 12 | 13 | * It's more explicit. 14 | * It leaves less work for your API clients. 15 | * There's no ambiguity about the meaning of the string when it's found in representations such as JSON that do not have a native URI type. 16 | * It makes it easy to do things like markup HTML representations with hyperlinks. 17 | 18 | REST framework provides two utility functions to make it more simple to return absolute URIs from your Web API. 19 | 20 | There's no requirement for you to use them, but if you do then the self-describing API will be able to automatically hyperlink its output for you, which makes browsing the API much easier. 21 | 22 | ## reverse 23 | 24 | **Signature:** `reverse(viewname, *args, **kwargs)` 25 | 26 | Has the same behavior as [`django.core.urlresolvers.reverse`][reverse], except that it returns a fully qualified URL, using the request to determine the host and port. 27 | 28 | You should **include the request as a keyword argument** to the function, for example: 29 | 30 | from rest_framework.reverse import reverse 31 | from rest_framework.views import APIView 32 | from django.utils.timezone import now 33 | 34 | class APIRootView(APIView): 35 | def get(self, request): 36 | year = now().year 37 | data = { 38 | ... 39 | 'year-summary-url': reverse('year-summary', args=[year], request=request) 40 | } 41 | return Response(data) 42 | 43 | ## reverse_lazy 44 | 45 | **Signature:** `reverse_lazy(viewname, *args, **kwargs)` 46 | 47 | Has the same behavior as [`django.core.urlresolvers.reverse_lazy`][reverse-lazy], except that it returns a fully qualified URL, using the request to determine the host and port. 48 | 49 | As with the `reverse` function, you should **include the request as a keyword argument** to the function, for example: 50 | 51 | api_root = reverse_lazy('api-root', request=request) 52 | 53 | [cite]: http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5 54 | [reverse]: https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse 55 | [reverse-lazy]: https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy 56 | -------------------------------------------------------------------------------- /tests/browsable_api/test_browsable_api.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.contrib.auth.models import User 4 | from django.test import TestCase, override_settings 5 | 6 | from rest_framework.test import APIClient 7 | 8 | 9 | @override_settings(ROOT_URLCONF='tests.browsable_api.auth_urls') 10 | class DropdownWithAuthTests(TestCase): 11 | """Tests correct dropdown behaviour with Auth views enabled.""" 12 | def setUp(self): 13 | self.client = APIClient(enforce_csrf_checks=True) 14 | self.username = 'john' 15 | self.email = 'lennon@thebeatles.com' 16 | self.password = 'password' 17 | self.user = User.objects.create_user( 18 | self.username, 19 | self.email, 20 | self.password 21 | ) 22 | 23 | def tearDown(self): 24 | self.client.logout() 25 | 26 | def test_name_shown_when_logged_in(self): 27 | self.client.login(username=self.username, password=self.password) 28 | response = self.client.get('/') 29 | self.assertContains(response, 'john') 30 | 31 | def test_logout_shown_when_logged_in(self): 32 | self.client.login(username=self.username, password=self.password) 33 | response = self.client.get('/') 34 | self.assertContains(response, '>Log out<') 35 | 36 | def test_login_shown_when_logged_out(self): 37 | response = self.client.get('/') 38 | self.assertContains(response, '>Log in<') 39 | 40 | 41 | @override_settings(ROOT_URLCONF='tests.browsable_api.no_auth_urls') 42 | class NoDropdownWithoutAuthTests(TestCase): 43 | """Tests correct dropdown behaviour with Auth views NOT enabled.""" 44 | def setUp(self): 45 | self.client = APIClient(enforce_csrf_checks=True) 46 | self.username = 'john' 47 | self.email = 'lennon@thebeatles.com' 48 | self.password = 'password' 49 | self.user = User.objects.create_user( 50 | self.username, 51 | self.email, 52 | self.password 53 | ) 54 | 55 | def tearDown(self): 56 | self.client.logout() 57 | 58 | def test_name_shown_when_logged_in(self): 59 | self.client.login(username=self.username, password=self.password) 60 | response = self.client.get('/') 61 | self.assertContains(response, 'john') 62 | 63 | def test_dropdown_not_shown_when_logged_in(self): 64 | self.client.login(username=self.username, password=self.password) 65 | response = self.client.get('/') 66 | self.assertNotContains(response, '