diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index 304d35412..85e38185e 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -398,10 +398,15 @@ A string representing the function that should be used when generating view name This should be a function with the following signature: - view_name(cls, suffix=None) + view_name(self) -* `cls`: The view class. Typically the name function would inspect the name of the class when generating a descriptive name, by accessing `cls.__name__`. -* `suffix`: The optional suffix used when differentiating individual views in a viewset. +* `self`: The view instance. Typically the name function would inspect the name of the class when generating a descriptive name, by accessing `self.__class__.__name__`. + +If the view instance inherits `ViewSet`, it may have been initialized with several optional arguments: + +* `name`: A name expliticly provided to a view in the viewset. Typically, this value should be used as-is when provided. +* `suffix`: Text used when differentiating individual views in a viewset. This argument is mutually exclusive to `name`. +* `detail`: Boolean that differentiates an individual view in a viewset as either being a 'list' or 'detail' view. Default: `'rest_framework.views.get_view_name'` @@ -413,11 +418,15 @@ This setting can be changed to support markup styles other than the default mark This should be a function with the following signature: - view_description(cls, html=False) + view_description(self, html=False) -* `cls`: The view class. Typically the description function would inspect the docstring of the class when generating a description, by accessing `cls.__doc__` +* `self`: The view instance. Typically the description function would inspect the docstring of the class when generating a description, by accessing `self.__class__.__doc__` * `html`: A boolean indicating if HTML output is required. `True` when used in the browsable API, and `False` when used in generating `OPTIONS` responses. +If the view instance inherits `ViewSet`, it may have been initialized with several optional arguments: + +* `description`: A description explicitly provided to the view in the viewset. Typically, this is set by extra viewset `action`s, and should be used as-is. + Default: `'rest_framework.views.get_view_description'` ## HTML Select Field cutoffs diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 503459a96..9be62bf16 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -110,6 +110,8 @@ During dispatch, the following attributes are available on the `ViewSet`. * `action` - the name of the current action (e.g., `list`, `create`). * `detail` - boolean indicating if the current action is configured for a list or detail view. * `suffix` - the display suffix for the viewset type - mirrors the `detail` attribute. +* `name` - the display name for the viewset. This argument is mutually exclusive to `suffix`. +* `description` - the display description for the individual view of a viewset. You may inspect these attributes to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the `list` action similar to this: @@ -142,7 +144,7 @@ A more complete example of extra actions: queryset = User.objects.all() serializer_class = UserSerializer - @action(methods=['post'], detail=True) + @action(detail=True, methods=['post']) def set_password(self, request, pk=None): user = self.get_object() serializer = PasswordSerializer(data=request.data) @@ -168,13 +170,13 @@ A more complete example of extra actions: The decorator can additionally take extra arguments that will be set for the routed view only. For example: - @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf]) + @action(detail=True, methods=['post'], permission_classes=[IsAdminOrIsSelf]) def set_password(self, request, pk=None): ... These decorator will route `GET` requests by default, but may also accept other HTTP methods by setting the `methods` argument. For example: - @action(methods=['post', 'delete'], detail=True) + @action(detail=True, methods=['post', 'delete']) def unset_password(self, request, pk=None): ... @@ -182,6 +184,22 @@ The two new actions will then be available at the urls `^users/{pk}/set_password To view all extra actions, call the `.get_extra_actions()` method. +### Routing additional HTTP methods for extra actions + +Extra actions can be mapped to different `ViewSet` methods. For example, the above password set/unset methods could be consolidated into a single route. Note that additional mappings do not accept arguments. + +```python + @action(detail=True, methods=['put'], name='Change Password') + def password(self, request, pk=None): + """Update the user's password.""" + ... + + @password.mapping.delete + def delete_password(self, request, pk=None): + """Delete the user's password.""" + ... +``` + ## Reversing action URLs If you need to get the URL of an action, use the `.reverse_action()` method. This is a convenience wrapper for `reverse()`, automatically passing the view's `request` object and prepending the `url_name` with the `.basename` attribute.