Commit 1fd83adb by Tom Christie
parents 75d6446c 57a51f79
...@@ -195,9 +195,9 @@ For more details on using filter sets see the [django-filter documentation][djan ...@@ -195,9 +195,9 @@ For more details on using filter sets see the [django-filter documentation][djan
## SearchFilter ## SearchFilter
The `SearchFilterBackend` class supports simple single query parameter based searching, and is based on the [Django admin's search functionality][search-django-admin]. The `SearchFilter` class supports simple single query parameter based searching, and is based on the [Django admin's search functionality][search-django-admin].
The `SearchFilterBackend` class will only be applied if the view has a `search_fields` attribute set. The `search_fields` attribute should be a list of names of text type fields on the model, such as `CharField` or `TextField`. The `SearchFilter` class will only be applied if the view has a `search_fields` attribute set. The `search_fields` attribute should be a list of names of text type fields on the model, such as `CharField` or `TextField`.
class UserListView(generics.ListAPIView): class UserListView(generics.ListAPIView):
queryset = User.objects.all() queryset = User.objects.all()
......
...@@ -169,6 +169,7 @@ The following people have helped make REST framework great. ...@@ -169,6 +169,7 @@ The following people have helped make REST framework great.
* Edmond Wong - [edmondwong] * Edmond Wong - [edmondwong]
* Ben Reilly - [bwreilly] * Ben Reilly - [bwreilly]
* Tai Lee - [mrmachine] * Tai Lee - [mrmachine]
* Markus Kaiserswerth - [mkai]
Many thanks to everyone who's contributed to the project. Many thanks to everyone who's contributed to the project.
...@@ -374,3 +375,4 @@ You can also contact [@_tomchristie][twitter] directly on twitter. ...@@ -374,3 +375,4 @@ You can also contact [@_tomchristie][twitter] directly on twitter.
[edmondwong]: https://github.com/edmondwong [edmondwong]: https://github.com/edmondwong
[bwreilly]: https://github.com/bwreilly [bwreilly]: https://github.com/bwreilly
[mrmachine]: https://github.com/mrmachine [mrmachine]: https://github.com/mrmachine
[mkai]: https://github.com/mkai
...@@ -147,7 +147,7 @@ Similarly, we can control the format of the request that we send, using the `Con ...@@ -147,7 +147,7 @@ Similarly, we can control the format of the request that we send, using the `Con
# POST using form data # POST using form data
curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123" curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"
{"id": 3, "title": "", "code": "123", "linenos": false, "language": "python", "style": "friendly"} {"id": 3, "title": "", "code": "print 123", "linenos": false, "language": "python", "style": "friendly"}
# POST using JSON # POST using JSON
curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json" curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"
......
...@@ -85,7 +85,7 @@ Right, we'd better write some views then. Open `quickstart/views.py` and get ty ...@@ -85,7 +85,7 @@ Right, we'd better write some views then. Open `quickstart/views.py` and get ty
queryset = Group.objects.all() queryset = Group.objects.all()
serializer_class = GroupSerializer serializer_class = GroupSerializer
Rather that write multiple views we're grouping together all the common behavior into classes called `ViewSets`. Rather than write multiple views we're grouping together all the common behavior into classes called `ViewSets`.
We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise. We can easily break these down into individual views if we need to, but using viewsets keeps the view logic nicely organized as well as being very concise.
......
...@@ -80,6 +80,14 @@ except ImportError: ...@@ -80,6 +80,14 @@ except ImportError:
Image = None Image = None
def get_model_name(model_cls):
try:
return model_cls._meta.model_name
except AttributeError:
# < 1.6 used module_name instead of model_name
return model_cls._meta.module_name
def get_concrete_model(model_cls): def get_concrete_model(model_cls):
try: try:
return model_cls._meta.concrete_model return model_cls._meta.concrete_model
......
...@@ -4,7 +4,7 @@ returned by list views. ...@@ -4,7 +4,7 @@ returned by list views.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models from django.db import models
from rest_framework.compat import django_filters, six, guardian from rest_framework.compat import django_filters, six, guardian, get_model_name
from functools import reduce from functools import reduce
import operator import operator
...@@ -158,7 +158,7 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend): ...@@ -158,7 +158,7 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend):
model_cls = queryset.model model_cls = queryset.model
kwargs = { kwargs = {
'app_label': model_cls._meta.app_label, 'app_label': model_cls._meta.app_label,
'model_name': model_cls._meta.module_name 'model_name': get_model_name(model_cls)
} }
permission = self.perm_format % kwargs permission = self.perm_format % kwargs
return guardian.shortcuts.get_objects_for_user(user, permission, queryset) return guardian.shortcuts.get_objects_for_user(user, permission, queryset)
...@@ -8,7 +8,8 @@ import warnings ...@@ -8,7 +8,8 @@ import warnings
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'] SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
from django.http import Http404 from django.http import Http404
from rest_framework.compat import oauth2_provider_scope, oauth2_constants from rest_framework.compat import (get_model_name, oauth2_provider_scope,
oauth2_constants)
class BasePermission(object): class BasePermission(object):
...@@ -116,7 +117,7 @@ class DjangoModelPermissions(BasePermission): ...@@ -116,7 +117,7 @@ class DjangoModelPermissions(BasePermission):
""" """
kwargs = { kwargs = {
'app_label': model_cls._meta.app_label, 'app_label': model_cls._meta.app_label,
'model_name': model_cls._meta.module_name 'model_name': get_model_name(model_cls)
} }
return [perm % kwargs for perm in self.perms_map[method]] return [perm % kwargs for perm in self.perms_map[method]]
...@@ -177,7 +178,7 @@ class DjangoObjectPermissions(DjangoModelPermissions): ...@@ -177,7 +178,7 @@ class DjangoObjectPermissions(DjangoModelPermissions):
def get_required_object_permissions(self, method, model_cls): def get_required_object_permissions(self, method, model_cls):
kwargs = { kwargs = {
'app_label': model_cls._meta.app_label, 'app_label': model_cls._meta.app_label,
'model_name': model_cls._meta.module_name 'model_name': get_model_name(model_cls)
} }
return [perm % kwargs for perm in self.perms_map[method]] return [perm % kwargs for perm in self.perms_map[method]]
......
...@@ -518,6 +518,9 @@ class BaseSerializer(WritableField): ...@@ -518,6 +518,9 @@ class BaseSerializer(WritableField):
""" """
Save the deserialized object and return it. Save the deserialized object and return it.
""" """
# Clear cached _data, which may be invalidated by `save()`
self._data = None
if isinstance(self.object, list): if isinstance(self.object, list):
[self.save_object(item, **kwargs) for item in self.object] [self.save_object(item, **kwargs) for item in self.object]
......
...@@ -4,7 +4,7 @@ from django.db import models ...@@ -4,7 +4,7 @@ from django.db import models
from django.test import TestCase from django.test import TestCase
from django.utils import unittest from django.utils import unittest
from rest_framework import generics, status, permissions, authentication, HTTP_HEADER_ENCODING from rest_framework import generics, status, permissions, authentication, HTTP_HEADER_ENCODING
from rest_framework.compat import guardian from rest_framework.compat import guardian, get_model_name
from rest_framework.filters import DjangoObjectPermissionsFilter from rest_framework.filters import DjangoObjectPermissionsFilter
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
from rest_framework.tests.models import BasicModel from rest_framework.tests.models import BasicModel
...@@ -202,7 +202,7 @@ class ObjectPermissionsIntegrationTests(TestCase): ...@@ -202,7 +202,7 @@ class ObjectPermissionsIntegrationTests(TestCase):
# give everyone model level permissions, as we are not testing those # give everyone model level permissions, as we are not testing those
everyone = Group.objects.create(name='everyone') everyone = Group.objects.create(name='everyone')
model_name = BasicPermModel._meta.module_name model_name = get_model_name(BasicPermModel)
app_label = BasicPermModel._meta.app_label app_label = BasicPermModel._meta.app_label
f = '{0}_{1}'.format f = '{0}_{1}'.format
perms = { perms = {
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import models from django.db import models
from django.db.models.fields import BLANK_CHOICE_DASH from django.db.models.fields import BLANK_CHOICE_DASH
...@@ -136,6 +137,7 @@ class BasicTests(TestCase): ...@@ -136,6 +137,7 @@ class BasicTests(TestCase):
'Happy new year!', 'Happy new year!',
datetime.datetime(2012, 1, 1) datetime.datetime(2012, 1, 1)
) )
self.actionitem = ActionItem(title='Some to do item',)
self.data = { self.data = {
'email': 'tom@example.com', 'email': 'tom@example.com',
'content': 'Happy new year!', 'content': 'Happy new year!',
...@@ -264,6 +266,20 @@ class BasicTests(TestCase): ...@@ -264,6 +266,20 @@ class BasicTests(TestCase):
""" """
self.assertRaises(AssertionError, PersonSerializerInvalidReadOnly, []) self.assertRaises(AssertionError, PersonSerializerInvalidReadOnly, [])
def test_serializer_data_is_cleared_on_save(self):
"""
Check _data attribute is cleared on `save()`
Regression test for #1116
— id field is not populated if `data` is accessed prior to `save()`
"""
serializer = ActionItemSerializer(self.actionitem)
self.assertIsNone(serializer.data.get('id',None), 'New instance. `id` should not be set.')
serializer.save()
self.assertIsNotNone(serializer.data.get('id',None), 'Model is saved. `id` should be set.')
class DictStyleSerializer(serializers.Serializer): class DictStyleSerializer(serializers.Serializer):
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment