diff options
Diffstat (limited to 'rest_framework')
24 files changed, 146 insertions, 103 deletions
| diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index 01036cef..f30012b9 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -1,9 +1,9 @@  """ -______ _____ _____ _____    __                                             _     -| ___ \  ___/  ___|_   _|  / _|                                           | |    -| |_/ / |__ \ `--.  | |   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __ +______ _____ _____ _____    __ +| ___ \  ___/  ___|_   _|  / _|                                           | | +| |_/ / |__ \ `--.  | |   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| |__  |    /|  __| `--. \ | |   |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / -| |\ \| |___/\__/ / | |   | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <  +| |\ \| |___/\__/ / | |   | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <  \_| \_\____/\____/  \_/   |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_|  """ diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index 82cea70f..5721a869 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -21,7 +21,7 @@ def get_authorization_header(request):      Hide some test client ickyness where the header can be unicode.      """      auth = request.META.get('HTTP_AUTHORIZATION', b'') -    if type(auth) == type(''): +    if isinstance(auth, type('')):          # Work around django test client oddness          auth = auth.encode(HTTP_HEADER_ENCODING)      return auth diff --git a/rest_framework/authtoken/models.py b/rest_framework/authtoken/models.py index 167fa531..db21d44c 100644 --- a/rest_framework/authtoken/models.py +++ b/rest_framework/authtoken/models.py @@ -1,6 +1,5 @@  import binascii  import os -from hashlib import sha1  from django.conf import settings  from django.db import models diff --git a/rest_framework/authtoken/south_migrations/0001_initial.py b/rest_framework/authtoken/south_migrations/0001_initial.py index d5965e40..926de02b 100644 --- a/rest_framework/authtoken/south_migrations/0001_initial.py +++ b/rest_framework/authtoken/south_migrations/0001_initial.py @@ -1,15 +1,10 @@  # -*- coding: utf-8 -*- -import datetime  from south.db import db  from south.v2 import SchemaMigration -from django.db import models - -from rest_framework.settings import api_settings -  try:      from django.contrib.auth import get_user_model -except ImportError: # django < 1.5 +except ImportError:  # django < 1.5      from django.contrib.auth.models import User  else:      User = get_user_model() @@ -26,12 +21,10 @@ class Migration(SchemaMigration):          ))          db.send_create_signal('authtoken', ['Token']) -      def backwards(self, orm):          # Deleting model 'Token'          db.delete_table('authtoken_token') -      models = {          'auth.group': {              'Meta': {'object_name': 'Group'}, diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index 18e41a18..e06d6ff5 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -131,6 +131,7 @@ def list_route(methods=['get'], **kwargs):          return func      return decorator +  # These are now pending deprecation, in favor of `detail_route` and `list_route`.  def link(**kwargs): @@ -139,11 +140,13 @@ def link(**kwargs):      """      msg = 'link is pending deprecation. Use detail_route instead.'      warnings.warn(msg, PendingDeprecationWarning, stacklevel=2) +      def decorator(func):          func.bind_to_methods = ['get']          func.detail = True          func.kwargs = kwargs          return func +      return decorator @@ -153,9 +156,11 @@ def action(methods=['post'], **kwargs):      """      msg = 'action is pending deprecation. Use detail_route instead.'      warnings.warn(msg, PendingDeprecationWarning, stacklevel=2) +      def decorator(func):          func.bind_to_methods = methods          func.detail = True          func.kwargs = kwargs          return func -    return decorator
\ No newline at end of file + +    return decorator diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index 5f774a9f..97dab77e 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -23,6 +23,7 @@ class APIException(Exception):      def __str__(self):          return self.detail +  class ParseError(APIException):      status_code = status.HTTP_400_BAD_REQUEST      default_detail = 'Malformed request.' diff --git a/rest_framework/filters.py b/rest_framework/filters.py index c3b846ae..538386ce 100644 --- a/rest_framework/filters.py +++ b/rest_framework/filters.py @@ -116,7 +116,7 @@ class OrderingFilter(BaseFilterBackend):      def get_ordering(self, request):          """          Ordering is set by a comma delimited ?ordering=... query parameter. -         +          The `ordering` query parameter can be overridden by setting          the `ordering_param` value on the OrderingFilter or by          specifying an `ORDERING_PARAM` value in the API settings. diff --git a/rest_framework/generics.py b/rest_framework/generics.py index cecb548f..02d24365 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -25,6 +25,7 @@ def strict_positive_int(integer_string, cutoff=None):          ret = min(ret, cutoff)      return ret +  def get_object_or_404(queryset, *filter_args, **filter_kwargs):      """      Same as Django's standard shortcut, but make sure to raise 404 @@ -162,10 +163,11 @@ class GenericAPIView(views.APIView):                  raise Http404(_("Page is not 'last', nor can it be converted to an int."))          try:              page = paginator.page(page_number) -        except InvalidPage as e: -            raise Http404(_('Invalid page (%(page_number)s): %(message)s') % { -                                'page_number': page_number, -                                'message': str(e) +        except InvalidPage as exc: +            error_format = _('Invalid page (%(page_number)s): %(message)s') +            raise Http404(error_format % { +                'page_number': page_number, +                'message': str(exc)              })          if deprecated_style: @@ -208,7 +210,6 @@ class GenericAPIView(views.APIView):          return filter_backends -      ########################      ### The following methods provide default implementations      ### that you may want to override for more complex cases. @@ -284,8 +285,8 @@ class GenericAPIView(views.APIView):          if self.model is not None:              return self.model._default_manager.all() -        raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'" -                                    % self.__class__.__name__) +        error_format = "'%s' must define 'queryset' or 'model'" +        raise ImproperlyConfigured(error_format % self.__class__.__name__)      def get_object(self, queryset=None):          """ diff --git a/rest_framework/negotiation.py b/rest_framework/negotiation.py index 4d205c0e..ca7b5397 100644 --- a/rest_framework/negotiation.py +++ b/rest_framework/negotiation.py @@ -54,8 +54,10 @@ class DefaultContentNegotiation(BaseContentNegotiation):                  for media_type in media_type_set:                      if media_type_matches(renderer.media_type, media_type):                          # Return the most specific media type as accepted. -                        if (_MediaType(renderer.media_type).precedence > -                            _MediaType(media_type).precedence): +                        if ( +                            _MediaType(renderer.media_type).precedence > +                            _MediaType(media_type).precedence +                        ):                              # Eg client requests '*/*'                              # Accepted media type is 'application/json'                              return renderer, renderer.media_type diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index c9517138..6a1a0077 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -62,9 +62,11 @@ class IsAuthenticatedOrReadOnly(BasePermission):      """      def has_permission(self, request, view): -        return (request.method in SAFE_METHODS or  -            request.user and  -            request.user.is_authenticated()) +        return ( +            request.method in SAFE_METHODS or +            request.user and +            request.user.is_authenticated() +        )  class DjangoModelPermissions(BasePermission): @@ -122,9 +124,11 @@ class DjangoModelPermissions(BasePermission):          perms = self.get_required_permissions(request.method, model_cls) -        return (request.user and +        return ( +            request.user and              (request.user.is_authenticated() or not self.authenticated_users_only) and -            request.user.has_perms(perms)) +            request.user.has_perms(perms) +        )  class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions): @@ -212,6 +216,8 @@ class TokenHasReadWriteScope(BasePermission):              required = oauth2_constants.READ if read_only else oauth2_constants.WRITE              return oauth2_provider_scope.check(required, request.auth.scope) -        assert False, ('TokenHasReadWriteScope requires either the' -        '`OAuthAuthentication` or `OAuth2Authentication` authentication ' -        'class to be used.') +        assert False, ( +            'TokenHasReadWriteScope requires either the' +            '`OAuthAuthentication` or `OAuth2Authentication` authentication ' +            'class to be used.' +        ) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 7048d87d..3dabd277 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -8,7 +8,6 @@ REST framework also provides an HTML renderer the renders the browsable API.  """  from __future__ import unicode_literals -import copy  import json  import django  from django import forms @@ -75,7 +74,6 @@ class JSONRenderer(BaseRenderer):          # E.g. If we're being called by the BrowsableAPIRenderer.          return renderer_context.get('indent', None) -      def render(self, data, accepted_media_type=None, renderer_context=None):          """          Render `data` into JSON, returning a bytestring. @@ -86,8 +84,10 @@ class JSONRenderer(BaseRenderer):          renderer_context = renderer_context or {}          indent = self.get_indent(accepted_media_type, renderer_context) -        ret = json.dumps(data, cls=self.encoder_class, -            indent=indent, ensure_ascii=self.ensure_ascii) +        ret = json.dumps( +            data, cls=self.encoder_class, +            indent=indent, ensure_ascii=self.ensure_ascii +        )          # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,          # but if ensure_ascii=False, the return type is underspecified, @@ -454,8 +454,10 @@ class BrowsableAPIRenderer(BaseRenderer):              if method in ('DELETE', 'OPTIONS'):                  return True  # Don't actually need to return a form -            if (not getattr(view, 'get_serializer', None) -                or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes)): +            if ( +                not getattr(view, 'get_serializer', None) +                or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes) +            ):                  return              serializer = view.get_serializer(instance=obj, data=data, files=files) @@ -576,7 +578,7 @@ class BrowsableAPIRenderer(BaseRenderer):              'version': VERSION,              'breadcrumblist': self.get_breadcrumbs(request),              'allowed_methods': view.allowed_methods, -            'available_formats': [renderer.format for renderer in view.renderer_classes], +            'available_formats': [renderer_cls.format for renderer_cls in view.renderer_classes],              'response_headers': response_headers,              'put_form': self.get_rendered_html_form(view, 'PUT', request), @@ -625,4 +627,3 @@ class MultiPartRenderer(BaseRenderer):      def render(self, data, accepted_media_type=None, renderer_context=None):          return encode_multipart(self.BOUNDARY, data) - diff --git a/rest_framework/request.py b/rest_framework/request.py index d508f9b4..620b00ad 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -295,8 +295,11 @@ class Request(object):          Return the content body of the request, as a stream.          """          try: -            content_length = int(self.META.get('CONTENT_LENGTH', -                                    self.META.get('HTTP_CONTENT_LENGTH'))) +            content_length = int( +                self.META.get( +                    'CONTENT_LENGTH', self.META.get('HTTP_CONTENT_LENGTH') +                ) +            )          except (ValueError, TypeError):              content_length = 0 @@ -320,9 +323,11 @@ class Request(object):          )          # We only need to use form overloading on form POST requests. -        if (not USE_FORM_OVERLOADING +        if ( +            not USE_FORM_OVERLOADING              or self._request.method != 'POST' -            or not is_form_media_type(self._content_type)): +            or not is_form_media_type(self._content_type) +        ):              return          # At this point we're committed to parsing the request as form data. @@ -330,15 +335,19 @@ class Request(object):          self._files = self._request.FILES          # Method overloading - change the method and remove the param from the content. -        if (self._METHOD_PARAM and -            self._METHOD_PARAM in self._data): +        if ( +            self._METHOD_PARAM and +            self._METHOD_PARAM in self._data +        ):              self._method = self._data[self._METHOD_PARAM].upper()          # Content overloading - modify the content type, and force re-parse. -        if (self._CONTENT_PARAM and +        if ( +            self._CONTENT_PARAM and              self._CONTENTTYPE_PARAM and              self._CONTENT_PARAM in self._data and -            self._CONTENTTYPE_PARAM in self._data): +            self._CONTENTTYPE_PARAM in self._data +        ):              self._content_type = self._data[self._CONTENTTYPE_PARAM]              self._stream = BytesIO(self._data[self._CONTENT_PARAM].encode(self.parser_context['encoding']))              self._data, self._files = (Empty, Empty) diff --git a/rest_framework/response.py b/rest_framework/response.py index 25b78524..80225cac 100644 --- a/rest_framework/response.py +++ b/rest_framework/response.py @@ -62,8 +62,10 @@ class Response(SimpleTemplateResponse):          ret = renderer.render(self.data, media_type, context)          if isinstance(ret, six.text_type): -            assert charset, 'renderer returned unicode, and did not specify ' \ -            'a charset value.' +            assert charset, ( +                'renderer returned unicode, and did not specify ' +                'a charset value.' +            )              return bytes(ret.encode(charset))          if not ret: diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 2fdc9b9d..95288671 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -449,9 +449,11 @@ class BaseSerializer(WritableField):                  # If we have a model manager or similar object then we need                  # to iterate through each instance. -                if (self.many and +                if ( +                    self.many and                      not hasattr(obj, '__iter__') and -                    is_simple_callable(getattr(obj, 'all', None))): +                    is_simple_callable(getattr(obj, 'all', None)) +                ):                      obj = obj.all()                  kwargs = { @@ -601,8 +603,10 @@ class BaseSerializer(WritableField):          API schemas for auto-documentation.          """          return SortedDict( -            [(field_name, field.metadata()) -            for field_name, field in six.iteritems(self.fields)] +            [ +                (field_name, field.metadata()) +                for field_name, field in six.iteritems(self.fields) +            ]          ) @@ -656,8 +660,10 @@ class ModelSerializer(Serializer):          """          cls = self.opts.model -        assert cls is not None, \ -                "Serializer class '%s' is missing 'model' Meta option" % self.__class__.__name__ +        assert cls is not None, ( +            "Serializer class '%s' is missing 'model' Meta option" % +            self.__class__.__name__ +        )          opts = cls._meta.concrete_model._meta          ret = SortedDict()          nested = bool(self.opts.depth) @@ -668,9 +674,9 @@ class ModelSerializer(Serializer):              # If model is a child via multitable inheritance, use parent's pk              pk_field = pk_field.rel.to._meta.pk -        field = self.get_pk_field(pk_field) -        if field: -            ret[pk_field.name] = field +        serializer_pk_field = self.get_pk_field(pk_field) +        if serializer_pk_field: +            ret[pk_field.name] = serializer_pk_field          # Deal with forward relationships          forward_rels = [field for field in opts.fields if field.serialize] @@ -739,9 +745,11 @@ class ModelSerializer(Serializer):              is_m2m = isinstance(relation.field,                                  models.fields.related.ManyToManyField) -            if (is_m2m and +            if ( +                is_m2m and                  hasattr(relation.field.rel, 'through') and -                not relation.field.rel.through._meta.auto_created): +                not relation.field.rel.through._meta.auto_created +            ):                  has_through_model = True              if nested: @@ -911,10 +919,12 @@ class ModelSerializer(Serializer):          for field_name, field in self.fields.items():              field_name = field.source or field_name -            if field_name in exclusions \ -                and not field.read_only \ -                and (field.required or hasattr(instance, field_name)) \ -                and not isinstance(field, Serializer): +            if ( +                field_name in exclusions +                and not field.read_only +                and (field.required or hasattr(instance, field_name)) +                and not isinstance(field, Serializer) +            ):                  exclusions.remove(field_name)          return exclusions diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 2727f596..6806a468 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -46,16 +46,12 @@ DEFAULTS = {      'DEFAULT_PERMISSION_CLASSES': (          'rest_framework.permissions.AllowAny',      ), -    'DEFAULT_THROTTLE_CLASSES': ( -    ), -    'DEFAULT_CONTENT_NEGOTIATION_CLASS': -        'rest_framework.negotiation.DefaultContentNegotiation', +    'DEFAULT_THROTTLE_CLASSES': (), +    'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',      # Genric view behavior -    'DEFAULT_MODEL_SERIALIZER_CLASS': -        'rest_framework.serializers.ModelSerializer', -    'DEFAULT_PAGINATION_SERIALIZER_CLASS': -        'rest_framework.pagination.PaginationSerializer', +    'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.serializers.ModelSerializer', +    'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'rest_framework.pagination.PaginationSerializer',      'DEFAULT_FILTER_BACKENDS': (),      # Throttling diff --git a/rest_framework/status.py b/rest_framework/status.py index 76435371..90a75508 100644 --- a/rest_framework/status.py +++ b/rest_framework/status.py @@ -10,15 +10,19 @@ from __future__ import unicode_literals  def is_informational(code):      return code >= 100 and code <= 199 +  def is_success(code):      return code >= 200 and code <= 299 +  def is_redirect(code):      return code >= 300 and code <= 399 +  def is_client_error(code):      return code >= 400 and code <= 499 +  def is_server_error(code):      return code >= 500 and code <= 599 diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index 911b1b62..5b8fa385 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -152,8 +152,10 @@ def urlize_quoted_links(text, trim_url_limit=None, nofollow=True, autoescape=Tru                      middle = middle[len(opening):]                      lead = lead + opening                  # Keep parentheses at the end only if they're balanced. -                if (middle.endswith(closing) -                    and middle.count(closing) == middle.count(opening) + 1): +                if ( +                    middle.endswith(closing) +                    and middle.count(closing) == middle.count(opening) + 1 +                ):                      middle = middle[:-len(closing)]                      trail = closing + trail diff --git a/rest_framework/test.py b/rest_framework/test.py index d4ec50a0..9242cf7c 100644 --- a/rest_framework/test.py +++ b/rest_framework/test.py @@ -49,9 +49,10 @@ class APIRequestFactory(DjangoRequestFactory):          else:              format = format or self.default_format -            assert format in self.renderer_classes, ("Invalid format '{0}'. " -                "Available formats are {1}.  Set TEST_REQUEST_RENDERER_CLASSES " -                "to enable extra request formats.".format( +            assert format in self.renderer_classes, ( +                "Invalid format '{0}'. Available formats are {1}. " +                "Set TEST_REQUEST_RENDERER_CLASSES to enable " +                "extra request formats.".format(                      format,                      ', '.join(["'" + fmt + "'" for fmt in self.renderer_classes.keys()])                  ) diff --git a/rest_framework/urls.py b/rest_framework/urls.py index eed4bd14..8fa3073e 100644 --- a/rest_framework/urls.py +++ b/rest_framework/urls.py @@ -8,17 +8,19 @@ your API requires authentication:          ...          url(r'^auth', include('rest_framework.urls', namespace='rest_framework'))      ) -     +  The urls must be namespaced as 'rest_framework', and you should make sure  your authentication settings include `SessionAuthentication`.  """  from __future__ import unicode_literals  from django.conf.urls import patterns, url +from django.contrib.auth import views  template_name = {'template_name': 'rest_framework/login.html'} -urlpatterns = patterns('django.contrib.auth.views', -    url(r'^login/$', 'login', template_name, name='login'), -    url(r'^logout/$', 'logout', template_name, name='logout'), +urlpatterns = patterns( +    '', +    url(r'^login/$', views.login, template_name, name='login'), +    url(r'^logout/$', views.logout, template_name, name='logout')  ) diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index c125ac8a..00ffdfba 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -98,14 +98,23 @@ else:                      node.flow_style = best_style              return node -    SafeDumper.add_representer(decimal.Decimal, -            SafeDumper.represent_decimal) - -    SafeDumper.add_representer(SortedDict, -            yaml.representer.SafeRepresenter.represent_dict) -    SafeDumper.add_representer(DictWithMetadata, -            yaml.representer.SafeRepresenter.represent_dict) -    SafeDumper.add_representer(SortedDictWithMetadata, -            yaml.representer.SafeRepresenter.represent_dict) -    SafeDumper.add_representer(types.GeneratorType, -            yaml.representer.SafeRepresenter.represent_list) +    SafeDumper.add_representer( +        decimal.Decimal, +        SafeDumper.represent_decimal +    ) +    SafeDumper.add_representer( +        SortedDict, +        yaml.representer.SafeRepresenter.represent_dict +    ) +    SafeDumper.add_representer( +        DictWithMetadata, +        yaml.representer.SafeRepresenter.represent_dict +    ) +    SafeDumper.add_representer( +        SortedDictWithMetadata, +        yaml.representer.SafeRepresenter.represent_dict +    ) +    SafeDumper.add_representer( +        types.GeneratorType, +        yaml.representer.SafeRepresenter.represent_list +    ) diff --git a/rest_framework/utils/formatting.py b/rest_framework/utils/formatting.py index 4b59ba84..6d53aed1 100644 --- a/rest_framework/utils/formatting.py +++ b/rest_framework/utils/formatting.py @@ -6,8 +6,6 @@ from __future__ import unicode_literals  from django.utils.html import escape  from django.utils.safestring import mark_safe  from rest_framework.compat import apply_markdown -from rest_framework.settings import api_settings -from textwrap import dedent  import re @@ -40,6 +38,7 @@ def dedent(content):      return content.strip() +  def camelcase_to_spaces(content):      """      Translate 'CamelCaseNames' to 'Camel Case Names'. @@ -49,6 +48,7 @@ def camelcase_to_spaces(content):      content = re.sub(camelcase_boundry, ' \\1', content).strip()      return ' '.join(content.split('_')).title() +  def markup_description(description):      """      Apply HTML markup to the given description. diff --git a/rest_framework/utils/mediatypes.py b/rest_framework/utils/mediatypes.py index 92f99efd..727f9c19 100644 --- a/rest_framework/utils/mediatypes.py +++ b/rest_framework/utils/mediatypes.py @@ -57,7 +57,7 @@ class _MediaType(object):              if key != 'q' and other.params.get(key, None) != self.params.get(key, None):                  return False -        if self.sub_type != '*' and other.sub_type != '*'  and other.sub_type != self.sub_type: +        if self.sub_type != '*' and other.sub_type != '*' and other.sub_type != self.sub_type:              return False          if self.main_type != '*' and other.main_type != '*' and other.main_type != self.main_type: diff --git a/rest_framework/views.py b/rest_framework/views.py index a2668f2c..bca0aaef 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -31,6 +31,7 @@ def get_view_name(view_cls, suffix=None):      return name +  def get_view_description(view_cls, html=False):      """      Given a view class, return a textual description to represent the view. @@ -119,7 +120,6 @@ class APIView(View):              headers['Vary'] = 'Accept'          return headers -      def http_method_not_allowed(self, request, *args, **kwargs):          """          If `request.method` does not correspond to a handler method, diff --git a/rest_framework/viewsets.py b/rest_framework/viewsets.py index 7eb29f99..bb5b304e 100644 --- a/rest_framework/viewsets.py +++ b/rest_framework/viewsets.py @@ -127,11 +127,11 @@ class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,  class ModelViewSet(mixins.CreateModelMixin, -                    mixins.RetrieveModelMixin, -                    mixins.UpdateModelMixin, -                    mixins.DestroyModelMixin, -                    mixins.ListModelMixin, -                    GenericViewSet): +                   mixins.RetrieveModelMixin, +                   mixins.UpdateModelMixin, +                   mixins.DestroyModelMixin, +                   mixins.ListModelMixin, +                   GenericViewSet):      """      A viewset that provides default `create()`, `retrieve()`, `update()`,      `partial_update()`, `destroy()` and `list()` actions. | 
