diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/api-guide/authentication.md | 24 | ||||
| -rw-r--r-- | docs/api-guide/fields.md | 14 | ||||
| -rw-r--r-- | docs/api-guide/permissions.md | 9 | ||||
| -rw-r--r-- | docs/api-guide/relations.md | 2 | ||||
| -rw-r--r-- | docs/api-guide/renderers.md | 5 | ||||
| -rw-r--r-- | docs/api-guide/requests.md | 4 | ||||
| -rw-r--r-- | docs/api-guide/serializers.md | 12 | ||||
| -rw-r--r-- | docs/api-guide/throttling.md | 10 | ||||
| -rw-r--r-- | docs/api-guide/views.md | 2 | ||||
| -rw-r--r-- | docs/index.md | 3 | ||||
| -rw-r--r-- | docs/template.html | 1 | ||||
| -rw-r--r-- | docs/topics/ajax-csrf-cors.md | 41 | ||||
| -rw-r--r-- | docs/topics/credits.md | 10 | ||||
| -rw-r--r-- | docs/topics/csrf.md | 12 | ||||
| -rw-r--r-- | docs/topics/release-notes.md | 16 | ||||
| -rw-r--r-- | docs/tutorial/1-serialization.md | 12 |
16 files changed, 138 insertions, 39 deletions
diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index ac690bdc..59afc2b9 100644 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -177,7 +177,7 @@ If successfully authenticated, `SessionAuthentication` provides the following cr Unauthenticated responses that are denied permission will result in an `HTTP 403 Forbidden` response. -If you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as `PUT`, `POST` or `DELETE` requests. See the [Django CSRF documentation][csrf-ajax] for more details. +If you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as `PUT`, `PATCH`, `POST` or `DELETE` requests. See the [Django CSRF documentation][csrf-ajax] for more details. # Custom authentication @@ -190,9 +190,27 @@ Typically the approach you should take is: * If authentication is not attempted, return `None`. Any other authentication schemes also in use will still be checked. * If authentication is attempted but fails, raise a `AuthenticationFailed` exception. An error response will be returned immediately, without checking any other authentication schemes. -You *may* also override the `.authentication_header(self, request)` method. If implemented, it should return a string that will be used as the value of the `WWW-Authenticate` header in a `HTTP 401 Unauthorized` response. +You *may* also override the `.authenticate_header(self, request)` method. If implemented, it should return a string that will be used as the value of the `WWW-Authenticate` header in a `HTTP 401 Unauthorized` response. -If the `.authentication_header()` method is not overridden, the authentication scheme will return `HTTP 403 Forbidden` responses when an unauthenticated request is denied access. +If the `.authenticate_header()` method is not overridden, the authentication scheme will return `HTTP 403 Forbidden` responses when an unauthenticated request is denied access. + +## Example + +The following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'. + + class ExampleAuthentication(authentication.BaseAuthentication): + def has_permission(self, request, view, obj=None): + username = request.META.get('X_USERNAME') + if not username: + return None + + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + raise authenticate.AuthenticationFailed('No such user') + + return (user, None) + [cite]: http://jacobian.org/writing/rest-worst-practices/ [http401]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2 diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 5bc8f7f7..3f8a36e2 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -193,6 +193,16 @@ A date and time representation. Corresponds to `django.db.models.fields.DateTimeField` +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. + +If you want to override this behavior, you'll need to declare the `DateTimeField` explicitly on the serializer. For example: + + class CommentSerializer(serializers.ModelSerializer): + created = serializers.DateTimeField() + + class Meta: + model = Comment + ## IntegerField An integer representation. @@ -230,7 +240,9 @@ Signature and validation is the same as with `FileField`. --- **Note:** `FileFields` and `ImageFields` are only suitable for use with MultiPartParser, since e.g. json doesn't support file uploads. -Django's regular [FILE_UPLOAD_HANDLERS] are used for handling uploaded files. +Django's regular [FILE_UPLOAD_HANDLERS] are used for handling uploaded files. + +--- [cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data [FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index fce68f6d..1814b811 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -110,6 +110,15 @@ To implement a custom permission, override `BasePermission` and implement the `. The method should return `True` if the request should be granted access, and `False` otherwise. +## Example + +The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted. + + class BlacklistPermission(permissions.BasePermission): + def has_permission(self, request, view, obj=None): + ip_addr = request.META['REMOTE_ADDR'] + blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists() + return not blacklisted [cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html [authentication]: authentication.md diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md index 351b5e09..9f5a04b2 100644 --- a/docs/api-guide/relations.md +++ b/docs/api-guide/relations.md @@ -67,7 +67,7 @@ For example, given the following models: And a model serializer defined like this: class BookmarkSerializer(serializers.ModelSerializer): - tags = serializers.ManyRelatedField(source='tags') + tags = serializers.ManyRelatedField() class Meta: model = Bookmark diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index b4f7ec3d..4c1fdc53 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -80,7 +80,7 @@ Renders the request data into `JSONP`. The `JSONP` media type provides a mechan The javascript callback function must be set by the client including a `callback` URL query parameter. For example `http://example.com/api/users?callback=jsonpCallback`. If the callback function is not explicitly set by the client it will default to `'callback'`. -**Note**: If you require cross-domain AJAX requests, you may also want to consider using [CORS] as an alternative to `JSONP`. +**Note**: If you require cross-domain AJAX requests, you may want to consider using the more modern approach of [CORS][cors] as an alternative to `JSONP`. See the [CORS documentation][cors-docs] for more details. **.media_type**: `application/javascript` @@ -288,7 +288,8 @@ Comma-separated values are a plain-text tabular data format, that can be easily [cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process [conneg]: content-negotiation.md [browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers -[CORS]: http://en.wikipedia.org/wiki/Cross-origin_resource_sharing +[cors]: http://www.w3.org/TR/cors/ +[cors-docs]: ../topics/ajax-csrf-cors.md [HATEOAS]: http://timelessrepo.com/haters-gonna-hateoas [quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven [application/vnd.github+json]: http://developer.github.com/v3/media/ diff --git a/docs/api-guide/requests.md b/docs/api-guide/requests.md index 72932f5d..39a34fcf 100644 --- a/docs/api-guide/requests.md +++ b/docs/api-guide/requests.md @@ -83,13 +83,13 @@ You won't typically need to access this property. # Browser enhancements -REST framework supports a few browser enhancements such as browser-based `PUT` and `DELETE` forms. +REST framework supports a few browser enhancements such as browser-based `PUT`, `PATCH` and `DELETE` forms. ## .method `request.method` returns the **uppercased** string representation of the request's HTTP method. -Browser-based `PUT` and `DELETE` forms are transparently supported. +Browser-based `PUT`, `PATCH` and `DELETE` forms are transparently supported. For more information see the [browser enhancements documentation]. diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index d98a602f..487502e9 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -190,18 +190,12 @@ By default field values are treated as mapping to an attribute on the object. I As an example, let's create a field that can be used represent the class name of the object being serialized: - class ClassNameField(serializers.WritableField): + class ClassNameField(serializers.Field): def field_to_native(self, obj, field_name): """ - Serialize the object's class name, not an attribute of the object. + Serialize the object's class name. """ - return obj.__class__.__name__ - - def field_from_native(self, data, field_name, into): - """ - We don't want to set anything when we revert this field. - """ - pass + return obj.__class__ --- diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md index b03bc9e0..923593bc 100644 --- a/docs/api-guide/throttling.md +++ b/docs/api-guide/throttling.md @@ -150,8 +150,16 @@ User requests to either `ContactListView` or `ContactDetailView` would be restri # Custom throttles -To create a custom throttle, override `BaseThrottle` and implement `.allow_request(request, view)`. The method should return `True` if the request should be allowed, and `False` otherwise. +To create a custom throttle, override `BaseThrottle` and implement `.allow_request(self, request, view)`. The method should return `True` if the request should be allowed, and `False` otherwise. Optionally you may also override the `.wait()` method. If implemented, `.wait()` should return a recommended number of seconds to wait before attempting the next request, or `None`. The `.wait()` method will only be called if `.allow_request()` has previously returned `False`. +## Example + +The following is an example of a rate throttle, that will randomly throttle 1 in every 10 requests. + + class RandomRateThrottle(throttles.BaseThrottle): + def allow_request(self, request, view): + return random.randint(1, 10) == 1 + [permissions]: permissions.md diff --git a/docs/api-guide/views.md b/docs/api-guide/views.md index d1e42ec1..574020f9 100644 --- a/docs/api-guide/views.md +++ b/docs/api-guide/views.md @@ -85,7 +85,7 @@ The following methods are called before dispatching to the handler method. ## Dispatch methods The following methods are called directly by the view's `.dispatch()` method. -These perform any actions that need to occur before or after calling the handler methods such as `.get()`, `.post()`, `put()` and `.delete()`. +These perform any actions that need to occur before or after calling the handler methods such as `.get()`, `.post()`, `put()`, `patch()` and `.delete()`. ### .initial(self, request, \*args, **kwargs) diff --git a/docs/index.md b/docs/index.md index 05c68b25..453a67b8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -117,6 +117,7 @@ The API guide is your complete reference manual to all the functionality provide General guides to using REST framework. +* [AJAX, CSRF & CORS][ajax-csrf-cors] * [Browser enhancements][browser-enhancements] * [The Browsable API][browsableapi] * [REST, Hypermedia & HATEOAS][rest-hypermedia-hateoas] @@ -210,7 +211,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [status]: api-guide/status-codes.md [settings]: api-guide/settings.md -[csrf]: topics/csrf.md +[ajax-csrf-cors]: topics/ajax-csrf-cors.md [browser-enhancements]: topics/browser-enhancements.md [browsableapi]: topics/browsable-api.md [rest-hypermedia-hateoas]: topics/rest-hypermedia-hateoas.md diff --git a/docs/template.html b/docs/template.html index d789cc58..2a87e92b 100644 --- a/docs/template.html +++ b/docs/template.html @@ -89,6 +89,7 @@ <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a> <ul class="dropdown-menu"> + <li><a href="{{ base_url }}/topics/ajax-csrf-cors{{ suffix }}">AJAX, CSRF & CORS</a></li> <li><a href="{{ base_url }}/topics/browser-enhancements{{ suffix }}">Browser enhancements</a></li> <li><a href="{{ base_url }}/topics/browsable-api{{ suffix }}">The Browsable API</a></li> <li><a href="{{ base_url }}/topics/rest-hypermedia-hateoas{{ suffix }}">REST, Hypermedia & HATEOAS</a></li> diff --git a/docs/topics/ajax-csrf-cors.md b/docs/topics/ajax-csrf-cors.md new file mode 100644 index 00000000..f7d12940 --- /dev/null +++ b/docs/topics/ajax-csrf-cors.md @@ -0,0 +1,41 @@ +# Working with AJAX, CSRF & CORS + +> "Take a close look at possible CSRF / XSRF vulnerabilities on your own websites. They're the worst kind of vulnerability — very easy to exploit by attackers, yet not so intuitively easy to understand for software developers, at least until you've been bitten by one." +> +> — [Jeff Atwood][cite] + +## Javascript clients + +If your building a javascript client to interface with your Web API, you'll need to consider if the client can use the same authentication policy that is used by the rest of the website, and also determine if you need to use CSRF tokens or CORS headers. + +AJAX requests that are made within the same context as the API they are interacting with will typically use `SessionAuthentication`. This ensures that once a user has logged in, any AJAX requests made can be authenticated using the same session-based authentication that is used for the rest of the website. + +AJAX requests that are made on a different site from the API they are communicating with will typically need to use a non-session-based authentication scheme, such as `TokenAuthentication`. + +## CSRF protection + +[Cross Site Request Forgery][csrf] protection is a mechanism of guarding against a particular type of attack, which can occur when a user has not logged out of a web site, and continues to have a valid session. In this circumstance a malicious site may be able to perform actions against the target site, within the context of the logged-in session. + +To guard against these type of attacks, you need to do two things: + +1. Ensure that the 'safe' HTTP operations, such as `GET`, `HEAD` and `OPTIONS` cannot be used to alter any server-side state. +2. Ensure that any 'unsafe' HTTP operations, such as `POST`, `PUT`, `PATCH` and `DELETE`, always require a valid CSRF token. + +If you're using `SessionAuthentication` you'll need to include valid CSRF tokens for any `POST`, `PUT`, `PATCH` or `DELETE` operations. + +The Django documentation describes how to [include CSRF tokens in AJAX requests][csrf-ajax]. + +## CORS + +[Cross-Origin Resource Sharing][cors] is a mechanism for allowing clients to interact with APIs that are hosted on a different domain. CORS works by requiring the server to include a specific set of headers that allow a browser to determine if and when cross-domain requests should be allowed. + +The best way to deal with CORS in REST framework is to add the required response headers in middleware. This ensures that CORS is supported transparently, without having to change any behavior in your views. + +[Otto Yiu][ottoyiu] maintains the [django-cors-headers] package, which is known to work correctly with REST framework APIs. + +[cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html +[csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) +[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax +[cors]: http://www.w3.org/TR/cors/ +[ottoyiu]: https://github.com/ottoyiu/ +[django-cors-headers]: https://github.com/ottoyiu/django-cors-headers/ diff --git a/docs/topics/credits.md b/docs/topics/credits.md index 7cffbede..a67a8169 100644 --- a/docs/topics/credits.md +++ b/docs/topics/credits.md @@ -96,6 +96,11 @@ The following people have helped make REST framework great. * Bruno Renié - [brutasse] * Kevin Stone - [kevinastone] * Guglielmo Celata - [guglielmo] +* Mike Tums - [mktums] +* Michael Elovskikh - [wronglink] +* Michał Jaworski - [swistakm] +* Andrea de Marco - [z4r] +* Fernando Rocha - [fernandogrd] Many thanks to everyone who's contributed to the project. @@ -227,3 +232,8 @@ You can also contact [@_tomchristie][twitter] directly on twitter. [brutasse]: https://github.com/brutasse [kevinastone]: https://github.com/kevinastone [guglielmo]: https://github.com/guglielmo +[mktums]: https://github.com/mktums +[wronglink]: https://github.com/wronglink +[swistakm]: https://github.com/swistakm +[z4r]: https://github.com/z4r +[fernandogrd]: https://github.com/fernandogrd diff --git a/docs/topics/csrf.md b/docs/topics/csrf.md deleted file mode 100644 index 043144c1..00000000 --- a/docs/topics/csrf.md +++ /dev/null @@ -1,12 +0,0 @@ -# Working with AJAX and CSRF - -> "Take a close look at possible CSRF / XSRF vulnerabilities on your own websites. They're the worst kind of vulnerability -- very easy to exploit by attackers, yet not so intuitively easy to understand for software developers, at least until you've been bitten by one." -> -> — [Jeff Atwood][cite] - -* Explain need to add CSRF token to AJAX requests. -* Explain deferred CSRF style used by REST framework -* Why you should use Django's standard login/logout views, and not REST framework view - - -[cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 0c3ebca0..70c915b7 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -12,10 +12,26 @@ Medium version numbers (0.x.0) may include minor API changes. You should read t Major version numbers (x.0.0) are reserved for project milestones. No major point releases are currently planned. +## Upgrading + +To upgrade Django REST framework to the latest version, use pip: + + pip install -U djangorestframework + +You can determine your currently installed version using `pip freeze`: + + pip freeze | grep djangorestframework + --- ## 2.1.x series +### Master + +* Bugfix: Fix styling on browsable API login. +* Bugfix: Fix issue with deserializing empty to-many relations. +* Bugfix: Ensure model field validation is still applied for ModelSerializer subclasses with an custom `.restore_object()` method. + ### 2.1.17 **Date**: 26th Jan 2013 diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index f5ff167f..5f292211 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -4,7 +4,7 @@ This tutorial will cover creating a simple pastebin code highlighting Web API. Along the way it will introduce the various components that make up REST framework, and give you a comprehensive understanding of how everything fits together. -The tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started.<!-- If you just want a quick overview, you should head over to the [quickstart] documentation instead. --> +The tutorial is fairly in-depth, so you should probably get a cookie and a cup of your favorite brew before getting started. If you just want a quick overview, you should head over to the [quickstart] documentation instead. --- @@ -130,11 +130,11 @@ The first thing we need to get started on our Web API is provide a way of serial """ if instance: # Update existing instance - instance.title = attrs['title'] - instance.code = attrs['code'] - instance.linenos = attrs['linenos'] - instance.language = attrs['language'] - instance.style = attrs['style'] + instance.title = attrs.get('title', instance.title) + instance.code = attrs.get('code', instance.code) + instance.linenos = attrs.get('linenos', instance.linenos) + instance.language = attrs.get('language', instance.language) + instance.style = attrs.get('style', instance.style) return instance # Create new instance |
