Merge master

This commit is contained in:
Tom Christie 2013-04-30 19:32:34 +01:00
commit 22af28d146
8 changed files with 103 additions and 77 deletions

View File

@ -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. 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 ## Setting the permission policy

View File

@ -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. 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 %}
<h3 style="margin: 0 0 20px;">My Site Name</h3>
{% endblock %}
You can also customize the style by adding the `bootstrap_theme` or `style` block similar to `api.html`.
### Advanced Customization ### Advanced Customization

View File

@ -116,6 +116,8 @@ The following people have helped make REST framework great.
* Victor Shih - [vshih] * Victor Shih - [vshih]
* Atle Frenvik Sveen - [atlefren] * Atle Frenvik Sveen - [atlefren]
* J. Paul Reed - [preed] * J. Paul Reed - [preed]
* Matt Majewski - [forgingdestiny]
* Jerome Chen - [chenjyw]
Many thanks to everyone who's contributed to the project. 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 [vshih]: https://github.com/vshih
[atlefren]: https://github.com/atlefren [atlefren]: https://github.com/atlefren
[preed]: https://github.com/preed [preed]: https://github.com/preed
[forgingdestiny]: https://github.com/forgingdestiny
[chenjyw]: https://github.com/chenjyw

View File

@ -55,6 +55,10 @@ You can determine your currently installed version using `pip freeze`:
## 2.2.x series ## 2.2.x series
### Master
* Made Login template more easy to restyle.
### 2.2.7 ### 2.2.7
**Date**: 17th April 2013 **Date**: 17th April 2013

View File

@ -217,18 +217,6 @@ class BaseSerializer(WritableField):
return ret 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. # Methods to convert or revert from objects <--> primitive representations.
@ -683,6 +671,8 @@ class ModelSerializer(Serializer):
class NestedModelSerializer(ModelSerializer): class NestedModelSerializer(ModelSerializer):
class Meta: class Meta:
model = related_model model = related_model
depth = self.opts.depth - 1
return NestedModelSerializer(many=to_many) return NestedModelSerializer(many=to_many)
def get_related_field(self, model_field, related_model, to_many): def get_related_field(self, model_field, related_model, to_many):

View File

@ -1,53 +1,3 @@
{% load url from future %} {% extends "rest_framework/login_base.html" %}
{% load rest_framework %}
<html>
<head> {# Override this template in your own templates directory to customize #}
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/>
</head>
<body class="container">
<div class="container-fluid" style="margin-top: 30px">
<div class="row-fluid">
<div class="well" style="width: 320px; margin-left: auto; margin-right: auto">
<div class="row-fluid">
<div>
<h3 style="margin: 0 0 20px;">Django REST framework</h3>
</div>
</div><!-- /row fluid -->
<div class="row-fluid">
<div>
<form action="{% url 'rest_framework:login' %}" class=" form-inline" method="post">
{% csrf_token %}
<div id="div_id_username" class="clearfix control-group">
<div class="controls">
<Label class="span4">Username:</label>
<input style="height: 25px" type="text" name="username" maxlength="100" autocapitalize="off" autocorrect="off" class="textinput textInput" id="id_username">
</div>
</div>
<div id="div_id_password" class="clearfix control-group">
<div class="controls">
<Label class="span4">Password:</label>
<input style="height: 25px" type="password" name="password" maxlength="100" autocapitalize="off" autocorrect="off" class="textinput textInput" id="id_password">
</div>
</div>
<input type="hidden" name="next" value="{{ next }}" />
<div class="form-actions-no-box">
<input type="submit" name="submit" value="Log in" class="btn btn-primary" id="submit-id-submit">
</div>
</form>
</div>
</div><!-- /row fluid -->
</div><!--/span-->
</div><!-- /.row-fluid -->
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,55 @@
{% load url from future %}
{% load rest_framework %}
<html>
<head>
{% block style %}
{% block bootstrap_theme %}<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/>{% endblock %}
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/>
{% endblock %}
</head>
<body class="container">
<div class="container-fluid" style="margin-top: 30px">
<div class="row-fluid">
<div class="well" style="width: 320px; margin-left: auto; margin-right: auto">
<div class="row-fluid">
<div>
{% block branding %}<h3 style="margin: 0 0 20px;">Django REST framework</h3>{% endblock %}
</div>
</div><!-- /row fluid -->
<div class="row-fluid">
<div>
<form action="{% url 'rest_framework:login' %}" class=" form-inline" method="post">
{% csrf_token %}
<div id="div_id_username" class="clearfix control-group">
<div class="controls">
<Label class="span4">Username:</label>
<input style="height: 25px" type="text" name="username" maxlength="100" autocapitalize="off" autocorrect="off" class="textinput textInput" id="id_username">
</div>
</div>
<div id="div_id_password" class="clearfix control-group">
<div class="controls">
<Label class="span4">Password:</label>
<input style="height: 25px" type="password" name="password" maxlength="100" autocapitalize="off" autocorrect="off" class="textinput textInput" id="id_password">
</div>
</div>
<input type="hidden" name="next" value="{{ next }}" />
<div class="form-actions-no-box">
<input type="submit" name="submit" value="Log in" class="btn btn-primary" id="submit-id-submit">
</div>
</form>
</div>
</div><!-- /row fluid -->
</div><!--/span-->
</div><!-- /.row-fluid -->
</div>
</div>
</body>
</html>

View File

@ -3,7 +3,7 @@ from django.utils.datastructures import MultiValueDict
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel, 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) ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo)
import datetime import datetime
import pickle import pickle
@ -803,8 +803,6 @@ class RelatedTraversalTest(TestCase):
post = BlogPost.objects.create(title="Test blog post", writer=user) post = BlogPost.objects.create(title="Test blog post", writer=user)
post.blogpostcomment_set.create(text="I love this blog post") post.blogpostcomment_set.create(text="I love this blog post")
from rest_framework.tests.models import BlogPostComment
class PersonSerializer(serializers.ModelSerializer): class PersonSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Person model = Person
@ -1004,23 +1002,26 @@ class SerializerPickleTests(TestCase):
class DepthTest(TestCase): class DepthTest(TestCase):
def test_implicit_nesting(self): def test_implicit_nesting(self):
writer = Person.objects.create(name="django", age=1) writer = Person.objects.create(name="django", age=1)
post = BlogPost.objects.create(title="Test blog post", writer=writer) 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: class Meta:
model = BlogPost model = BlogPostComment
depth = 1 depth = 2
serializer = BlogPostSerializer(instance=post) serializer = BlogPostCommentSerializer(instance=comment)
expected = {'id': 1, 'title': 'Test blog post', expected = {'id': 1, 'text': 'Test blog post comment', 'blog_post': {'id': 1, 'title': 'Test blog post',
'writer': {'id': 1, 'name': 'django', 'age': 1}} 'writer': {'id': 1, 'name': 'django', 'age': 1}}}
self.assertEqual(serializer.data, expected) self.assertEqual(serializer.data, expected)
def test_explicit_nesting(self): def test_explicit_nesting(self):
writer = Person.objects.create(name="django", age=1) writer = Person.objects.create(name="django", age=1)
post = BlogPost.objects.create(title="Test blog post", writer=writer) 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 PersonSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@ -1032,9 +1033,15 @@ class DepthTest(TestCase):
class Meta: class Meta:
model = BlogPost model = BlogPost
serializer = BlogPostSerializer(instance=post) class BlogPostCommentSerializer(serializers.ModelSerializer):
expected = {'id': 1, 'title': 'Test blog post', blog_post = BlogPostSerializer()
'writer': {'id': 1, 'name': 'django', 'age': 1}}
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) self.assertEqual(serializer.data, expected)