From 176831e22b14379ac780491ec0c16834e598f4e1 Mon Sep 17 00:00:00 2001 From: Michael Borisov Date: Wed, 8 Feb 2017 18:17:58 +0300 Subject: [PATCH 01/15] Missing comma (#4889) --- docs/api-guide/serializers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 6602d5e2c..e157845a9 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -700,7 +700,7 @@ You can override a URL field view name and lookup field by using either, or both model = Account fields = ('account_url', 'account_name', 'users', 'created') extra_kwargs = { - 'url': {'view_name': 'accounts', 'lookup_field': 'account_name'} + 'url': {'view_name': 'accounts', 'lookup_field': 'account_name'}, 'users': {'lookup_field': 'username'} } From eb5774229ff1562218f73fd885eff7dd8668ea37 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 10 Feb 2017 11:15:39 +0000 Subject: [PATCH 02/15] Version 3.5.4 (#4894) --- docs/topics/release-notes.md | 38 ++++++++++++++++++++++++++++++++++++ rest_framework/__init__.py | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index af6ad7a74..085f888b7 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -40,6 +40,24 @@ You can determine your currently installed version using `pip freeze`: ## 3.5.x series +### 3.5.4 + +**Date**: [10th February 2017][3.5.4-milestone] + +* Add max_length and min_length arguments for ListField. ([#4877][gh4877]) +* Add per-view custom exception handler support. ([#4753][gh4753]) +* Support disabling of declared fields on serializer subclasses. ([#4764][gh4764]) +* Support custom view names on `@list_route` and `@detail_route` endpoints. ([#4821][gh4821]) +* Correct labels for fields in login template when custom user model is used. ([#4841][gh4841]) +* Whitespace fixes for descriptions generated from docstrings. ([#4759][gh4759], [#4869][gh4869], [#4870][gh4870]) +* Better error reporting when schemas are returned by views without a schema renderer. ([#4790][gh4790]) +* Fix for returned response of `PUT` requests when `prefetch_related` is used. ([#4661][gh4661], [#4668][gh4668]) +* Fix for breadcrumb view names. ([#4750][gh4750]) +* Fix for RequestsClient ensuring fully qualified URLs. ([#4678][gh4678]) +* Fix for incorrect behavior of writable-nested fields check in some cases. ([#4634][gh4634], [#4669][gh4669]) +* Resolve Django deprecation warnings. ([#4712][gh4712]) +* Various cleanup of test cases. + ### 3.5.3 **Date**: [7th November 2016][3.5.3-milestone] @@ -639,6 +657,7 @@ For older release notes, [please see the version 2.x documentation][old-release- [3.5.1-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.5.1+Release%22 [3.5.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.5.2+Release%22 [3.5.3-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.5.3+Release%22 +[3.5.4-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.5.4+Release%22 [gh2013]: https://github.com/tomchristie/django-rest-framework/issues/2013 @@ -1216,3 +1235,22 @@ For older release notes, [please see the version 2.x documentation][old-release- [gh4645]: https://github.com/tomchristie/django-rest-framework/issues/4645 [gh4646]: https://github.com/tomchristie/django-rest-framework/issues/4646 [gh4650]: https://github.com/tomchristie/django-rest-framework/issues/4650 + + + +[gh4877]: https://github.com/tomchristie/django-rest-framework/issues/4877 +[gh4753]: https://github.com/tomchristie/django-rest-framework/issues/4753 +[gh4764]: https://github.com/tomchristie/django-rest-framework/issues/4764 +[gh4821]: https://github.com/tomchristie/django-rest-framework/issues/4821 +[gh4841]: https://github.com/tomchristie/django-rest-framework/issues/4841 +[gh4759]: https://github.com/tomchristie/django-rest-framework/issues/4759 +[gh4869]: https://github.com/tomchristie/django-rest-framework/issues/4869 +[gh4870]: https://github.com/tomchristie/django-rest-framework/issues/4870 +[gh4790]: https://github.com/tomchristie/django-rest-framework/issues/4790 +[gh4661]: https://github.com/tomchristie/django-rest-framework/issues/4661 +[gh4668]: https://github.com/tomchristie/django-rest-framework/issues/4668 +[gh4750]: https://github.com/tomchristie/django-rest-framework/issues/4750 +[gh4678]: https://github.com/tomchristie/django-rest-framework/issues/4678 +[gh4634]: https://github.com/tomchristie/django-rest-framework/issues/4634 +[gh4669]: https://github.com/tomchristie/django-rest-framework/issues/4669 +[gh4712]: https://github.com/tomchristie/django-rest-framework/issues/4712 diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index d9aa7718c..7a5df6804 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -8,7 +8,7 @@ ______ _____ _____ _____ __ """ __title__ = 'Django REST framework' -__version__ = '3.5.3' +__version__ = '3.5.4' __author__ = 'Tom Christie' __license__ = 'BSD 2-Clause' __copyright__ = 'Copyright 2011-2016 Tom Christie' From 40e34627676286918084c3f8c467ba60f37fd80e Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Sat, 11 Feb 2017 17:37:27 +0100 Subject: [PATCH 03/15] Reverted "Removed multi-table inheritance auto created PK from serialize" 1ecbeebbe5e1f4ac5f7f8112d80f3ea13972cc0f. --- rest_framework/utils/model_meta.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rest_framework/utils/model_meta.py b/rest_framework/utils/model_meta.py index f8200c98f..3e3e434e6 100644 --- a/rest_framework/utils/model_meta.py +++ b/rest_framework/utils/model_meta.py @@ -76,12 +76,7 @@ def _get_forward_relationships(opts): Returns an `OrderedDict` of field names to `RelationInfo`. """ forward_relations = OrderedDict() - for field in [ - field for field in opts.fields - if field.serialize and get_remote_field(field) and not (field.primary_key and field.one_to_one) - # If the field is a OneToOneField and it's been marked as PK, then this - # is a multi-table inheritance auto created PK ('%_ptr'). - ]: + for field in [field for field in opts.fields if field.serialize and get_remote_field(field)]: forward_relations[field.name] = RelationInfo( model_field=field, related_model=get_related_model(field), From de8fcbf6968a30405ada6647bc12d7819f4cf62c Mon Sep 17 00:00:00 2001 From: Eduard Iskandarov Date: Tue, 14 Feb 2017 13:27:33 +0300 Subject: [PATCH 04/15] Refs: #4256 delete unrelevant documentation --- docs/api-guide/fields.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 22ce7dd77..677598205 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -303,8 +303,6 @@ Format strings may either be [Python strftime formats][strftime] which explicitl When a value of `None` is used for the format `datetime` objects will be returned by `to_representation` and the final output representation will determined by the renderer class. -In the case of JSON this means the default datetime representation uses the [ECMA 262 date time string specification][ecma262]. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: `2013-01-29T12:34:56.123Z`. - #### `auto_now` and `auto_now_add` model fields. When using `ModelSerializer` or `HyperlinkedModelSerializer`, note that any model fields with `auto_now=True` or `auto_now_add=True` will use serializer fields that are `read_only=True` by default. From cd469f616ae78107497a0e74827c4fdbda97d184 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 15 Feb 2017 07:14:49 +0100 Subject: [PATCH 05/15] Increased utils/encoders.py test coverage. --- tests/test_encoders.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/tests/test_encoders.py b/tests/test_encoders.py index 5c6915d0c..8f8694c47 100644 --- a/tests/test_encoders.py +++ b/tests/test_encoders.py @@ -1,14 +1,20 @@ -from datetime import date, datetime, timedelta, tzinfo +from datetime import date, datetime, timedelta from decimal import Decimal from uuid import uuid4 import pytest from django.test import TestCase +from django.utils.timezone import utc from rest_framework.compat import coreapi from rest_framework.utils.encoders import JSONEncoder +class MockList(object): + def tolist(self): + return [1, 2, 3] + + class JSONEncoderTests(TestCase): """ Tests the JSONEncoder method @@ -22,7 +28,7 @@ class JSONEncoderTests(TestCase): Tests encoding a decimal """ d = Decimal(3.14) - assert d == float(d) + assert self.encoder.default(d) == float(d) def test_encode_datetime(self): """ @@ -30,6 +36,8 @@ class JSONEncoderTests(TestCase): """ current_time = datetime.now() assert self.encoder.default(current_time) == current_time.isoformat() + current_time_utc = current_time.replace(tzinfo=utc) + assert self.encoder.default(current_time_utc) == current_time.isoformat() + 'Z' def test_encode_time(self): """ @@ -42,22 +50,8 @@ class JSONEncoderTests(TestCase): """ Tests encoding a timezone aware timestamp """ - - class UTC(tzinfo): - """ - Class extending tzinfo to mimic UTC time - """ - def utcoffset(self, dt): - return timedelta(0) - - def tzname(self, dt): - return "UTC" - - def dst(self, dt): - return timedelta(0) - current_time = datetime.now().time() - current_time = current_time.replace(tzinfo=UTC()) + current_time = current_time.replace(tzinfo=utc) with pytest.raises(ValueError): self.encoder.default(current_time) @@ -91,3 +85,10 @@ class JSONEncoderTests(TestCase): with pytest.raises(RuntimeError): self.encoder.default(coreapi.Error()) + + def test_encode_object_with_tolist(self): + """ + Tests encoding a object with tolist method + """ + foo = MockList() + assert self.encoder.default(foo) == [1, 2, 3] From 963cb4cdc6a814d2d62480f4e2a3b94db44cdce3 Mon Sep 17 00:00:00 2001 From: Akhil Lawrence Date: Sat, 18 Feb 2017 13:20:03 +0530 Subject: [PATCH 06/15] Corrected documentation --- docs/api-guide/serializers.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index e157845a9..75d429eb4 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -1100,8 +1100,6 @@ This API included the `.get_field()`, `.get_pk_field()` and other methods. Because the serializers have been fundamentally redesigned with 3.0 this API no longer exists. You can still modify the fields that get created but you'll need to refer to the source code, and be aware that if the changes you make are against private bits of API then they may be subject to change. -A new interface for controlling this behavior is currently planned for REST framework 3.1. - --- # Third party packages From 289e1e440ef6b18ffcfbc74823d69af61ea97529 Mon Sep 17 00:00:00 2001 From: Isaac Stone Date: Sun, 19 Feb 2017 13:00:41 -0800 Subject: [PATCH 07/15] Check for collection.Mapping instead of dict issue #4901 --- rest_framework/serializers.py | 8 ++++---- tests/test_serializer.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index a8f6e9df2..80e384c22 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -15,7 +15,7 @@ from __future__ import unicode_literals import copy import inspect import traceback -from collections import OrderedDict +from collections import Mapping, OrderedDict from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ImproperlyConfigured @@ -326,11 +326,11 @@ def as_serializer_error(exc): else: detail = exc.detail - if isinstance(detail, dict): + if isinstance(detail, Mapping): # If errors may be a dict we use the standard {key: list of values}. # Here we ensure that all the values are *lists* of errors. return { - key: value if isinstance(value, (list, dict)) else [value] + key: value if isinstance(value, (list, Mapping)) else [value] for key, value in detail.items() } elif isinstance(detail, list): @@ -442,7 +442,7 @@ class Serializer(BaseSerializer): """ Dict of native values <- Dict of primitive datatypes. """ - if not isinstance(data, dict): + if not isinstance(data, Mapping): message = self.error_messages['invalid'].format( datatype=type(data).__name__ ) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 04fa39c0d..cd82ba3df 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -4,9 +4,10 @@ from __future__ import unicode_literals import inspect import pickle import re +import unittest +from collections import Mapping import pytest - from django.db import models from rest_framework import fields, relations, serializers @@ -15,6 +16,11 @@ from rest_framework.fields import Field from .utils import MockObject +try: + from collections import ChainMap +except ImportError: + ChainMap = False + # Test serializer fields imports. # ------------------------------- @@ -113,6 +119,31 @@ class TestSerializer: assert not serializer.is_valid() assert serializer.errors == {'non_field_errors': ['No data provided']} + @unittest.skipUnless(ChainMap, 'requires python 3.3') + def test_serialize_chainmap(self): + data = ChainMap({'char': 'abc'}, {'integer': 123}) + serializer = self.Serializer(data=data) + assert serializer.is_valid() + assert serializer.validated_data == {'char': 'abc', 'integer': 123} + assert serializer.errors == {} + + def test_serialize_custom_mapping(self): + class SinglePurposeMapping(Mapping): + def __getitem__(self, key): + return 'abc' if key == 'char' else 123 + + def __iter__(self): + yield 'char' + yield 'integer' + + def __len__(self): + return 2 + + serializer = self.Serializer(data=SinglePurposeMapping()) + assert serializer.is_valid() + assert serializer.validated_data == {'char': 'abc', 'integer': 123} + assert serializer.errors == {} + class TestValidateMethod: def test_non_field_error_validate_method(self): From eacb93d453db25df11c873b50743910101e383cb Mon Sep 17 00:00:00 2001 From: Pavlin Gergov Date: Mon, 20 Feb 2017 11:33:54 +0200 Subject: [PATCH 08/15] Update _not_authenticated's docstring (#4906) --- rest_framework/request.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rest_framework/request.py b/rest_framework/request.py index b4bd2d020..9428708ed 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -353,10 +353,9 @@ class Request(object): def _not_authenticated(self): """ - Return a three-tuple of (authenticator, user, authtoken), representing - an unauthenticated request. + Set authenticator, user & authtoken representing an unauthenticated request. - By default this will be (None, AnonymousUser, None). + Defaults are None, AnonymousUser & None. """ self._authenticator = None From 5986f95c8dd1c9b9172ffa121564cfbee869c532 Mon Sep 17 00:00:00 2001 From: Lanrik Date: Mon, 20 Feb 2017 13:48:19 +0400 Subject: [PATCH 09/15] Rearrange code (#4908) Minor refactor. Move assignment to after `None` check. --- rest_framework/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index f46edef1e..2efe89610 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1446,11 +1446,11 @@ class FileField(Field): return data def to_representation(self, value): - use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL) - if not value: return None + use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL) + if use_url: if not getattr(value, 'url', None): # If the file has not been saved it may not have a URL. From d390762e18484bb82951db4f0ffd7c65dae7a71d Mon Sep 17 00:00:00 2001 From: Vadim Date: Mon, 20 Feb 2017 22:16:27 +0700 Subject: [PATCH 10/15] Add drf-writable-nested package to third-party serializers (#4913) --- docs/api-guide/serializers.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 75d429eb4..a3f7fdcc1 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -1157,6 +1157,9 @@ The [html-json-forms][html-json-forms] package provides an algorithm and seriali [djangorestframework-queryfields][djangorestframework-queryfields] allows API clients to specify which fields will be sent in the response via inclusion/exclusion query parameters. +## DRF Writable Nested + +The [drf-writable-nested][drf-writable-nested] package provides writable nested model serializer which allows to create/update models with nested related data. [cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion [relations]: relations.md @@ -1177,3 +1180,4 @@ The [html-json-forms][html-json-forms] package provides an algorithm and seriali [drf-base64]: https://bitbucket.org/levit_scs/drf_base64 [drf-serializer-extensions]: https://github.com/evenicoulddoit/django-rest-framework-serializer-extensions [djangorestframework-queryfields]: http://djangorestframework-queryfields.readthedocs.io/ +[drf-writable-nested]: http://github.com/Brogency/drf-writable-nested From 1a493185228ad24a1f938b8414df7f6a7913873f Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Tue, 21 Feb 2017 10:31:05 +0600 Subject: [PATCH 11/15] added django 1.11 beta 1 for testing --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index abe045e15..b1be1a83c 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,7 @@ deps = django18: Django>=1.8,<1.9 django19: Django>=1.9,<1.10 django110: Django>=1.10,<1.11 - django111: Django>=1.11a1,<2.0 + django111: Django>=1.11b1,<2.0 djangomaster: https://github.com/django/django/archive/master.tar.gz -rrequirements/requirements-testing.txt -rrequirements/requirements-optionals.txt From d82dbc09257a521e8d912880855e5758c758dafb Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 21 Feb 2017 21:18:53 +0000 Subject: [PATCH 12/15] Add MicroPyramid --- README.md | 3 ++- docs/img/premium/micropyramid-readme.png | Bin 0 -> 23782 bytes docs/index.md | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 docs/img/premium/micropyramid-readme.png diff --git a/README.md b/README.md index 609f99184..7d11aa081 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,10 @@ The initial aim is to provide a single full-time position on REST framework. +

-*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [Machinalis](https://hello.machinalis.co.uk/), and [Rollbar](https://rollbar.com).* +*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [Machinalis](https://hello.machinalis.co.uk/), [Rollbar](https://rollbar.com), and [MicroPyramid](https://micropyramid.com/django-rest-framework-development-services/).* --- diff --git a/docs/img/premium/micropyramid-readme.png b/docs/img/premium/micropyramid-readme.png new file mode 100644 index 0000000000000000000000000000000000000000..9fa9500e14b2a9c215a112ef7ddb1f4f377538db GIT binary patch literal 23782 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

0VM1Hnz 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 literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index 1760ce916..aada80737 100644 --- a/docs/index.md +++ b/docs/index.md @@ -76,10 +76,11 @@ The initial aim is to provide a single full-time position on REST framework.

  • Stream
  • Machinalis
  • Rollbar
  • +
  • MicroPyramid
  • -*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [Machinalis](https://hello.machinalis.co.uk/), and [Rollbar](https://rollbar.com).* +*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Rover](http://jobs.rover.com/), [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [Machinalis](https://hello.machinalis.co.uk/), [Rollbar](https://rollbar.com), and [MicroPyramid](https://micropyramid.com/django-rest-framework-development-services/).* --- From 7a408f6cd2b67fd9c4f0d3a2240dec20d2a87a7b Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Wed, 22 Feb 2017 13:06:48 +0200 Subject: [PATCH 13/15] Guard against the possible misspelling `readonly_fields` in model serializers Fixes #4897. --- rest_framework/serializers.py | 9 +++++++++ tests/test_model_serializer.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 80e384c22..94c37321f 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -1290,6 +1290,15 @@ class ModelSerializer(Serializer): kwargs['read_only'] = True extra_kwargs[field_name] = kwargs + else: + # Guard against the possible misspelling `readonly_fields` (used + # by the Django admin and others). + assert not hasattr(self.Meta, 'readonly_fields'), ( + 'Serializer `%s.%s` has field `readonly_fields`; ' + 'the correct spelling for the option is `read_only_fields`.' % + (self.__class__.__module__, self.__class__.__name__) + ) + return extra_kwargs def get_uniqueness_extra_kwargs(self, field_names, declared_fields, extra_kwargs): diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index b839f56ca..cfa671125 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -10,6 +10,7 @@ from __future__ import unicode_literals import decimal from collections import OrderedDict +import pytest from django.core.exceptions import ImproperlyConfigured from django.core.validators import ( MaxValueValidator, MinLengthValidator, MinValueValidator @@ -1064,3 +1065,18 @@ class Issue3674Test(TestCase): child_expected = {'parent': 1, 'value': 'def'} self.assertEqual(child_serializer.data, child_expected) + + +class Issue4897TestCase(TestCase): + def test_should_assert_if_writing_readonly_fields(self): + class TestSerializer(serializers.ModelSerializer): + class Meta: + model = OneFieldModel + fields = ('char_field',) + readonly_fields = fields + + obj = OneFieldModel.objects.create(char_field='abc') + + with pytest.raises(AssertionError) as cm: + TestSerializer(obj).fields + cm.match(r'readonly_fields') From e922d916146701808c663844ed0c695279d8b508 Mon Sep 17 00:00:00 2001 From: Anna Ossowski Date: Fri, 24 Feb 2017 13:55:34 +0100 Subject: [PATCH 14/15] Created Tutorials and Resources, cleaned up Third Party Packages (#4910) * Updated Support section and added funding email * Created new tutorials and resources section, cleaned up third party packages section * Created Jobs section --- LICENSE.md | 2 +- docs/index.md | 8 +- docs/topics/jobs.md | 38 ++++++ ...y-resources.md => third-party-packages.md} | 48 +------- docs/topics/tutorials-and-resources.md | 109 ++++++++++++++++++ mkdocs.yml | 4 +- 6 files changed, 160 insertions(+), 49 deletions(-) create mode 100644 docs/topics/jobs.md rename docs/topics/{third-party-resources.md => third-party-packages.md} (85%) create mode 100644 docs/topics/tutorials-and-resources.md diff --git a/LICENSE.md b/LICENSE.md index aca195ec4..4c599a394 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # License -Copyright (c) 2011-2016, Tom Christie +Copyright (c) 2011-2017, Tom Christie All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/docs/index.md b/docs/index.md index aada80737..4abfba587 100644 --- a/docs/index.md +++ b/docs/index.md @@ -238,7 +238,8 @@ General guides to using REST framework. * [Browser enhancements][browser-enhancements] * [The Browsable API][browsableapi] * [REST, Hypermedia & HATEOAS][rest-hypermedia-hateoas] -* [Third Party Resources][third-party-resources] +* [Third Party Packages][third-party-packages] +* [Tutorials and Resources][tutorials-and-resources] * [Contributing to REST framework][contributing] * [Project management][project-management] * [3.0 Announcement][3.0-announcement] @@ -251,6 +252,7 @@ General guides to using REST framework. * [Mozilla Grant][mozilla-grant] * [Funding][funding] * [Release Notes][release-notes] +* [Jobs][jobs] ## Development @@ -367,7 +369,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [rest-hypermedia-hateoas]: topics/rest-hypermedia-hateoas.md [contributing]: topics/contributing.md [project-management]: topics/project-management.md -[third-party-resources]: topics/third-party-resources.md +[third-party-packages]: topics/third-party-packages.md +[tutorials-and-resources]: topics/tutorials-and-resources.md [3.0-announcement]: topics/3.0-announcement.md [3.1-announcement]: topics/3.1-announcement.md [3.2-announcement]: topics/3.2-announcement.md @@ -378,6 +381,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [mozilla-grant]: topics/mozilla-grant.md [funding]: topics/funding.md [release-notes]: topics/release-notes.md +[jobs]: topics/jobs.md [tox]: http://testrun.org/tox/latest/ diff --git a/docs/topics/jobs.md b/docs/topics/jobs.md new file mode 100644 index 000000000..9c5e95c59 --- /dev/null +++ b/docs/topics/jobs.md @@ -0,0 +1,38 @@ +# Jobs + +Looking for a new Django REST Framework related role? On this site we provide a list of job resources that may be helpful. It's also worth checking out if any of [our sponsors are hiring][drf-funding]. + + +## Places to Look for Django REST Framework Jobs + +* [https://www.djangoproject.com/community/jobs/][djangoproject-website] +* [https://www.python.org/jobs/][python-org-jobs] +* [https://djangogigs.com][django-gigs-com] +* [https://djangojobs.net/jobs/][django-jobs-net] +* [http://djangojobbers.com][django-jobbers-com] +* [https://www.indeed.com/q-Django-jobs.html][indeed-com] +* [http://stackoverflow.com/jobs/developer-jobs-using-django][stackoverflow-com] +* [https://www.upwork.com/o/jobs/browse/skill/django-framework/][upwork-com] +* [https://www.technojobs.co.uk/django-jobs][technobjobs-co-uk] +* [https://remoteok.io/remote-django-jobs][remoteok-io] +* [https://www.remotepython.com/jobs/][remotepython-com] + + +Know of any other great resources for Django REST Framework jobs that are missing in our list? Please [submit a pull request][submit-pr] or [email us][mailto:anna@django-rest-framework.org]. + +Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for [REST Framework sponsorship][drf-funding] yet. + + +[djangoproject-website]: https://www.djangoproject.com/community/jobs/ +[python-org-jobs]: https://www.python.org/jobs/ +[django-gigs-com]: https://djangogigs.com +[django-jobs-net]: https://djangojobs.net/jobs/ +[django-jobbers-com]: http://djangojobbers.com +[indeed-com]: https://www.indeed.com/q-Django-jobs.html +[stackoverflow-com]: http://stackoverflow.com/jobs/developer-jobs-using-django +[upwork-com]: https://www.upwork.com/o/jobs/browse/skill/django-framework/ +[technobjobs-co-uk]: https://www.technojobs.co.uk/django-jobs +[remoteok-io]: https://remoteok.io/remote-django-jobs +[remotepython-com]: https://www.remotepython.com/jobs/ +[drf-funding]: https://fund.django-rest-framework.org/topics/funding/ +[submit-pr]: https://github.com/tomchristie/django-rest-framework diff --git a/docs/topics/third-party-resources.md b/docs/topics/third-party-packages.md similarity index 85% rename from docs/topics/third-party-resources.md rename to docs/topics/third-party-packages.md index 1ccedbc01..d092e163e 100644 --- a/docs/topics/third-party-resources.md +++ b/docs/topics/third-party-packages.md @@ -1,4 +1,4 @@ -# Third Party Resources +# Third Party Packages > Software ecosystems […] establish a community that further accelerates the sharing of knowledge, content, issues, expertise and skills. > @@ -165,7 +165,7 @@ We suggest adding your package to the [REST Framework][rest-framework-grid] grid #### Adding to the Django REST framework docs -Create a [Pull Request][drf-create-pr] or [Issue][drf-create-issue] on GitHub, and we'll add a link to it from the main REST framework documentation. You can add your package under **Third party packages** of the API Guide section that best applies, like [Authentication][authentication] or [Permissions][permissions]. You can also link your package under the [Third Party Resources][third-party-resources] section. +Create a [Pull Request][drf-create-pr] or [Issue][drf-create-issue] on GitHub, and we'll add a link to it from the main REST framework documentation. You can add your package under **Third party packages** of the API Guide section that best applies, like [Authentication][authentication] or [Permissions][permissions]. You can also link your package under the [Third Party Packages][third-party-packages] section. #### Announce on the discussion group. @@ -261,33 +261,6 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque * [django-rest-framework-version-transforms][django-rest-framework-version-transforms] - Enables the use of delta transformations for versioning of DRF resource representations. * [django-rest-messaging][django-rest-messaging], [django-rest-messaging-centrifugo][django-rest-messaging-centrifugo] and [django-rest-messaging-js][django-rest-messaging-js] - A real-time pluggable messaging service using DRM. -## Other Resources - -### Tutorials - -* [Beginner's Guide to the Django Rest Framework][beginners-guide-to-the-django-rest-framework] -* [Getting Started with Django Rest Framework and AngularJS][getting-started-with-django-rest-framework-and-angularjs] -* [End to end web app with Django-Rest-Framework & AngularJS][end-to-end-web-app-with-django-rest-framework-angularjs] -* [Start Your API - django-rest-framework part 1][start-your-api-django-rest-framework-part-1] -* [Permissions & Authentication - django-rest-framework part 2][permissions-authentication-django-rest-framework-part-2] -* [ViewSets and Routers - django-rest-framework part 3][viewsets-and-routers-django-rest-framework-part-3] -* [Django Rest Framework User Endpoint][django-rest-framework-user-endpoint] -* [Check credentials using Django Rest Framework][check-credentials-using-django-rest-framework] -* [Django REST Framework course][django-rest-framework-course] - -### Videos - -* [Ember and Django Part 1 (Video)][ember-and-django-part 1-video] -* [Django Rest Framework Part 1 (Video)][django-rest-framework-part-1-video] - -### Articles - -* [Web API performance: profiling Django REST framework][web-api-performance-profiling-django-rest-framework] -* [API Development with Django and Django REST Framework][api-development-with-django-and-django-rest-framework] -* [Blog posts about Django REST framework][medium-django-rest-framework] - -### Documentations -* [Classy Django REST Framework][cdrf.co] [cite]: http://www.software-ecosystems.com/Software_Ecosystems/Ecosystems.html [cookiecutter]: https://github.com/jpadilla/cookiecutter-django-rest-framework @@ -304,7 +277,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [drf-create-issue]: https://github.com/tomchristie/django-rest-framework/issues/new [authentication]: ../api-guide/authentication.md [permissions]: ../api-guide/permissions.md -[third-party-resources]: ../topics/third-party-resources/#existing-third-party-packages +[third-party-packages]: ../topics/third-party-packages/#existing-third-party-packages [discussion-group]: https://groups.google.com/forum/#!forum/django-rest-framework [djangorestframework-digestauth]: https://github.com/juanriaza/django-rest-framework-digestauth [django-oauth-toolkit]: https://github.com/evonove/django-oauth-toolkit @@ -337,22 +310,9 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [gaiarestframework]: https://github.com/AppsFuel/gaiarestframework [drf-extensions]: https://github.com/chibisov/drf-extensions [ember-django-adapter]: https://github.com/dustinfarris/ember-django-adapter -[beginners-guide-to-the-django-rest-framework]: http://code.tutsplus.com/tutorials/beginners-guide-to-the-django-rest-framework--cms-19786 -[getting-started-with-django-rest-framework-and-angularjs]: http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html -[end-to-end-web-app-with-django-rest-framework-angularjs]: http://mourafiq.com/2013/07/01/end-to-end-web-app-with-django-angular-1.html -[start-your-api-django-rest-framework-part-1]: https://godjango.com/41-start-your-api-django-rest-framework-part-1/ -[permissions-authentication-django-rest-framework-part-2]: https://godjango.com/43-permissions-authentication-django-rest-framework-part-2/ -[viewsets-and-routers-django-rest-framework-part-3]: https://godjango.com/45-viewsets-and-routers-django-rest-framework-part-3/ -[django-rest-framework-user-endpoint]: http://richardtier.com/2014/02/25/django-rest-framework-user-endpoint/ -[check-credentials-using-django-rest-framework]: http://richardtier.com/2014/03/06/110/ -[ember-and-django-part 1-video]: http://www.neckbeardrepublic.com/screencasts/ember-and-django-part-1 -[django-rest-framework-part-1-video]: http://www.neckbeardrepublic.com/screencasts/django-rest-framework-part-1 -[web-api-performance-profiling-django-rest-framework]: http://dabapps.com/blog/api-performance-profiling-django-rest-framework/ -[api-development-with-django-and-django-rest-framework]: https://bnotions.com/api-development-with-django-and-django-rest-framework/ [django-rest-auth]: https://github.com/Tivix/django-rest-auth/ [django-versatileimagefield]: https://github.com/WGBH/django-versatileimagefield [django-versatileimagefield-drf-docs]:https://django-versatileimagefield.readthedocs.io/en/latest/drf_integration.html -[cdrf.co]:http://www.cdrf.co [drf-tracking]: https://github.com/aschn/drf-tracking [django-rest-framework-braces]: https://github.com/dealertrack/django-rest-framework-braces [dry-rest-permissions]: https://github.com/Helioscene/dry-rest-permissions @@ -366,8 +326,6 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [django-rest-messaging]: https://github.com/raphaelgyory/django-rest-messaging [django-rest-messaging-centrifugo]: https://github.com/raphaelgyory/django-rest-messaging-centrifugo [django-rest-messaging-js]: https://github.com/raphaelgyory/django-rest-messaging-js -[medium-django-rest-framework]: https://medium.com/django-rest-framework -[django-rest-framework-course]: https://teamtreehouse.com/library/django-rest-framework [drf_tweaks]: https://github.com/ArabellaTech/drf_tweaks [drf-oidc-auth]: https://github.com/ByteInternet/drf-oidc-auth [drf-serializer-extensions]: https://github.com/evenicoulddoit/django-rest-framework-serializer-extensions diff --git a/docs/topics/tutorials-and-resources.md b/docs/topics/tutorials-and-resources.md new file mode 100644 index 000000000..3bbe52e44 --- /dev/null +++ b/docs/topics/tutorials-and-resources.md @@ -0,0 +1,109 @@ +# Tutorials and Resources + +There are a wide range of resources available for learning and using Django REST framework. We try to keep a comprehensive list available here. + +## Tutorials + +* [Beginner's Guide to the Django REST Framework][beginners-guide-to-the-django-rest-framework] +* [Django REST Framework - An Introduction][drf-an-intro] +* [Django REST Framework Tutorial][drf-tutorial] +* [Django REST Framework Course][django-rest-framework-course] +* [Building a RESTful API with Django REST Framework][building-a-restful-api-with-drf] +* [Getting Started with Django REST Framework and AngularJS][getting-started-with-django-rest-framework-and-angularjs] +* [End to End Web App with Django REST Framework & AngularJS][end-to-end-web-app-with-django-rest-framework-angularjs] +* [Start Your API - Django REST Framework Part 1][start-your-api-django-rest-framework-part-1] +* [Permissions & Authentication - Django REST Framework Part 2][permissions-authentication-django-rest-framework-part-2] +* [ViewSets and Routers - Django REST Framework Part 3][viewsets-and-routers-django-rest-framework-part-3] +* [Django REST Framework User Endpoint][django-rest-framework-user-endpoint] +* [Check Credentials Using Django REST Framework][check-credentials-using-django-rest-framework] +* [Creating a Production Ready API with Python and Django REST Framework – Part 1][creating-a-production-ready-api-with-python-and-drf-part1] +* [Creating a Production Ready API with Python and Django REST Framework – Part 2][creating-a-production-ready-api-with-python-and-drf-part2] + + +## Videos + +### Talks + +* [How to Make a Full Fledged REST API with Django OAuth Toolkit][full-fledged-rest-api-with-django-oauth-tookit] +* [Django REST API - So Easy You Can Learn It in 25 Minutes][django-rest-api-so-easy] +* [Tom Christie about Django Rest Framework at Django: Under The Hood][django-under-hood-2014] +* [Django REST Framework: Schemas, Hypermedia & Client Libraries][pycon-uk-2016] + + +### Tutorials + + +* [Django REST Framework Part 1][django-rest-framework-part-1-video] +* [Django REST Framework in Your PJ's!][drf-in-your-pjs] +* [Building a REST API Using Django & Django REST Framework][building-a-rest-api-using-django-and-drf] +* [Blog API with Django REST Framework][blog-api-with-drf] +* [Ember and Django Part 1][ember-and-django-part 1-video] +* [Django REST Framework Image Upload Tutorial (with AngularJS)][drf-image-upload-tutorial-with-angularjs] +* [Django REST Framework Tutorials][drf-tutorials] + + +## Articles + +* [Web API performance: Profiling Django REST Framework][web-api-performance-profiling-django-rest-framework] +* [API Development with Django and Django REST Framework][api-development-with-django-and-django-rest-framework] +* [Integrating Pandas, Django REST Framework and Bokeh][integrating-pandas-drf-and-bokeh] +* [Controlling Uncertainty on Web Applications and APIs][controlling-uncertainty-on-web-apps-and-apis] +* [Full Text Search in Django REST Framework with Database Backends][full-text-search-in-drf] +* [OAuth2 Authentication with Django REST Framework and Custom Third-Party OAuth2 Backends][oauth2-authentication-with-drf] +* [Nested Resources with Django REST Framework][nested-resources-with-drf] +* [Image Fields with Django REST Framework][image-fields-with-drf] +* [Chatbot Using Django REST Framework + api.ai + Slack — Part 1/3][chatbot-using-drf-part1] +* [New Django Admin with DRF and EmberJS... What are the News?][new-django-admin-with-drf-and-emberjs] +* [Blog posts about Django REST Framework][medium-django-rest-framework] + +## Books + +* [Hello Web App: Intermediate Concepts, Chapter 10][hello-web-app-intermediate] + +### Documentations +* [Classy Django REST Framework][cdrf.co] +* [DRF-schema-adapter][drf-schema] + +Want your Django REST Framework talk/tutorial/article to be added to our website? Or know of a resource that's not yet included here? Please [submit a pull request][submit-pr] or [email us][mailto:anna@django-rest-framework.org]! + + +[beginners-guide-to-the-django-rest-framework]: http://code.tutsplus.com/tutorials/beginners-guide-to-the-django-rest-framework--cms-19786 +[getting-started-with-django-rest-framework-and-angularjs]: http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html +[end-to-end-web-app-with-django-rest-framework-angularjs]: http://mourafiq.com/2013/07/01/end-to-end-web-app-with-django-angular-1.html +[start-your-api-django-rest-framework-part-1]: https://godjango.com/41-start-your-api-django-rest-framework-part-1/ +[permissions-authentication-django-rest-framework-part-2]: https://godjango.com/43-permissions-authentication-django-rest-framework-part-2/ +[viewsets-and-routers-django-rest-framework-part-3]: https://godjango.com/45-viewsets-and-routers-django-rest-framework-part-3/ +[django-rest-framework-user-endpoint]: http://richardtier.com/2014/02/25/django-rest-framework-user-endpoint/ +[check-credentials-using-django-rest-framework]: http://richardtier.com/2014/03/06/110/ +[ember-and-django-part 1-video]: http://www.neckbeardrepublic.com/screencasts/ember-and-django-part-1 +[django-rest-framework-part-1-video]: http://www.neckbeardrepublic.com/screencasts/django-rest-framework-part-1 +[web-api-performance-profiling-django-rest-framework]: http://dabapps.com/blog/api-performance-profiling-django-rest-framework/ +[api-development-with-django-and-django-rest-framework]: https://bnotions.com/api-development-with-django-and-django-rest-framework/ +[cdrf.co]:http://www.cdrf.co +[medium-django-rest-framework]: https://medium.com/django-rest-framework +[django-rest-framework-course]: https://teamtreehouse.com/library/django-rest-framework +[pycon-uk-2016]: https://www.youtube.com/watch?v=FjmiGh7OqVg +[django-under-hood-2014]: https://www.youtube.com/watch?v=3cSsbe-tA0E +[integrating-pandas-drf-and-bokeh]: http://machinalis.com/blog/pandas-django-rest-framework-bokeh/ +[controlling-uncertainty-on-web-apps-and-apis]: http://machinalis.com/blog/controlling-uncertainty-on-web-applications-and-apis/ +[full-text-search-in-drf]: http://machinalis.com/blog/full-text-search-on-django-rest-framework/ +[oauth2-authentication-with-drf]: http://machinalis.com/blog/oauth2-authentication/ +[nested-resources-with-drf]: http://machinalis.com/blog/nested-resources-with-django/ +[image-fields-with-drf]: http://machinalis.com/blog/image-fields-with-django-rest-framework/ +[chatbot-using-drf-part1]: https://chatbotslife.com/chatbot-using-django-rest-framework-api-ai-slack-part-1-3-69c7e38b7b1e#.g2aceuncf +[new-django-admin-with-drf-and-emberjs]: https://blog.levit.be/new-django-admin-with-emberjs-what-are-the-news/ +[drf-schema]: http://drf-schema-adapter.readthedocs.io/en/latest/ +[creating-a-production-ready-api-with-python-and-drf-part1]: https://www.andreagrandi.it/2016/09/28/creating-production-ready-api-python-django-rest-framework-part-1/ +[creating-a-production-ready-api-with-python-and-drf-part2]: https://www.andreagrandi.it/2016/10/01/creating-a-production-ready-api-with-python-and-django-rest-framework-part-2/ +[hello-web-app-intermediate]: https://hellowebapp.com/order/ +[django-rest-api-so-easy]: https://www.youtube.com/watch?v=cqP758k1BaQ +[full-fledged-rest-api-with-django-oauth-tookit]: https://www.youtube.com/watch?v=M6Ud3qC2tTk +[drf-in-your-pjs]: https://www.youtube.com/watch?v=xMtHsWa72Ww +[building-a-rest-api-using-django-and-drf]: https://www.youtube.com/watch?v=PwssEec3IRw +[drf-tutorials]: https://www.youtube.com/watch?v=axRCBgbOJp8&list=PLJtp8Jm8EDzjgVg9vVyIUMoGyqtegj7FH +[drf-image-upload-tutorial-with-angularjs]: https://www.youtube.com/watch?v=hMiNTCIY7dw&list=PLUe5s-xycYk_X0vDjYBmKuIya2a2myF8O +[blog-api-with-drf]: https://www.youtube.com/watch?v=XMu0T6L2KRQ&list=PLEsfXFp6DpzTOcOVdZF-th7BS_GYGguAS +[drf-an-intro]: https://realpython.com/blog/python/django-rest-framework-quick-start/ +[drf-tutorial]: https://tests4geeks.com/django-rest-framework-tutorial/ +[building-a-restful-api-with-drf]: http://agiliq.com/blog/2014/12/building-a-restful-api-with-django-rest-framework/ +[submit-pr]: https://github.com/tomchristie/django-rest-framework diff --git a/mkdocs.yml b/mkdocs.yml index 01c59caaa..6c57618ae 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -58,7 +58,8 @@ pages: - 'Browser Enhancements': 'topics/browser-enhancements.md' - 'The Browsable API': 'topics/browsable-api.md' - 'REST, Hypermedia & HATEOAS': 'topics/rest-hypermedia-hateoas.md' - - 'Third Party Resources': 'topics/third-party-resources.md' + - 'Third Party Packages': 'topics/third-party-packages.md' + - 'Tutorials and Resources': 'topics/tutorials-and-resources.md' - 'Contributing to REST framework': 'topics/contributing.md' - 'Project management': 'topics/project-management.md' - '3.0 Announcement': 'topics/3.0-announcement.md' @@ -71,3 +72,4 @@ pages: - 'Mozilla Grant': 'topics/mozilla-grant.md' - 'Funding': 'topics/funding.md' - 'Release Notes': 'topics/release-notes.md' + - 'Jobs': 'topics/jobs.md' From b936d829a6b77fe344d2021ae41e89dd66eba4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Padilla?= Date: Sun, 26 Feb 2017 04:08:03 -0500 Subject: [PATCH 15/15] Fix mailto link (#4923) --- docs/topics/jobs.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/topics/jobs.md b/docs/topics/jobs.md index 9c5e95c59..9c67483a8 100644 --- a/docs/topics/jobs.md +++ b/docs/topics/jobs.md @@ -18,7 +18,7 @@ Looking for a new Django REST Framework related role? On this site we provide a * [https://www.remotepython.com/jobs/][remotepython-com] -Know of any other great resources for Django REST Framework jobs that are missing in our list? Please [submit a pull request][submit-pr] or [email us][mailto:anna@django-rest-framework.org]. +Know of any other great resources for Django REST Framework jobs that are missing in our list? Please [submit a pull request][submit-pr] or [email us][anna-email]. Wonder how else you can help? One of the best ways you can help Django REST Framework is to ask interviewers if their company is signed up for [REST Framework sponsorship][drf-funding] yet. @@ -36,3 +36,4 @@ Wonder how else you can help? One of the best ways you can help Django REST Fram [remotepython-com]: https://www.remotepython.com/jobs/ [drf-funding]: https://fund.django-rest-framework.org/topics/funding/ [submit-pr]: https://github.com/tomchristie/django-rest-framework +[anna-email]: mailto:anna@django-rest-framework.org