{"id":26018521,"url":"https://github.com/alaouimehdi1995/django-rest","last_synced_at":"2025-03-06T06:21:19.213Z","repository":{"id":52691260,"uuid":"252743168","full_name":"alaouimehdi1995/django-rest","owner":"alaouimehdi1995","description":"Tiny, fast django REST library","archived":false,"fork":false,"pushed_at":"2021-04-20T22:13:27.000Z","size":141,"stargazers_count":8,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-17T12:17:13.096Z","etag":null,"topics":["api","decorator","django","fast","library","permission","python","rest","restful-api","serializer"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alaouimehdi1995.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-03T13:37:51.000Z","updated_at":"2024-09-03T11:59:45.000Z","dependencies_parsed_at":"2022-08-19T22:41:22.426Z","dependency_job_id":null,"html_url":"https://github.com/alaouimehdi1995/django-rest","commit_stats":null,"previous_names":["alaouimehdi1995/django-flash-rest"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alaouimehdi1995%2Fdjango-rest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alaouimehdi1995%2Fdjango-rest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alaouimehdi1995%2Fdjango-rest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alaouimehdi1995%2Fdjango-rest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alaouimehdi1995","download_url":"https://codeload.github.com/alaouimehdi1995/django-rest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242123501,"owners_count":20075371,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","decorator","django","fast","library","permission","python","rest","restful-api","serializer"],"created_at":"2025-03-06T06:21:18.700Z","updated_at":"2025-03-06T06:21:19.193Z","avatar_url":"https://github.com/alaouimehdi1995.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-REST\n\n[![PyPI version](https://badge.fury.io/py/django-rest.svg)](https://badge.fury.io/py/django-rest)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/django-rest.svg)](https://pypi.python.org/pypi/django-rest/)\n[![PyPI license](https://img.shields.io/pypi/l/django-rest.svg)](https://pypi.python.org/pypi/django-rest/)\n[![PyPI status](https://img.shields.io/pypi/status/django-rest.svg)](https://pypi.python.org/pypi/django-rest/)\n\n[![Build Status](https://travis-ci.org/alaouimehdi1995/django-rest.png?branch=master)](https://travis-ci.org/alaouimehdi1995/django-rest)\n[![codecov](https://codecov.io/gh/alaouimehdi1995/django-rest/branch/master/graph/badge.svg)](https://codecov.io/gh/alaouimehdi1995/django-rest)\n[![Known Vulnerabilities](https://snyk.io/test/github/alaouimehdi1995/django-rest/badge.svg)](https://snyk.io/test/github/alaouimehdi1995/django-rest)\n[![Maintainability](https://api.codeclimate.com/v1/badges/bcfd8d86afef77cf14ab/maintainability)](https://codeclimate.com/github/alaouimehdi1995/django-rest/maintainability)\n\n# Overview\n\ndjango-REST is a **tiny**, **lightweight**, **easy-to-use** and **incredibly fast** library to implement\nREST views with django. The whole library's focused in **one** decorator that transforms the\nsimple views into REST ones, allowing easy customizations (such as permissions, serializers, etc.)\n\nThe library itself was highly inspired from the great [django-rest-framework](https://www.django-rest-framework.org/) and [SerPy](https://serpy.readthedocs.io/en/latest/)\n\n# Table of contents\n\n1. [Overview](#overview)\n2. [Table of contents](#table-of-contents)\n3. [Requirements](#requirements)\n4. [Installation](#installation)\n5. [Example](#example)\n6. [Documentation](#documentation)\n\n   1. [The @api_view decorator](#1-the-api_view-decorator)\n      1. [Decorator argments](#11-decorator-arguments)\n      2. [Decorated view's arguments](#12-decorated-views-arguments)\n      3. [How to decorate a view](#13-how-to-decorate-a-view)\n   2. [View Permissions](#2-view-permissions)\n      1. [Introduction](#21-introduction)\n      2. [Available Permissions](#22-available-permissions)\n      3. [Permissions Operators](#23-permissions-operators)\n      4. [Implement your own permission](#24-implement-your-own-permission)\n   3. [Deserializers](#3-deserializers)\n      1. [Introduction](#31-introduction)\n      2. [Impmement a new Deserializer](#32-implement-a-new-deserializer)\n      3. [Available Deserializer Fields](#33-available-deserializer-fields)\n      4. [Nested Deserializers](#34-nested-deserializers)\n      5. [Post-clean methods](#35-post-clean-methods)\n      6. [All-pass Deserializer](#36-all-pass-deserializer)\n   4. [Serializers](#4-serializers)\n      1. [Introduction](#41-introduction)\n      2. [Impmement a new Serializer](#42-implement-a-new-serializer)\n      3. [Available Serializer Fields](#43-available-serializer-fields)\n         1. [Primitive types](#1-primitive-types)\n         2. [MethodField](#2-methodfield)\n         3. [ConstantField](#3-constantfield)\n         4. [ListField](#4-listfield)\n      4. [Nested Serializers](#44-nested-serializers)\n      5. [DictSerializer](#45-dictserializer)\n   5. [Exceptions](#5-exceptions)\n      1. [@api_view exceptions catching](#51-api_view-exceptions-catching)\n      2. [Existing API Exceptions](#52-existing-api-exceptions)\n      3. [Define your own API Exception](#53-define-your-own-api-exception)\n   6. [HTTP](#6-http)\n      1. [HTTP Status codes](#62-http-status-codes)\n      2. [HTTP Methods](#63-http-methods)\n\n# Requirements\n\ndjango-REST library requires:\n\n-  Python version 2.7+ or 3.3+\n-  django version 1.10+\n\n# Installation\n\nYou can get the package using `pip`, as the following:\n\n```bash\npip install django-rest\n```\n\n# Example\n\nLet's implement a quick public API endpoint that lists existing regular (_i.e._ not staff) users:\n\nFirst, start a new django project:\n\n```sh\npip install django-rest # Will install django if not already installed\ndjango-admin startproject first_project .\n./manage.py migrate\n./manage.py createsuperuser\n# Follow instructions\n```\n\nLet's get started by implementing the views in `./first_project/urls.py`:\n\n```python\nfrom typing import Dict\n\nfrom django.contrib import admin\nfrom django.contrib.auth.models import User\nfrom django.http import JsonResponse\nfrom django.urls import path\n\nfrom django_rest.decorators import api_view\nfrom django_rest.http import status\nfrom django_rest.serializers import fields as fields, Serializer\n\n\n# The serializer defines the output format of our endpoints\nclass UserSerializer(Serializer):\n    id = fields.IntegerField()\n    username = fields.CharField()\n    email = fields.CharField()\n    is_staff = fields.BooleanField()\n\n\n@api_view(allowed_methods=[\"GET\"])\ndef list_users_view(request, url_params: Dict, query_params: Dict, **kwargs):\n    regular_users = User.objects.exclude(is_staff=True)\n    return JsonResponse(\n        UserSerializer(regular_users, many=True).data,\n        status=status.HTTP_200_OK,\n        safe=False,\n    )\n\n\nurlpatterns = [\n    path(\"admin/\", admin.site.urls),\n    path(\"api/users/\", list_users_view),\n]\n```\n\nThat's all! Now run the server:\n\n```sh\n./manage.py runserver\n```\n\nIn order to test your endpoints, you can use [PostMan](https://www.postman.com/), [httpie](https://httpie.org/) or [curl](https://curl.haxx.se/).\nI'll be using `httpie` in the example:\n\n```sh\nhttp GET http://127.0.0.1:8000/api/users/\n\nHTTP/1.1 200 OK\nContent-Length: 84\nContent-Type: application/json\nDate: Sat, 30 May 2020 02:13:49 GMT\nServer: WSGIServer/0.2 CPython/3.6.9\nX-Content-Type-Options: nosniff\nX-Frame-Options: DENY\n\n[]\n\n# After creating a new user from django-admin section (visit: http://127.0.0.1:8000/admin/ using your browser)\n\nhttp GET http://127.0.0.1:8000/api/users/\n\nHTTP/1.1 200 OK\nContent-Length: 84\nContent-Type: application/json\nDate: Sat, 30 May 2020 02:17:23 GMT\nServer: WSGIServer/0.2 CPython/3.6.9\nX-Content-Type-Options: nosniff\nX-Frame-Options: DENY\n\n[\n    {\n        \"email\": \"myfirst@user.com\",\n        \"id\": 1,\n        \"is_staff\": true,\n        \"username\": \"firstuser\"\n    }\n]\n\n```\n\n# Documentation\n\n## 1. The `@api_view` decorator\n\n### 1.1 Decorator arguments\n\nAs shown in the example section, the `@api_view` could be used with multiple\n(optional) arguments:\n\n```python\napi_view(\n    permission_class: BasePermission = AllowAny,\n    allowed_methods: Iterable[str] = ALL_HTTP_METHODS,\n    deserializer_class: Union[\n        Deserializer, Dict[str, Deserializer]\n    ] = AllPassDeserializer,\n    allow_forms: bool = False,\n)\n```\n\n1. **permission_class**\n\n   A class that defines who is allowed to access the\n   decorated view. If no `permission_class` given, the decorator's default permission is\n   `AllowAny` (your view is public).\n\n   In case the user isn't allowed to access the view,\n   a `403 Forbidden access` response will be returned before even executing the\n   view's code. More details in [permissions section](#2-view-permissions).\n\n2. **allowed_methods**:\n\n   A `list`/`tuple` of HTTP allowed methods. Allowed methods should\n   be in uppercase strings (_ex.`GET`, `POST`, etc._). You can also use some\n   predefined sets in `django_rest.http.methods`. If no `allowed_methods`\n   given, all HTTP methods will be allowed.\n\n   If the user requests the decorated view\n   with a non-allowed method, a `405 Method not allowed` response will be\n   returned before executing your view's code.\n\n3. **deserializer_class**:\n\n   Could be either a sub-class of `Deserializer` (as shown in the\n   previous example), or a `dict` that maps HTTP methods that use payload (_i.e._ `POST`, `PUT`\n   and `PATCH`) to `Deserializer` sub-classes, as the following:\n\n   ```python\n   @api_view(deserializer_class=MyDeserializerClass)\n   def first_case_view(request, **kwargs):\n      # [...]\n\n   @api_view(\n      deserializer_class={\n         \"POST\": MyCustomPOSTDeserializer,\n         \"PUT\": MyCustomPUTDeserializer,\n      },\n   )\n   def second_case_view(request, **kwargs):\n      # [...]\n   ```\n\n   In the first case above, `MyDeserializerClass` will be applied to: `POST`,\n   `PUT` and `PATCH` methods. Also, note that in second case, the `deserializer_class` mapping doesn't\n   define a deserializer for the `PATCH` HTTP method. In this case,\n   the \"all-pass\" deserializer (_i.e._ passes payload data to the view without any\n   validation) will be used. The same deserializer will be applied if no\n   `deserializer_class` is given.\n\n   If the payload data doesn't respect the format defined in the deserializer,\n   a `400 Bad Request` response will be returned.\n\n4. **allow_forms**:\n\n   A `bool` that allows/forbids payloads coming from forms (\n   `application/x-www-form-urlencoded` and `multipart/form-data` content-types).\n\n   A `415 Unsupported Media Type` response will be returned in case the user sends form\n   data to a view decorated with `allow_forms=False`. The argument's default value is `False`.\n\n### 1.2 Decorated view's arguments\n\nAs illustrated in the examples above, the `@api_view` decorator alters the\ndecorated view's arguments. The decorator gathers, extracts and standardizes\ndifferent arguments, then passes them to your view, in order to facilitate their\nuse. Let's explain each argument:\n\n```python\n@api_view\ndef decorated_view(\n    request: HttpRequest,\n    url_params: Dict[str, Any],\n    query_params: Dict[str, str],\n    deserialized_data: Optional[Dict[str, Any]],\n) -\u003e JsonResponse:\n   # For class methods, the first argument is `self` (the class instance)\n   # [...]\n```\n\n1. **request**:\n\n   django's native request object (`django.http.request.HttpRequest`). Similar\n   to every django view's first argument.\n   More details on [django's documentation](https://docs.djangoproject.com/en/3.0/ref/request-response/)\n\n2. **url_params**:\n\n   A `dict` containing the parameter defined in your view's\n   route (django router). For example, let's take a look to `url_params` when requesting the URL `/api/hello/foo/bar/25/` in the following example:\n\n   ```python\n   # urls.py\n   from django.urls import path\n   from django_rest.decorators import api_view\n\n   @api_view\n   def hello_view(request, url_params, query_params, **kwargs):\n      #  url_params = {\"first_name\": \"foo\", \"last_name\": \"bar\", \"age\": 25}\n\n   urlpatterns = [\n      path(\"api/hello/\u003cstr:first_name\u003e/\u003cstr:last_name\u003e/\u003cint:age\u003e/\", hello_view),\n   ]\n   ```\n\n   **Important note:** The parameters are already casted into their target types (_in\n   the example above, `url_params['age']` is `int`, while `url_params['first_name']` is `str`_)\n\n3. **query_params**:\n\n   A `dict` containing all the query parameters encoded in the request's URL.\n   Let's request the previous example's view with the following URL:`/api/hello/foo/bar/25/?lang=fr\u0026display=true`:\n\n   ```python\n   # views.py\n   @api_view\n   def hello_view(request, url_params, query_params, **kwargs):\n      #  url_params = {\"first_name\": \"foo\", \"last_name\": \"bar\", \"age\": 25}\n      #  query_params = {\"lang\": \"fr\", \"display\": \"true\"}\n\n   ```\n\n   **Important note:** Unlike `url_params`, for query parameters, the values are **ALWAYS** strings (`str`), and\n   they should be casted manually.\n\n4. **deserialized_data**:\n\n   A `dict` with the data validated by the deserializer. For HTTP\n   methods without payload (`GET`, `DELETE`, _etc._), this argument's value is\n   `None`.\n\n   As explained in the section before, for HTTP methods requiring\n   data, if no `deserializer_class`'s been given to the decorator, `deserialized_data`\n   will contain the raw payload's data (without any validation).\n\n**Note:** In case you want to ignore a argument (let's say `deserialized_data`\nfor a `GET` view), add `**kwargs` argument to your view. Otherwise, you'll have\na arguments error.\n\n### 1.3 How to decorate a view\n\nThe `@api_view` decorator could be applied differently on the views, depending on your use-case. You can:\n\n1. Decorate a function-based view. For example:\n   ```python\n   @api_view(allowed_methods=['GET'])\n   def hello_view(request, **kwargs):\n      return JsonResponse({'message': 'Hello world'}, status=200)\n   ```\n2. Decorate a whole class-based view (should be a sub-class of `django.view.View`). For example:\n\n   ```python\n   @api_view(permission_class=IsStaffUser)\n   class HelloView(View):\n      def get(self, request, **kwargs):\n         return JsonResponse({\"message\": \"Hello world\"}, status=200)\n\n      def post(self, request, **kwargs):\n         return JsonResponse({}, status=201)\n\n      def other_method(self, arg_1, arg_2):\n         # [...]\n   ```\n\n   For class-based views, the decorator decorates all view's http methods\n   (`get()`, `post()`, `put()`, _etc._) and **ONLY** them. In the example above, all http methods are restricted for staff-users only, but `other_method` method hasn't been altered.\n\n**Note:** Both `@api_view()` and `@api_view` syntaxes are correct in case the decorator is used without arguments.\n\n## 2. View Permissions\n\n### 2.1 Introduction\n\nPermissions is what determines whether a request should be granted or denied\naccess, for a particular view. The inspection process is done before executing\nthe decorated view's code, then, if the request satisfies the\npermission's constraints, the access is granted. If not, a `403 Forbidden access`\nresponse is returned.\n\nIn django-REST, all permissions inherit from `Permission`, and passed as argument to the `@api_view` decorator, as seen in\nthe previous examples.\n\nIn this section, we will start by introducing the django-REST's provided\npermissions, then how to build more complex permissions by combining the\nexisting ones, and finally, how to implement your own custom permission.\n\n### 2.2 Available Permissions\n\nAll the permissions listed below could be imported from `django_rest.permissions`\n\n-  **AllowAny**:\n   By choosing this permission, your view will be public (all requests will have granted access). It's the default permission for `@api_view` decorator.\n-  **IsAuthenticated**:\n   Allows only authenticated users to access your view. Anonymous users (_i.e._ not authenticated) receive a `403 Forbidden access` response.\n-  **IsStaffUser**:\n   The view can be accessed by staff users only. A staff user is a `User` object having `is_staff` attribute set to `True`.\n-  **IsAdminUser**:\n   Admins are the only users who can access the decorated view. An admin is a `User` object having `is_superuser` attribute set to `True`.\n-  **IsReadOnly**:\n   Only HTTP safe methods (`GET`, `HEAD` and `OPTIONS`) are allowed. For a `POST` request for example, the user receives a `403 Forbidden access`.\n\n   This permission is not meant to be used in standalone, because, remember, the `@api_view` decorator has already the `allowed_methods` argument for this purpose, that returns a `405 Method not allowed`.\n   It has been implemented only to be combined with other permissions in order to build a more complex ones (the next permission on the list is a good example).\n\n-  **IsAuthenticatedOrReadOnly**:\n   This permission allows Authenticated users to use all HTTP methods (`GET`, `POST`, `DELETE`, _etc._), and anonymous users to use safe methods only (`GET`, `HEAD` and `OPTIONS`).\n\n### 2.3 Permissions Operators\n\nUsing logical operators allows you to combine different `Permission` sub-classes, in a simple and powerful way, to obtain more complex and complete permissions.\n\ndjango-REST provides you 4 logical operators: **AND** (`\u0026`), **OR** (`|`), **XOR** (`^`) and **NOT** (`~`).\n\nLet's demonstrate those operators then their combinations in concrete examples:\n\n1. **AND operator**:\n\nLet's create a new `IsStaffAndReadOnly` permission that grants access to:\n\n-  Staff users, **and** only with reading http methods (`GET`, `HEAD` and `OPTIONS`).\n\nIt will be implemented as the following:\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.permissions import IsReadOnly, IsStaffUser\n\nIsStaffAndReadOnly = IsStaffUser \u0026 IsReadOnly\n\n@api_view(permission_class=IsStaffAndReadOnly)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\n2. **OR operator**:\n\nLet's create a new `IsAdminOrReadOnly` permission granting access to:\n\n-  Admin users with all HTTP methods\n-  Non-admin users with reading http methods (`GET`, `HEAD` and `OPTIONS`) only.\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.permissions import IsAdminUser, IsReadOnly\n\nIsAdminOrReadOnly = IsAdminUser | IsReadOnly\n\n@api_view(permission_class=IsAdminOrReadOnly)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\n3. **XOR (_eXclusive OR_) operator**:\n\nFor this example, let's implement a permission that grants access to:\n\n-  Users that are staff\n-  Users that are **not** admins\n\nNote that this permission could be implemented differently (and in a more\ncorrect and readable way). The use of XOR operator here is for demonstration purpose only.\nThe correct implementation is shown below in \"_5. Combining Operators_\" example.\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.permissions import IsAdminUser, IsStaffUser\n\nIsStaffAndNotAdminUser = IsAdminUser ^ IsStaffUser\n\n@api_view(permission_class=IsStaffAndNotAdminUser)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\n4. **NOT operator**:\n\nLet's consider a view that should be exposed to anonymous (_i.e._ not\nauthenticated) users only. This view's permission will be defined as the following:\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.permissions import IsAuthenticated\n\nAnonymousUserOnly = ~IsAuthenticated\n\n@api_view(permission_class=AnonymousUserOnly)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\n5. **Combining Operators**:\n\nLet's re-implement the `IsStaffAndNotAdminUser` used in the XOR example above, by using\nmultiple operators. Then, we'll re-use it (`IsStaffAndNotAdminUser`) to implement a new\n`IsStaffAndNotAdminUserOrReadOnly`:\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.permissions import IsAdminUser, IsReadOnly, IsStaffUser\n\nIsStaffAndNotAdminUser = IsStaffUser \u0026 (~ IsAdminUser)\n\nIsStaffAndNotAdminUserOrReadOnly = IsStaffAndNotAdminUser | IsReadOnly\n# Or: IsStaffAndNotAdminUserOrReadOnly = (IsStaffUser \u0026 (~ IsAdminUser)) | IsReadOnly\n\n@api_view(permission_class=IsStaffAndNotAdminUserOrReadOnly)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\n### 2.4 Implement your own permission\n\nEven if combining standard permissions covers the most usual use-cases, you may have some unusual constrains that cannot be tackled using existing operators only.\n\ndjango-REST provides you a way to implement a custom permission that fits your needs.\nAll you have to do is inherit from `django_rest.permissions.BasePermission`, then implement the `has_permission()` method.\n\nThe `has_permission()` takes the `request` object, and the target view object as\narguments, and should return a `bool` that represents if the access should be\ngranted (`True`) or not (`False`).\n\n```python\ndef has_permission(self, request: HttpRequest, view:Union[Callable, View]) -\u003e bool:\n```\n\nLet's implement a custom permission that grants access to authenticated users\nhaving `gmail` address only. The \"authenticated users\" part will be taken care\nof using the existing `IsAuthenticated` permission.\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.permissions import BasePermission, IsAuthenticated\n\n\nclass HasGmailAddress(BasePermission):\n    def has_permission(self, request, view):\n        user_email = request.user.email\n        domain_name = user_email.split('@')[1]\n        has_gmail_address = (domain_name == 'gmail.com')\n        return has_gmail_address\n\n\n@api_view(permission_class=IsAuthenticated \u0026 HasGmailAddress)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\n**Important Note:**\n\nWhile using operators, operands order **matters**.\n\nIn the example above, in `HasGmailAddress` code, we assumed that the user is\nalready authenticated, instead of manually checking it. That's because if the permission `IsAuthenticated` isn't satisfied,\ndjango-REST returns a `403 Forbidden access` before even evaluating `HasGmailAddress` permission.\nThat's why in `HasGmailAddress` code, we assumed the user is authenticated.\n\nIf we switched permissions order as the following:\n\n```python\n@api_view(permission_class=HasGmailAddress \u0026 IsAuthenticated)\ndef target_view(request, **kwargs):\n    # [...]\n```\n\nWe should have added a condition in `HasGmailAddress` to verify if the user is\nauthenticated (and therefore, `IsAuthenticated` permission will be useless).\nOtherwise, if an anonymous user requests the view, a `AttributeError: 'NoneType' object has no attribute 'email'` exception will be raised.\n\n## 3. Deserializers\n\n### 3.1. Introduction\n\nIn django-REST, a deserializer validates input data (request payload and/or form data)\nbased on custom fields ans constrains defined in the deserializer class,\nthen \"translates\" data into the target format (Python primitive types), and finally\nexecutes some post-validation methods (if defined).\nIn this chapter, we'll cover how to implement a simple deserializer, what are the\nfields available for use, how to nest deserializers for more complex validation and to post-clean your data,\nand finally, what the `AllPassDeserializer` is.\n\n### 3.2. Implement a new Deserializer\n\nDefining a new `Deserializer` is quite simple. All you need to do is to inherit\nfrom `Deserializer` class:\n\n```python\nfrom django_rest.deserializers import Deserializer\n\n\nclass MyCustomDeserializer(Deserializer):\n    pass\n```\n\nBut, a deserializer class has no purpose without its fields. Let's define\na simple `Deserializer` with 2 fields: a positive integer primary key (`pk`),\nand a `username` (string).\n\n```python\nfrom django_rest.deserializers import fields, Deserializer\n\n\nclass MyCustomDeserializer(Deserializer):\n    pk = fields.IntegerField(min_value=0)  # Implicit required\n    username = fields.CharField(required=True)  # Explicit required\n```\n\nThat's how a `Deserializer` is defined. Now, if you want to use the deserializer\noutside the `@api_view`'s `deserializer_class` argument, you have two approaches to proceed:\n\n#### The first approach\n\n1. Instantiate your deserializer class, passing `data` argument to the\n   constructor.\n2. Check your data validity, by calling `.is_valid()` method.\n3. Retrieve the validated data with `.data` (or errors with `.errors`)\n   attribute.\n\nHere is a simple example:\n\n```python\nfrom django_rest.deserializers import fields, Deserializer\n\n\nclass MyCustomDeserializer(Deserializer):\n    pk = fields.IntegerField(min_value=0)\n    username = fields.CharField(required=True)\n\n\nvalid_input = {'pk': '3', 'username': 'foobar'}\ninvalid_input = {'pk': -3, 'username': 'foobar'}\n\nvalid_instance = MyCustomDeserializer(data=valid_input)\nvalid_instance.is_valid()  # True\nvalid_instance.data  # {'pk': 3, 'username': 'foobar'}\n\ninvalid_instance = MyCustomDeserializer(data=invalid_input)\ninvalid_instance.is_valid()  # False\ninvalid_instance.errors  # {\"pk\": [\"Ensure this value is greater than or equal to 0.\"]}\n```\n\n#### The second approach\n\n1. Instantiate the deserializer class without arguments.\n2. Call the `.clean()` method with the data to validate, it should return the\n   valid data, or raise a `ValidationError` in case the input data is invalid.\n3. Put the clean call inside a `try/except` clause to catch the validation errors.\n\nHere is a simple example:\n\n```python\nfrom django_rest.deserializers import fields, Deserializer, ValidationError\n\n\nclass MyCustomDeserializer(Deserializer):\n    pk = fields.IntegerField(min_value=0)\n    username = fields.CharField(required=True)\n\n\nvalid_input = {'pk': '3', 'username': 'foobar'}\ninvalid_input = {'pk': -3, 'username': 'foobar'}\n\ndeserializer_instance = MyCustomDeserializer()\n\ndeserializer.clean(valid_input)  # {'pk': 3, 'username': 'foobar'}\n\ntry:\n    data = deserializer.clean(invalid_input)\nexcept ValidationError as errors:\n    errors = dict(errors)  # errors = {\"pk\": [\"Ensure this value is greater than or equal to 0.\"]}\n    do_something_with_errors(errors)\nelse:\n    do_something(data)\n```\n\n### 3.3. Available Deserializer Fields\n\ndjango-REST deserializers use native django forms fields. **Depending on the\ndjango version you are using**, you may have access (or not) to some fields, and some of\ntheir attributes. More details on [django's official doc](https://docs.djangoproject.com/en/3.0/ref/forms/fields/).\n\n**Important Note:** You can enjoy **every** feature available in django forms fields, such as\n[custom validators](https://docs.djangoproject.com/en/3.0/ref/validators/) and\n[custom error messages](https://docs.djangoproject.com/en/3.0/ref/forms/fields/#error-messages)\n\n### 3.4 Nested Deserializers\n\ndjango-REST offers support for nesting deserializers, in order to build more complex ones, in a flexible way and without losing readability.\n\nBy nesting deserializers, errors are nested, and output data is a nested `dict`\ntoo. The following example illustrates how to nest deserializers:\n\n```python\nfrom django.core.validators import MinValueValidator, MaxValueValidator\nfrom django_rest.deserializers import fields, Deserializer\n\n\nclass RaceDriverDeserializer(Deserializer):\n    first_name = fields.CharField(required=True)\n    last_name = fields.CharField(required=True)\n    birth_day = fields.DateField()\n\n\nclass RaceCarDeserializer(Deserializer):\n    brand = fields.CharField()\n    model = fields.CharField()\n    production_year = fields.IntegerField(\n        required=False, validators=[MinValueValidator(1900), MaxValueValidator(2020)]\n    )\n    driver = RaceDriverDeserializer(required=True)\n\n\nvalid_data = {\n    \"brand\": \"Mercedes\",\n    \"model\": \"C11\",\n    \"production_year\": \"1990\",\n    \"driver\": {\n        \"first_name\": \"Michael\",\n        \"last_name\": \"Schumacher\",\n        \"birth_day\": \"1969-01-03\",\n    },\n}\n\ndeserializer = RaceCarDeserializer(data=valid_data)\ndeserializer.is_valid()  # True\ndeserializer.data\n\"\"\"\n{\n   'brand': 'Mercedes',\n   'model': 'C11',\n   'production_year': 1880,\n   'driver': {\n      'first_name': 'Michael',\n      'last_name': 'Schumacher',\n      'birth_day': datetime.date(1969, 1, 3),\n   },\n}\n\"\"\"\n\ninvalid_data = {\n    \"brand\": \"Mercedes\",\n    \"production_year\": \"1990\",\n    \"driver\": {\"birth_day\": \"1969-01-03\",},\n}\n\ndeserializer = RaceCarDeserializer(data=invalid_data)\ndeserializer.is_valid()  # False\ndeserializer.errors\n\"\"\"\n{\n   \"model\": [\"This field is required.\"],\n   \"driver\": {\n      \"first_name\": [\"This field is required.\"],\n      \"last_name\": [\"This field is required.\"],\n   }\n}\n\"\"\"\n```\n\nNote that a `Deserializer` is a field too, it can be used the exact same way you use a field (with the [same arguments](https://docs.djangoproject.com/fr/3.0/ref/forms/fields/#core-field-arguments)).\n\n### 3.5. Post-clean methods\n\nA post-clean method is a deserializer's method, specific to a single `Field` and\nthat will be called once the \"standard\" validation is done by the deserializer,\nallowing you to handle this validated value more easily, then return the value\nthat will appear in the output data (that will be given to your view).\nBy convention, their name follows the pattern: `post_clean_\u003cFIELD NAME\u003e`.\n\nFor example, if your deserializer defines a `foo` field as a `CharField()`, and\nyou want that your view receives a custom transformation of that `foo` field (for example, let's\nsay: striping border spaces), the post-clean method for that field should be\nnamed `post_clean_foo()`:\n\n```python\nfrom django_rest.deserializers import fields, Deserializer\n\n\nclass FooDeserializer(Deserializer):\n   foo = fields.CharField(required=True)\n\n   def post_clean_foo(self, cleaned_value):\n      return cleaned_value.strip()\n```\n\n**Important Note:** The post-clean methods are called **only** if the field's standard\nvalidation succeeds. If a `ValidationError` occurs, the post-clean won't be\ndone.\n\n### 3.6 All-pass Deserializer\n\nThe `AllPassDeserializer`, is a particular deserializer that allows all payloads to pass to the view, without\nany validation: No type-casts, no post-clean methods, and more importantly,\nnever raises a `ValidationError` or returns a `400 BadRequest`.\n\nThe `AllPassDeserializer` is the default deserializer used by `@api_view`\ndecorator. (You probably won't need it unless you're dealing with a very unusual\nuse-case)\n\n## 4. Serializers\n\n### 4.1. Introduction\n\nSerializers allow complex data such as querysets and model instances to be\nconverted into native Python data-types, so that they could be easily rendered\ninto JSON. Serializers do the opposite of Deserializers, and intervene at the\n\"return\" statement of your view.\n\n### 4.2. Implement a new Serializer\n\nSimilar to how we've implemented a `Deserializer`, in order to implement your\nown serializer, you have to inherit from `Serializer` class, then define the\nfields that you want to include into your serialized data (probably your view's response). Here is a simple\nexample:\n\n```python\nfrom django.http import JsonResponse\n\nfrom django_rest.decorators import api_view\nfrom django_rest.http import status\nfrom django_rest.serializers import fields, Serializer\n\nfrom .models import Subscription\n\n\nclass SubscriptionSerializer(Serializer):\n    id = fields.IntegerField(required=True)\n    user_id = fields.IntegerField()\n    started_at = fields.CharField(attr_name=\"created\")\n    invoices_urls = fields.ListField(fields.CharField(required=True))\n\n@api_view\ndef subscription_details_view(request, url_params, **kwargs):\n   subscription = Subscription.objects.get(id=url_params[\"subscription_pk\"])\n   return JsonResponse(\n      SubscriptionSerializer(subscription, many=False).data,\n      status=status.HTTP_200_OK,\n   )\n\n```\n\n`Serializer` class accepts 2 arguments:\n\n1. **instance**: The object (or iterable of objects) to be serialized.\n2. **many**: Boolean that tells the `Serializer` if the object is iterable or not. If\n   `many=True`, the serialized data will be a `list` of serialized elements of\n   the `instance` iterable. Its set by default to `False`.\n\n### 4.3. Available Serializer Fields\n\nSerializers fields are very limited, because, remember that the data will be converted\ninto native Python data-types (that are limited too). Besides primitive fields (`CharField`,\n`IntegerField`, `FloatField`, `BooleanField`), django-REST provides 3 additional\nfields to use within `Serializers`: `ListField`, `ConstantField` and `MethodField` (and the nested\nserializers). Let's dive into existing fields details.\n\n**Note** In order to simplify the wording in this section, \"field\" word refers\nto the serializer's field, and \"attribute\" word to an attribute of the object\nto serialize.\n\n#### 1. Primitive types\n\nThe primitive types are serializer's fields that cast your data into Python's\nnative data-types: `str`, `int`, `float` and `bool`. The `CharField`,\n`IntegerField`, `FloatField` and `BooleanField` accept the **same** arguments:\n\n```python\nBooleanField(attr_name: str = None, label: str = None, call: bool = False, required: bool = True)\nCharField(attr_name: str = None, label: str = None, call: bool = False, required: bool = True)\nFloatField(attr_name: str = None, label: str = None, call: bool = False, required: bool = True)\nIntegerField(attr_name: str = None, label: str = None, call: bool = False, required: bool = True)\n```\n\n1. **attr_name**: It refers to the object's attribute that should be binded to the\n   current field. The default value is the field name. For example:\n\n   ```python\n   class Example:\n       def __init__(self, foo, bar):\n          self.foo = foo\n          self.bar = bar\n\n   class ExampleSerializer(Serializer):\n       foo = fields.IntegerField()  # if `attr_name` is omitted, this field will lookup for your object's `.foo` attribute value\n       whatever = fields.CharField(attr_name=\"bar\")  # this field will store your object's `.bar` attribute's value\n\n   ExampleSerializer(Example(foo=3, bar=\"test\")).data  # {'foo': 3, 'whatever': 'test'}\n   ```\n\n2. **label**: It's the name you want to give to your field in the serialized object.\n   If omitted, it preserves the field's name. For the same `Example` class defined above, let's use `label` attribute:\n\n   ```python\n\n   class ExampleSerializer(Serializer):\n       foo = fields.IntegerField(label='integerFoo')\n       whatever = fields.CharField(attr_name='bar', label='textBar')\n\n   ExampleSerializer(Example(foo=3, bar=\"test\")).data  # {'integerFoo': 3, 'textBar': 'test'}\n   ```\n\n3. **call**: If set to `True`, the serializer will try to execute (call)\n   your attribute. This is useful when the attribute referred-to is a method. Here is a quick example:\n\n   ```python\n   class Example:\n       def __init__(self, foo):\n           self.foo = foo\n\n       def _get_text(self):\n           return \"Hello\"\n\n       def bar(self):\n           return self._get_text() + \" World!\"\n\n   class ExampleSerializer(Serializer):\n       foo = fields.IntegerField()\n       whatever = fields.CharField(attr_name=\"bar\", call=True)  # 'bar' is callable\n\n   ExampleSerializer(Example(foo=3)).data  # {'foo': 3, 'whatever': 'Hello World!'}\n   ```\n\n4. **required**: When set to `True`, if the serializer fails to\n   retrieve the attribute's value, or to convert it into the target type, a `SerializationError` will be raised.\n   If the fields isn't required (`required=False`), in case the serializer fails to render the attribute's value,\n   the field won't be added to the final result. If we take the same `Example` class from the previous examples:\n\n   ```python\n   class Example:\n       def __init__(self, foo, bar):\n           self.foo = foo\n           self.bar = bar\n\n   class ExampleSerializer(Serializer):\n       foo = fields.IntegerField()\n       bar = fields.IntegerField(required=True)  # Trying to fit a string into `IntegerField`\n\n   ExampleSerializer(Example(foo=3, bar=\"test\")).data  # raises a `SerializationError`\n\n   class ExampleSerializer(Serializer):\n       foo = fields.IntegerField()\n       bar = fields.IntegerField(required=False)  # Trying to fit a string into `IntegerField`\n\n   ExampleSerializer(Example(foo=3, bar=\"test\")).data  # {'foo': 3}\n   ```\n\n#### 2. MethodField\n\nThere are some situations in which you'd need a calculated value (from one or multiple attributes),\nwithout polluting your view, nor your model with a new method.\nIn that case, `MethodField` could be very useful. By defining a `MethodField`,\nyou have to define a method in your `Serializer`, that receives your object as\ninput, and has to return the value to be rendered\n\n**Note** `MethodField` is very similar to a deserializer's post-clean method,\nthe only difference is that the post-clean receives the attribute's value,\nwhile the `MethodField` receives the whole object.\n\nHere is a simple example that illustrates how `MethodField` works:\n\n```python\nfrom django_rest.serializers import fields, Serializer\n\nTAX_RATE = 20\n\nclass PricingExample:\n    def __init__(self, initial_price):\n        self.initial_price = initial_price\n\nclass PricingSerializer(Serializer):\n    initial_price = fields.FloatField()\n    final_price = fields.MethodField(method_name=\"calculate_final_price\", required=True)\n\n    def calculate_final_price(self, obj: PricingExample):\n        tax_price = obj.initial_price * (TAX_RATE / 100)\n        return obj.initial_price + tax_price\n\nPricingSerializer(PricingExample(initial_price=200)).data  # {'initial_price': 200.0, 'final_price': 240.0}\n```\n\n`MethodField` accepts 3 arguments:\n\n```python\nMethodField(label: str = None, required: bool = True, method_name: str = None)\n```\n\n1. **label**: The same as [primitive fields](#1-primitive-types) `label`.\n2. **required**: The same as [primitive fields](#1-primitive-types) `label`.\n3. **method_name**: The name of the serializer's method that should be\n   called. The default value is `get_\u003cSerializer's field name\u003e` (in the previous\n   example, if `method_name` was not given, the method should have been renamed\n   `get_final_price(self, obj)`)\n\n**Important note:** The `MethodField`'s method should return native Python\ndata-types (`str`, `bool`, `int`, `float`, `None`) or (nested) `list`/`dict` of native types.\n\n#### 3. ConstantField\n\n`ConstantField` allows you to include constant data in your response, without\nhaving to include that constant in your model. In the previous example,\n`TAX_RATE` was a constant. In case we wanted to include it in the serialized\ndata, we should had defined it as `PricingExample` class/instance attribute, or\ncreated a `MethodField` that returns a constant. Both solutions are quite\n\"painful\". Using `ConstantField`, the code will look like:\n\n```python\nfrom django_rest.serializers import fields, Serializer\n\nTAX_RATE = 20\n\nclass PricingExample:\n    def __init__(self, initial_price):\n        self.initial_price = initial_price\n\nclass PricingSerializer(Serializer):\n    initial_price = fields.FloatField()\n    final_price = fields.MethodField(method_name=\"calculate_final_price\", required=True)\n    tax_rate = fields.ConstantField(constant=TAX_RATE)\n\n    def calculate_final_price(self, obj: PricingExample):\n        tax_price = obj.initial_price * (TAX_RATE / 100)\n        return obj.initial_price + tax_price\n\nPricingSerializer(PricingExample(initial_price=200)).data  # {'initial_price': 200.0, 'final_price': 240.0, 'tax_rate': 20}\n```\n\n`ConstantField` accepts 3 arguments:\n\n```python\nConstantField(label: str = None, required: bool = True, constant: Any = None)\n```\n\n1. **label**: The same as [primitive fields](#1-primitive-types) `label`.\n2. **required**: The same as [primitive fields](#1-primitive-types) `label`.\n3. **constant**: The constant to be included in the serialized object. The\n   constant **should be** primitive (i.e. `str`, `bool`, `int`, `float`, `None`\n   or combinations -`list`/`dict`- of them), otherwise `SerializationError` will\n   be raised (unless `required` is set to `False`, in that case, the field won't figure\n   in the rendered object).\n\n#### 4. ListField\n\n`ListField` allows you to serialize iterables of primitives. Let's say your\nobject's attribute is a list of integers. With a simple `IntegerField`, you\nwon't be able to serialize that field. It could be achieved with `MethodField`,\nbut it will be too much written code for a trivial thing. `ListField` does the\nsame thing as the `many=True` for `Serializer` class, but the `many` argument\nisn't implemented for `IntegerField`, `BooleanField`, `FloatField` and\n`CharField` for performance purpose.\nThe `ListField` accepts a single argument which is the field to be rendered as list.\n\n```python\nListField(Union[BooleanField, CharField, FloatField, IntegerField])\n```\n\nHere is a simple example:\n\n```python\nfrom django_rest.serializers import fields, Serializer\n\n\nclass Path:\n   def __init__(self):\n      self.x_coordinates = [1.0, 1.2, 1.5, 1.8, 2.3, 8.6]\n      self.y_coordinates = [19.0, 20.9, 30.1, 15.0, 22.3, 5.0]\n\n\nclass PathSerializer(Serializer):\n   xs = fields.ListField(\n      fields.FloatField(label='path_xs', attr_name='x_coordinates', required=True)\n   )\n   ys = fields.ListField(\n      fields.FloatField(label='path_ys', attr_name='y_coordinates', required=True)\n   )\n\nPathSerializer(Path()).data  # {'path_xs': [1.0, 1.2, 1.5, 1.8, 2.3, 8.6], 'path_ys': [19.0, 20.9, 30.1, 15.0, 22.3, 5.0]}\n```\n\n### 4.4. Nested Serializers\n\nSimilarly to `Deserializer`, `Serializer` sub-classes could be nested (i.e.\nusing `Serializer` sub-class as a serializer's field). Here is a simple example\nthat shows how to nest serializers:\n\n```python\nfrom datetime import datetime\n\nfrom django_rest.serializers import fields, Serializer\n\n\nclass Invoice:\n    def __init__(self, id, date):\n        self.id = id\n        self.created_at = date\n\n\nclass Subscription:\n    def __init__(self):\n        self.name = \"foo bar subscription\"\n        self.invoices = [Invoice(id=i, date=datetime.now()) for i in range(10)]\n\n\nclass InvoiceSerializer(Serializer):\n    id = fields.IntegerField()\n    created = fields.CharField(attr_name=\"created_at\")\n\n\nclass SubscriptionSerializer(Serializer):\n    name = fields.CharField()\n    invoices = InvoiceSerializer(many=True)\n\n\nSubscriptionSerializer(instance=Subscription()).data  # {'name': 'foo bar subscription', 'invoices': [{'id': 0, 'created': '2020-06-08 15:26:15.414524'}, ..., {'id': 9, '2020-06-08 15:26:15.93843'}]}\n```\n\n### 4.5. DictSerializer\n\nA `DictSerializer` is a sub-class of `Serializer` (it means that it's\na particular serializer), that, instead of taking an object (class\ninstance) as input, it takes a `dict`. The `DictSerializer` transforms a `dict`\ninto another `dict`. It accepts the same fields as the classic serializer.\nHere is the previous example, rewritten using `DictSerializer` (to show the\ndifference):\n\n```python\nfrom datetime import datetime\n\nfrom django_rest.serializers import fields, DictSerializer\n\n\nsubscription = {\n    \"name\": \"foo bar subscription\",\n    \"invoices\": [\n        {\"id\": 0, \"created_at\": \"2020-06-08 15:26:15.414524\"},\n        {\"id\": 9, \"created_at\": \"2020-06-08 15:26:15.93843\"},\n    ],\n}\n\n\nclass InvoiceSerializer(DictSerializer):\n    id = fields.IntegerField()\n    created = fields.CharField(attr_name=\"created_at\")\n\n\nclass SubscriptionSerializer(DictSerializer):\n    name = fields.CharField()\n    invoices = InvoiceSerializer(many=True)\n\n\nSubscriptionSerializer(instance=subscription).data  # {'name': 'foo bar subscription', 'invoices': [{'id': 0, 'created': '2020-06-08 15:26:15.414524'}, ..., {'id': 9, '2020-06-08 15:26:15.93843'}]}\n```\n\n## 5. Exceptions\n\n### 5.1. `@api_view` exceptions catching\n\nThe `@api_view` decorator catches exceptions for you in case you did not, and returns a JSON response with the correct status code.\nIf the raised exception is a sub-class of `django_rest.http.exceptions.BaseAPIException`, a custom message and status code will be returned.\nIf it's not the case, the returned JSON response will have `\"An unknown server error occured.\"` as message, and `500` as status code.\n\nBy raising one of the [existing API exceptions](#52-existing-api-exceptions) (or\n[defining your own](#53-define-your-own-api-exception)), the decorator will\nreturn the response with the correct message (and status code). This approach\nensures that:\n\n1. Your responses are standardized in all your decorated views: always the same message and status code for the same situations.\n2. Your view's code is lighter (dropping all the useless `try/except` clauses).\n\nHere is a simple example of a view that receives `url_params`, calls a `find_results()` function, and returns a `404` in case there is no result:\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.http.exceptions import NotFound\n\n@api_view\ndef user_custom_view(request, url_params, **kwargs):\n    results = find_results(**url_params)\n    if results is None or len(results) == 0:\n        raise NotFound\n\n    # In case the `find_results()` returned non-empty results:\n    # [....]\n```\n\n### 5.2. Existing API Exceptions\n\nAs seen in the previous chapter, django-REST provides you some custom exceptions that you can use (_i.e._ raise) so that your view returns an error response,\nwithout having to do it manually everytime. Here is the list of the available API exceptions , each with its returned object and status code:\n\n-  **BadRequest**:\n\n   Response message: _\"Bad request.\"_ - status code: `400`\n\n-  **NotAuthenticated**:\n\n   Response message: _\"Unauthorized operation. Maybe forgot the authentication step ?\"_ - status code: `401`\n\n-  **PermissionDenied**:\n\n   Response message: _\"Forbidden operation. Make sure you have the right permissions.\"_ - status code: `403`\n\n-  **NotFound**:\n\n   Response message: _\"The requested resource is not found.\"_ - status code: `404`\n\n-  **MethodNotAllowed**:\n\n   Response message: _\"HTTP Method not allowed.\"_ - status code: `405`\n\n-  **UnsupportedMediaType**:\n\n   Response message: _\"Unsupported Media Type. Check your request's Content-Type.\"_ - status code: `415`\n\n*  **InternalServerError**:\n\n   Response message: _\"An unknown server error occured.\"_ - status code: `500`\n\n*  **ServiceUnavailable**:\n\n   Response message: _\"The requested service is unavailable.\"_ - status code: `502`\n\n### 5.3. Define your own API Exception\n\nIn order to define your own API Exception, all you have to do is inheriting from\n`django_rest.http.exceptions.BaseAPIException` (or one of its sub-classes), then override its `STATUS_CODE` and `RESPONSE_MESSAGE` attributes.\n\nHere is a simple example that shows how to define a [conflict](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409) exception:\n\n```python\nfrom django_rest.decorators import api_view\nfrom django_rest.http import exceptions, status\n\nclass Conflict(exceptions.BaseAPIException):\n    STATUS_CODE = status.HTTP_409_CONFLICT\n    RESPONSE_MESSAGE = \"Requests conflict.\"\n\n@api_view\ndef my_conflicting_view(request, **kwargs):\n    # [...]\n    if some_condition_is_satisfied:\n        raise Conflict  # returns JsonResponse({'error_msg': 'Requests conflict.'}, status=409)\n    # [....]\n```\n\n## 6. HTTP\n\ndjango-REST provides some constants/enumerations that allow you to avoid using\nhard-coded values (`str` for HTTP methods, and `int` for status codes), and\nimprove your code readability.\n\n### 6.1. HTTP Status codes\n\nThe HTTP status codes can be imported from `django_rest.http.status`:\n\n```python\nfrom django_rest.http.status import HTTP_200_OK\n\nresponse_status = HTTP_200_OK\n\n# OR\nfrom django_rest.http import status\n\nresponse_status = status.HTTP_200_OK\n\n```\n\nHere is the exhaustive list of http status constants provided by django-REST\n(more details about status codes [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)):\n\n-  `HTTP_100_CONTINUE`\n-  `HTTP_101_SWITCHING_PROTOCOLS`\n-  `HTTP_200_OK`\n-  `HTTP_201_CREATED`\n-  `HTTP_202_ACCEPTED`\n-  `HTTP_203_NON_AUTHORITATIVE_INFORMATION`\n-  `HTTP_204_NO_CONTENT`\n-  `HTTP_205_RESET_CONTENT`\n-  `HTTP_206_PARTIAL_CONTENT`\n-  `HTTP_207_MULTI_STATUS`\n-  `HTTP_208_ALREADY_REPORTED`\n-  `HTTP_226_IM_USED`\n-  `HTTP_300_MULTIPLE_CHOICES`\n-  `HTTP_301_MOVED_PERMANENTLY`\n-  `HTTP_302_FOUND`\n-  `HTTP_303_SEE_OTHER`\n-  `HTTP_304_NOT_MODIFIED`\n-  `HTTP_305_USE_PROXY`\n-  `HTTP_306_RESERVED`\n-  `HTTP_307_TEMPORARY_REDIRECT`\n-  `HTTP_308_PERMANENT_REDIRECT`\n-  `HTTP_400_BAD_REQUEST`\n-  `HTTP_401_UNAUTHORIZED`\n-  `HTTP_402_PAYMENT_REQUIRED`\n-  `HTTP_403_FORBIDDEN`\n-  `HTTP_404_NOT_FOUND`\n-  `HTTP_405_METHOD_NOT_ALLOWED`\n-  `HTTP_406_NOT_ACCEPTABLE`\n-  `HTTP_407_PROXY_AUTHENTICATION_REQUIRED`\n-  `HTTP_408_REQUEST_TIMEOUT`\n-  `HTTP_409_CONFLICT`\n-  `HTTP_410_GONE`\n-  `HTTP_411_LENGTH_REQUIRED`\n-  `HTTP_412_PRECONDITION_FAILED`\n-  `HTTP_413_REQUEST_ENTITY_TOO_LARGE`\n-  `HTTP_414_REQUEST_URI_TOO_LONG`\n-  `HTTP_415_UNSUPPORTED_MEDIA_TYPE`\n-  `HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE`\n-  `HTTP_417_EXPECTATION_FAILED`\n-  `HTTP_418_IM_A_TEAPOT`\n-  `HTTP_422_UNPROCESSABLE_ENTITY`\n-  `HTTP_423_LOCKED`\n-  `HTTP_424_FAILED_DEPENDENCY`\n-  `HTTP_426_UPGRADE_REQUIRED`\n-  `HTTP_428_PRECONDITION_REQUIRED`\n-  `HTTP_429_TOO_MANY_REQUESTS`\n-  `HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE`\n-  `HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS`\n-  `HTTP_500_INTERNAL_SERVER_ERROR`\n-  `HTTP_501_NOT_IMPLEMENTED`\n-  `HTTP_502_BAD_GATEWAY`\n-  `HTTP_503_SERVICE_UNAVAILABLE`\n-  `HTTP_504_GATEWAY_TIMEOUT`\n-  `HTTP_505_HTTP_VERSION_NOT_SUPPORTED`\n-  `HTTP_506_VARIANT_ALSO_NEGOTIATES`\n-  `HTTP_507_INSUFFICIENT_STORAGE`\n-  `HTTP_508_LOOP_DETECTED`\n-  `HTTP_509_BANDWIDTH_LIMIT_EXCEEDED`\n-  `HTTP_510_NOT_EXTENDED`\n-  `HTTP_511_NETWORK_AUTHENTICATION_REQUIRED`\n\nBesides, you also have (in the same module `django_rest.http.status`) 5 functions that you can use to verify\na status code category easily:\n\n-  `is_informational(code: int) -\u003e bool`\n-  `is_success(code: int) -\u003e bool`\n-  `is_redirect(code: int) -\u003e bool`\n-  `is_client_error(code: int) -\u003e bool`\n-  `is_server_error(code: int) -\u003e bool`\n\n### 6.2. HTTP Methods\n\nAll the following HTTP method's related constants can be found in\n`django_rest.http.methods`:\n\n**String constants:**\n\n-  `HEAD`\n-  `GET`\n-  `POST`\n-  `PUT`\n-  `PATCH`\n-  `DELETE`\n-  `OPTIONS`\n-  `TRACE`\n-  `CONNECT`\n\n**Tuple constants:**\n\n-  `SAFE_METHODS` = (`GET`, `HEAD`, `OPTIONS`)\n-  `SUPPORTING_PAYLOAD_METHODS` = (`POST`, `PUT`, `PATCH`)\n-  `ALL_METHODS` = (`HEAD`, `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `TRACE`, `CONNECT`)\n\n\u003cp align=\"center\"\u003e\u0026mdash; Made with :hearts: \u0026mdash;\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falaouimehdi1995%2Fdjango-rest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falaouimehdi1995%2Fdjango-rest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falaouimehdi1995%2Fdjango-rest/lists"}