diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 5dbaf3389..db0d4b26a 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -21,7 +21,12 @@ If any permission check fails an `exceptions.PermissionDenied` exception will be REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance. -Object level permissions are run by REST framework's generic views when `.get_object()` is called. As with view level permissions, an `exceptions.PermissionDenied` exception will be raised if the user is not allowed to act on the given object. +Object level permissions are run by REST framework's generic views when `.get_object()` is called. +As with view level permissions, an `exceptions.PermissionDenied` exception will be raised if the user is not allowed to act on the given object. + +If you're writing your own views and want to enforce object level permissions, +you'll need to explicitly call the `.check_object_permissions(request, obj)` method on the view at the point at which you've retrieved the object. +This will either raise a `PermissionDenied` or `NotAuthenticated` exception, or simply return if the view has the appropriate permissions. ## Setting the permission policy diff --git a/docs/topics/browsable-api.md b/docs/topics/browsable-api.md index 5f80c4f95..8ee018249 100644 --- a/docs/topics/browsable-api.md +++ b/docs/topics/browsable-api.md @@ -60,6 +60,17 @@ All of the [Bootstrap components][bcomponents] are available. The browsable API makes use of the Bootstrap tooltips component. Any element with the `js-tooltip` class and a `title` attribute has that title content displayed in a tooltip on hover after a 1000ms delay. +### Login Template + +To add branding and customize the look-and-feel of the auth login template, create a template called `login.html` and add it to your project, eg: `templates/rest_framework/login.html`, that extends the `rest_framework/base_login.html` template. + +You can add your site name or branding by including the branding block: + + {% block branding %} +

My Site Name

+ {% endblock %} + +You can also customize the style by adding the `bootstrap_theme` or `style` block similar to `api.html`. ### Advanced Customization diff --git a/docs/topics/credits.md b/docs/topics/credits.md index da49e5212..7b8a428ea 100644 --- a/docs/topics/credits.md +++ b/docs/topics/credits.md @@ -116,6 +116,8 @@ The following people have helped make REST framework great. * Victor Shih - [vshih] * Atle Frenvik Sveen - [atlefren] * J. Paul Reed - [preed] +* Matt Majewski - [forgingdestiny] +* Jerome Chen - [chenjyw] Many thanks to everyone who's contributed to the project. @@ -266,3 +268,5 @@ You can also contact [@_tomchristie][twitter] directly on twitter. [vshih]: https://github.com/vshih [atlefren]: https://github.com/atlefren [preed]: https://github.com/preed +[forgingdestiny]: https://github.com/forgingdestiny +[chenjyw]: https://github.com/chenjyw diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 84d45a00d..9b10a3426 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -55,6 +55,10 @@ You can determine your currently installed version using `pip freeze`: ## 2.2.x series +### Master + +* Made Login template more easy to restyle. + ### 2.2.7 **Date**: 17th April 2013 diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 0f943d799..b589eca83 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -217,18 +217,6 @@ class BaseSerializer(WritableField): return ret - ##### - # Field methods - used when the serializer class is itself used as a field. - - def initialize(self, parent, field_name): - """ - Same behaviour as usual Field, except that we need to keep track - of state so that we can deal with handling maximum depth. - """ - super(BaseSerializer, self).initialize(parent, field_name) - if parent.opts.depth: - self.opts.depth = parent.opts.depth - 1 - ##### # Methods to convert or revert from objects <--> primitive representations. @@ -683,6 +671,8 @@ class ModelSerializer(Serializer): class NestedModelSerializer(ModelSerializer): class Meta: model = related_model + depth = self.opts.depth - 1 + return NestedModelSerializer(many=to_many) def get_related_field(self, model_field, related_model, to_many): diff --git a/rest_framework/templates/rest_framework/login.html b/rest_framework/templates/rest_framework/login.html index e10ce20f3..b76293279 100644 --- a/rest_framework/templates/rest_framework/login.html +++ b/rest_framework/templates/rest_framework/login.html @@ -1,53 +1,3 @@ -{% load url from future %} -{% load rest_framework %} - +{% extends "rest_framework/login_base.html" %} - - - - - - - - -
-
- -
-
-
-

Django REST framework

-
-
- -
-
-
- {% csrf_token %} -
-
- - -
-
-
-
- - -
-
- -
- -
-
-
-
-
- -
-
- - - - +{# Override this template in your own templates directory to customize #} diff --git a/rest_framework/templates/rest_framework/login_base.html b/rest_framework/templates/rest_framework/login_base.html new file mode 100644 index 000000000..380d58205 --- /dev/null +++ b/rest_framework/templates/rest_framework/login_base.html @@ -0,0 +1,55 @@ +{% load url from future %} +{% load rest_framework %} + + + + {% block style %} + {% block bootstrap_theme %}{% endblock %} + + + {% endblock %} + + + + +
+
+ +
+
+
+ {% block branding %}

Django REST framework

{% endblock %} +
+
+ +
+
+
+ {% csrf_token %} +
+
+ + +
+
+
+
+ + +
+
+ +
+ +
+
+
+
+
+ +
+
+ + + + diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index ae8d09dc9..84e1ee4e0 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -3,7 +3,7 @@ from django.utils.datastructures import MultiValueDict from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel, - BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, + BlankFieldModel, BlogPost, BlogPostComment, Book, CallableDefaultValueModel, DefaultValueModel, ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo) import datetime import pickle @@ -803,8 +803,6 @@ class RelatedTraversalTest(TestCase): post = BlogPost.objects.create(title="Test blog post", writer=user) post.blogpostcomment_set.create(text="I love this blog post") - from rest_framework.tests.models import BlogPostComment - class PersonSerializer(serializers.ModelSerializer): class Meta: model = Person @@ -1004,23 +1002,26 @@ class SerializerPickleTests(TestCase): class DepthTest(TestCase): def test_implicit_nesting(self): + writer = Person.objects.create(name="django", age=1) post = BlogPost.objects.create(title="Test blog post", writer=writer) + comment = BlogPostComment.objects.create(text="Test blog post comment", blog_post=post) - class BlogPostSerializer(serializers.ModelSerializer): + class BlogPostCommentSerializer(serializers.ModelSerializer): class Meta: - model = BlogPost - depth = 1 + model = BlogPostComment + depth = 2 - serializer = BlogPostSerializer(instance=post) - expected = {'id': 1, 'title': 'Test blog post', - 'writer': {'id': 1, 'name': 'django', 'age': 1}} + serializer = BlogPostCommentSerializer(instance=comment) + expected = {'id': 1, 'text': 'Test blog post comment', 'blog_post': {'id': 1, 'title': 'Test blog post', + 'writer': {'id': 1, 'name': 'django', 'age': 1}}} self.assertEqual(serializer.data, expected) def test_explicit_nesting(self): writer = Person.objects.create(name="django", age=1) post = BlogPost.objects.create(title="Test blog post", writer=writer) + comment = BlogPostComment.objects.create(text="Test blog post comment", blog_post=post) class PersonSerializer(serializers.ModelSerializer): class Meta: @@ -1032,9 +1033,15 @@ class DepthTest(TestCase): class Meta: model = BlogPost - serializer = BlogPostSerializer(instance=post) - expected = {'id': 1, 'title': 'Test blog post', - 'writer': {'id': 1, 'name': 'django', 'age': 1}} + class BlogPostCommentSerializer(serializers.ModelSerializer): + blog_post = BlogPostSerializer() + + class Meta: + model = BlogPostComment + + serializer = BlogPostCommentSerializer(instance=comment) + expected = {'id': 1, 'text': 'Test blog post comment', 'blog_post': {'id': 1, 'title': 'Test blog post', + 'writer': {'id': 1, 'name': 'django', 'age': 1}}} self.assertEqual(serializer.data, expected)