worf


Nameworf JSON
Version 0.5.30 PyPI version JSON
download
home_pagehttps://github.com/gundotio/worf
SummaryWade's own REST Framework: A more Djangonic approach to REST APIs
upload_time2023-10-13 18:14:16
maintainer
docs_urlNone
authorWade Williams
requires_python>=3.9,<4.0
licenseMIT
keywords django rest framework api
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            Worf
====

[![build-status-image]][build-status]
[![pypi-version]][pypi]

Worf is a small Django API framework for building out REST APIs simply using
class-based views and serializers.

[![Worf](https://i.kym-cdn.com/photos/images/newsfeed/001/231/196/e18.jpg)][worf-docs]

Full documentation for the project is available at [https://memory-alpha.fandom.com/wiki/Worf][worf-docs].

[worf-docs]: https://memory-alpha.fandom.com/wiki/Worf


Table of contents
-----------------

- [Installation](#installation)
- [Requirements](#requirements)
- [Roadmap](#roadmap)
- [Usage](#usage)
- [Serializers](#serializers)
- [Permissions](#permissions)
- [Validators](#validators)
- [Views](#views)
  - [ListAPI](#listapi)
  - [DetailAPI](#detailapi)
  - [CreateAPI](#createapi)
  - [UpdateAPI](#updateapi)
  - [ActionAPI](#actionapi)
  - [DeleteAPI](#deleteapi)
- [Browsable API](#browsable-api)
- [Bundle loading](#bundle-loading)
- [Debugging](#debugging)
- [Field casing](#field-casing)
- [File uploads](#file-uploads)
- [Internal naming](#internal-naming)
- [Settings](#settings)
- [Credits](#credits)


Installation
------------

Install using pip:

```sh
pip install worf
```

Add `worf` to your `INSTALLED_APPS` setting:

```py
INSTALLED_APPS = [
    ...
    "worf",
]
```


Requirements
------------

- Python (3.9, 3.10, 3.11)
- Django (3.2, 4.0, 4.1)


Roadmap
-------

- [x] Abstracting serializers away from model methods
- [x] Browsable API
- [x] Declarative marshmallow-based serialization
- [x] File upload support
- [x] Support for PATCH/PUT methods
- [ ] Better test coverage
- [ ] Documentation generation
- [ ] Support for user-generated validators


Usage
-----

The following examples provides you with an API that does the following:

- Only allows authenticated users to access the endpoints
- Provides a list of books, with `POST` support to create a new book
- Provides an endpoint for each book's detail endpoint, with `PATCH` support

A more complete example will demonstrate the additional built-in capabilities,
including search, pagination, ordering, and the other things Worf can do.

```py
# models.py
class Book(models.Model):
    title = models.CharField(max_length=128)
    author_name = models.CharField(max_length=128)
    published_at = models.DateField()
```

```py
# serializers.py
from worf.serializers import Serializer

class BookSerializer(Serializer):
    class Meta:
        fields = [
            "id",
            "title",
            "author_name",
            "published_at",
        ]
```

```py
# views.py
from worf.permissions import Authenticated
from worf.views import ActionAPI, DeleteAPI, DetailAPI, ListAPI, UpdateAPI

class BookList(CreateAPI, ListAPI):
  model = Book
  serializer = BookSerializer(only=["id", "title"])
  permissions = [Authenticated]

class BookDetail(ActionAPI, DeleteAPI, UpdateAPI, DetailAPI):
  model = Book
  serializer = BookSerializer
  permissions = [Authenticated]
  actions = ["publish"]
```

```py
# urls.py
path("api/", include([
    path("books/", BookList.as_view()),
    path("books/<int:id>/", BookDetail.as_view()),
    path("books/<int:id>/<str:action>/", BookDetail.as_view()),
])),
```

Serializers
-----------

Worf serializers are basically [marshmallow schemas](https://marshmallow.readthedocs.io/)
with some tweaks to improve support for Django models, and supply extra defaults.

```py
from worf.serializers import fields, Serializer

class BookSerializer(Serializer):
    author = fields.Nested(AuthorSerializer)
    tags = fields.Nested(TagSerializer, many=True)

    class Meta:
        fields = [
            "id",
            "title",
            "content",
            "image",
            "url",
            "author",
            "tags",
        ]
```

Worf serializers build on top of marshmallow to make them a little easier to use
in Django, primarily, we add support for using the `Nested` field with related
managers, and setting default serializer options via settings:

```py
WORF_SERIALIZER_DEFAULT_OPTIONS = {
    "dump_only": [
        "id",
        "created_at",
        "deleted_at",
        "updated_at",
    ]
}
```

Permissions
-----------

Permissions are callable classes that can be found in `worf.permissions`, they're passed
the `request` and `kwargs` from the view, and raise an exception if the check fails.


Validators
-----------

Validation handling can be found in `worf.validators`.

The basics come from `ValidateFields` which `AbstractBaseAPI` inherits from, it
performs some coercion on `self.bundle`, potentially resulting in a different
bundle than what was originally passed to the view.


Views
-----

### AbstractBaseAPI

Provides the basic functionality of API views.

| Name        | Type   | Default | Description                   |
| ----------- | ------ | ------- | ----------------------------- |
| model       | class  | None    | Model class.                  |
| permissions | list   | []      | List of permissions classes.  |
| serializer  | object | None    | Serializer class or instance. |

**Note:** it is not recommended to use this abstract view directly.


### ListAPI

| Name              | Type      | Default             | Description                                                                            |
| ----------------- | --------- | ------------------- | -------------------------------------------------------------------------------------- |
| queryset          | object    | model.objects.all() | Queryset used to retrieve the results.                                                 |
| lookup_field      | str       | None                | Filter `queryset` based on a URL param, `lookup_url_kwarg` is required if this is set. |
| lookup_url_kwarg  | str       | None                | Filter `queryset` based on a URL param, `lookup_field` is required if this is set.     |
| payload_key       | str       | verbose_name_plural | Use in order to rename the key for the results array.                                  |
| ordering          | list      | []                  | Fields to default the queryset order by.                                               |
| filter_fields     | list      | []                  | Fields to support filtering via query params.                                          |
| include_fields    | dict/list | []                  | Fields to support optionally including via the `include` query param.                  |
| search_fields     | list      | []                  | Fields to full text search via the `q` query param.                                    |
| sort_fields       | list      | []                  | Fields to support sorting via the `sort` query param.                                  |
| per_page          | int       | 25                  | Number of results returned for each page.                                              |
| max_per_page      | int       | per_page            | Max number of results to allow when passing the `perPage` query param.                 |

The `get_queryset` method will use `lookup_url_kwarg` and `lookup_field` to filter results.
You _should_ not need to override `get_queryset`. Instead, set the optional variables
listed above to configure the queryset.

#### Filtering

Parameters in the URL must be camelCase and exactly match the snake_case model field.

To allow full text search, set to a list of fields for django filter lookups.

For a full list of supported lookups see https://django-url-filter.readthedocs.io.

#### Include fields

Include fields is a list of fields to include when `?include=skills,team` is passed.

If passing a dict the values are passed through to either `prefetch_related` or `select_related`.

```py
class ProfileList(CreateAPI, ListAPI):
    model = Profile
    include_fields = {
        "skills": Prefetch("skills"),
        "team": "team",
    }
```

#### Search fields

Search fields is a list of fields that are used for `icontains` lookups via `?q=`.

The `?search=id,name` query param can be used to filter `search_fields`.

#### Pagination

All ListAPI views are paginated and include a `pagination` json object.

Use `per_page` to set custom limit for pagination. Default 25.

### DetailAPI

| Name                | Type   | Default             | Description                                                |
| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |
| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |
| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |
| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |

This `get_instance()` method uses `lookup_field` and `lookup_url_kwargs` to return a model instance.

You _may_ prefer to override this method, for example in a case when you are using
`request.user` to return an instance.

### CreateAPI

| Name                | Type   | Default             | Description                                                |
| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |
| create_serializer   | object | serializer          | Serializer class or instance.                              |

Adds a `post` method to handle creation, mix this into a `ListAPI` view:

```py
class BookListAPI(CreateAPI, ListAPI):
    model = Book
    serializer = BookSerializer
```

Validation of creates is kind of sketchy right now, but the idea is that you'd
use the same serializer as you would for an update, unless you have `create-only`
fields, in which case, you may want to create a `BookCreateSerializer`.

### UpdateAPI

| Name                | Type   | Default             | Description                                                |
| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |
| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |
| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |
| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |
| update_serializer   | object | serializer          | Serializer class or instance.                              |

Adds `patch` and `put` methods to handle updates, mix this into a `DetailAPI`.

```py
class BookDetailAPI(UpdateAPI, DetailAPI):
    model = Book
    serializer = BookSerializer
```

Validation of update fields is delegated to the serializer, any fields that are
writeable should be within the `fields` definition of the serializer, and not
marked as `dump_only` (read-only).

### ActionAPI

| Name                | Type   | Default             | Description                                                |
| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |
| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |
| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |
| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |
| actions             | list   | []                  | List of action methods to support.                         |

Adds `put` endpoints keyed by a route param, mix this into a `DetailAPI` view:

```py
class BookDetailAPI(ActionAPI, DetailAPI):
    model = Book
    serializer = BookSerializer
    actions = ["publish"]
```

Actions must exist as a method on either the model or the view, they are passed the
contents of the bundle as kwargs, and if the method accepts a `user` kwarg then
`request.user` will be passed through too.

### DeleteAPI

| Name                | Type   | Default             | Description                                                |
| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |
| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |
| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |
| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |

Adds a `delete` method to handle deletes, mix this into a `DetailAPI`.

```py
class BookDetailAPI(DeleteAPI, DetailAPI):
    model = Book
```

Deletes return a 204 no content response, no serializer is required.


Browsable API
-------------

Similar to other popular REST frameworks; Worf exposes a browsable API which adds
syntax highlighting, linkified URLs and supports Django Debug Toolbar.

To override the default browser behaviour pass `?format=json`, or [disable the
feature entirely from settings](#settings).

### Theme

The theme is built with [Tailwind](https://tailwindcss.com/), making it easy to customize the look-and-feel.

For quick and easy branding, there are a couple of [settings that tweak the navbar](#settings).

To customize the markup create a template called `worf/api.html` that extends from `worf/base.html`:

```django
# templates/worf/api.html
{% extends "worf/base.html" %}

{% block branding %}
    {{ block.super }}
    <div>A warrior's drink!</div>
{% endblock %}
```

All of the blocks available in the base template can be used in your `api.html`.

| Name     | Description                     |
| -------- | ------------------------------- |
| body     | The entire html `<body>`.       |
| branding | Branding section of the navbar. |
| script   | JavaScript files for the page.  |
| style    | CSS stylesheets for the page.   |
| title    | Title of the page.              |

For more advanced customization you can choose not to have `api.html` extend `base.html`.


Bundle loading
--------------

The `dispatch` method is run by Django when the view is called. In our version
of dispatch, we interpret any `request.body` as JSON, and convert all values
from camel to snake case at that time. You'll always be able to access bundle
attributes by their snake case variable name, and these attributes will exactly
match the model fields.

`self.bundle` is set on a class level, it is available to all methods inside
the view. We perform type coercion during validation, so `self.bundle` will
be changed during processing. You may also append or remove attributes to the
bundle before saving the object via `post`, `patch`, or other methods.


Debugging
---------

Worf exposes the parsed bundle, lookup kwargs and skips some exception handling
[when in debug mode](#settings).


Field casing
------------

Worf expects all your model fields to be defined in snake case 🐍, and JSON
objects to be camel case 🐪 and that conversion is handled in `worf.casing`.

We interpret camelCase, _strictly_, based on the database model. This means that
inappropriate naming of database fields will result in confusion.

A quick example:

```py
freelance_fulltime = models.CharField(...)
freelancer_id = models.UUIDField(...)
API_strict = ...
```

This will be strictly translated by the API, and acronyms are not considered:

- `freelance_fulltime == freelanceFulltime`
- `freelancer_id == freelancerId`
- `API_strict == apiStrict`


File uploads
------------

File uploads are supported via `multipart/form-data` requests.


Internal naming
---------------

We refer to the json object that is sent and received by the API differently in
this codebase for clarity:

- `bundle` is what we send to the backend.
- `payload` is what the backend returns.


Settings
--------

| Name               | Default        | Description                         |
| ------------------ | -------------- | ----------------------------------- |
| WORF_API_NAME      | Worf API       | See [Browsable API](#browsable-api) |
| WORF_API_ROOT      | /api/          | See [Browsable API](#browsable-api) |
| WORF_BROWSABLE_API | True           | See [Browsable API](#browsable-api) |
| WORF_DEBUG         | settings.DEBUG | See [Debugging](#debugging)         |



Credits
-------

~Wanted dead or alive~ Made with 🥃 at [Gun.io][gun.io]

<a href="https://github.com/gundotio/worf/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=gundotio/worf" alt="Contributors">
</a>

[build-status-image]: https://github.com/gundotio/worf/actions/workflows/ci.yml/badge.svg
[build-status]: https://github.com/gundotio/worf/actions/workflows/ci.yml
[gun.io]: https://www.gun.io
[pypi-version]: https://img.shields.io/pypi/v/worf.svg?color=blue
[pypi]: https://pypi.org/project/worf/


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/gundotio/worf",
    "name": "worf",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9,<4.0",
    "maintainer_email": "",
    "keywords": "django,rest,framework,api",
    "author": "Wade Williams",
    "author_email": "wade@wadewilliams.com",
    "download_url": "https://files.pythonhosted.org/packages/d8/e7/731f8f81f1346d98dfc3e53dafc2949f7dc1643e93d74060f83b7d251d99/worf-0.5.30.tar.gz",
    "platform": null,
    "description": "Worf\n====\n\n[![build-status-image]][build-status]\n[![pypi-version]][pypi]\n\nWorf is a small Django API framework for building out REST APIs simply using\nclass-based views and serializers.\n\n[![Worf](https://i.kym-cdn.com/photos/images/newsfeed/001/231/196/e18.jpg)][worf-docs]\n\nFull documentation for the project is available at [https://memory-alpha.fandom.com/wiki/Worf][worf-docs].\n\n[worf-docs]: https://memory-alpha.fandom.com/wiki/Worf\n\n\nTable of contents\n-----------------\n\n- [Installation](#installation)\n- [Requirements](#requirements)\n- [Roadmap](#roadmap)\n- [Usage](#usage)\n- [Serializers](#serializers)\n- [Permissions](#permissions)\n- [Validators](#validators)\n- [Views](#views)\n  - [ListAPI](#listapi)\n  - [DetailAPI](#detailapi)\n  - [CreateAPI](#createapi)\n  - [UpdateAPI](#updateapi)\n  - [ActionAPI](#actionapi)\n  - [DeleteAPI](#deleteapi)\n- [Browsable API](#browsable-api)\n- [Bundle loading](#bundle-loading)\n- [Debugging](#debugging)\n- [Field casing](#field-casing)\n- [File uploads](#file-uploads)\n- [Internal naming](#internal-naming)\n- [Settings](#settings)\n- [Credits](#credits)\n\n\nInstallation\n------------\n\nInstall using pip:\n\n```sh\npip install worf\n```\n\nAdd `worf` to your `INSTALLED_APPS` setting:\n\n```py\nINSTALLED_APPS = [\n    ...\n    \"worf\",\n]\n```\n\n\nRequirements\n------------\n\n- Python (3.9, 3.10, 3.11)\n- Django (3.2, 4.0, 4.1)\n\n\nRoadmap\n-------\n\n- [x] Abstracting serializers away from model methods\n- [x] Browsable API\n- [x] Declarative marshmallow-based serialization\n- [x] File upload support\n- [x] Support for PATCH/PUT methods\n- [ ] Better test coverage\n- [ ] Documentation generation\n- [ ] Support for user-generated validators\n\n\nUsage\n-----\n\nThe following examples provides you with an API that does the following:\n\n- Only allows authenticated users to access the endpoints\n- Provides a list of books, with `POST` support to create a new book\n- Provides an endpoint for each book's detail endpoint, with `PATCH` support\n\nA more complete example will demonstrate the additional built-in capabilities,\nincluding search, pagination, ordering, and the other things Worf can do.\n\n```py\n# models.py\nclass Book(models.Model):\n    title = models.CharField(max_length=128)\n    author_name = models.CharField(max_length=128)\n    published_at = models.DateField()\n```\n\n```py\n# serializers.py\nfrom worf.serializers import Serializer\n\nclass BookSerializer(Serializer):\n    class Meta:\n        fields = [\n            \"id\",\n            \"title\",\n            \"author_name\",\n            \"published_at\",\n        ]\n```\n\n```py\n# views.py\nfrom worf.permissions import Authenticated\nfrom worf.views import ActionAPI, DeleteAPI, DetailAPI, ListAPI, UpdateAPI\n\nclass BookList(CreateAPI, ListAPI):\n  model = Book\n  serializer = BookSerializer(only=[\"id\", \"title\"])\n  permissions = [Authenticated]\n\nclass BookDetail(ActionAPI, DeleteAPI, UpdateAPI, DetailAPI):\n  model = Book\n  serializer = BookSerializer\n  permissions = [Authenticated]\n  actions = [\"publish\"]\n```\n\n```py\n# urls.py\npath(\"api/\", include([\n    path(\"books/\", BookList.as_view()),\n    path(\"books/<int:id>/\", BookDetail.as_view()),\n    path(\"books/<int:id>/<str:action>/\", BookDetail.as_view()),\n])),\n```\n\nSerializers\n-----------\n\nWorf serializers are basically [marshmallow schemas](https://marshmallow.readthedocs.io/)\nwith some tweaks to improve support for Django models, and supply extra defaults.\n\n```py\nfrom worf.serializers import fields, Serializer\n\nclass BookSerializer(Serializer):\n    author = fields.Nested(AuthorSerializer)\n    tags = fields.Nested(TagSerializer, many=True)\n\n    class Meta:\n        fields = [\n            \"id\",\n            \"title\",\n            \"content\",\n            \"image\",\n            \"url\",\n            \"author\",\n            \"tags\",\n        ]\n```\n\nWorf serializers build on top of marshmallow to make them a little easier to use\nin Django, primarily, we add support for using the `Nested` field with related\nmanagers, and setting default serializer options via settings:\n\n```py\nWORF_SERIALIZER_DEFAULT_OPTIONS = {\n    \"dump_only\": [\n        \"id\",\n        \"created_at\",\n        \"deleted_at\",\n        \"updated_at\",\n    ]\n}\n```\n\nPermissions\n-----------\n\nPermissions are callable classes that can be found in `worf.permissions`, they're passed\nthe `request` and `kwargs` from the view, and raise an exception if the check fails.\n\n\nValidators\n-----------\n\nValidation handling can be found in `worf.validators`.\n\nThe basics come from `ValidateFields` which `AbstractBaseAPI` inherits from, it\nperforms some coercion on `self.bundle`, potentially resulting in a different\nbundle than what was originally passed to the view.\n\n\nViews\n-----\n\n### AbstractBaseAPI\n\nProvides the basic functionality of API views.\n\n| Name        | Type   | Default | Description                   |\n| ----------- | ------ | ------- | ----------------------------- |\n| model       | class  | None    | Model class.                  |\n| permissions | list   | []      | List of permissions classes.  |\n| serializer  | object | None    | Serializer class or instance. |\n\n**Note:** it is not recommended to use this abstract view directly.\n\n\n### ListAPI\n\n| Name              | Type      | Default             | Description                                                                            |\n| ----------------- | --------- | ------------------- | -------------------------------------------------------------------------------------- |\n| queryset          | object    | model.objects.all() | Queryset used to retrieve the results.                                                 |\n| lookup_field      | str       | None                | Filter `queryset` based on a URL param, `lookup_url_kwarg` is required if this is set. |\n| lookup_url_kwarg  | str       | None                | Filter `queryset` based on a URL param, `lookup_field` is required if this is set.     |\n| payload_key       | str       | verbose_name_plural | Use in order to rename the key for the results array.                                  |\n| ordering          | list      | []                  | Fields to default the queryset order by.                                               |\n| filter_fields     | list      | []                  | Fields to support filtering via query params.                                          |\n| include_fields    | dict/list | []                  | Fields to support optionally including via the `include` query param.                  |\n| search_fields     | list      | []                  | Fields to full text search via the `q` query param.                                    |\n| sort_fields       | list      | []                  | Fields to support sorting via the `sort` query param.                                  |\n| per_page          | int       | 25                  | Number of results returned for each page.                                              |\n| max_per_page      | int       | per_page            | Max number of results to allow when passing the `perPage` query param.                 |\n\nThe `get_queryset` method will use `lookup_url_kwarg` and `lookup_field` to filter results.\nYou _should_ not need to override `get_queryset`. Instead, set the optional variables\nlisted above to configure the queryset.\n\n#### Filtering\n\nParameters in the URL must be camelCase and exactly match the snake_case model field.\n\nTo allow full text search, set to a list of fields for django filter lookups.\n\nFor a full list of supported lookups see https://django-url-filter.readthedocs.io.\n\n#### Include fields\n\nInclude fields is a list of fields to include when `?include=skills,team` is passed.\n\nIf passing a dict the values are passed through to either `prefetch_related` or `select_related`.\n\n```py\nclass ProfileList(CreateAPI, ListAPI):\n    model = Profile\n    include_fields = {\n        \"skills\": Prefetch(\"skills\"),\n        \"team\": \"team\",\n    }\n```\n\n#### Search fields\n\nSearch fields is a list of fields that are used for `icontains` lookups via `?q=`.\n\nThe `?search=id,name` query param can be used to filter `search_fields`.\n\n#### Pagination\n\nAll ListAPI views are paginated and include a `pagination` json object.\n\nUse `per_page` to set custom limit for pagination. Default 25.\n\n### DetailAPI\n\n| Name                | Type   | Default             | Description                                                |\n| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |\n| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |\n| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |\n| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |\n\nThis `get_instance()` method uses `lookup_field` and `lookup_url_kwargs` to return a model instance.\n\nYou _may_ prefer to override this method, for example in a case when you are using\n`request.user` to return an instance.\n\n### CreateAPI\n\n| Name                | Type   | Default             | Description                                                |\n| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |\n| create_serializer   | object | serializer          | Serializer class or instance.                              |\n\nAdds a `post` method to handle creation, mix this into a `ListAPI` view:\n\n```py\nclass BookListAPI(CreateAPI, ListAPI):\n    model = Book\n    serializer = BookSerializer\n```\n\nValidation of creates is kind of sketchy right now, but the idea is that you'd\nuse the same serializer as you would for an update, unless you have `create-only`\nfields, in which case, you may want to create a `BookCreateSerializer`.\n\n### UpdateAPI\n\n| Name                | Type   | Default             | Description                                                |\n| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |\n| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |\n| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |\n| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |\n| update_serializer   | object | serializer          | Serializer class or instance.                              |\n\nAdds `patch` and `put` methods to handle updates, mix this into a `DetailAPI`.\n\n```py\nclass BookDetailAPI(UpdateAPI, DetailAPI):\n    model = Book\n    serializer = BookSerializer\n```\n\nValidation of update fields is delegated to the serializer, any fields that are\nwriteable should be within the `fields` definition of the serializer, and not\nmarked as `dump_only` (read-only).\n\n### ActionAPI\n\n| Name                | Type   | Default             | Description                                                |\n| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |\n| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |\n| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |\n| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |\n| actions             | list   | []                  | List of action methods to support.                         |\n\nAdds `put` endpoints keyed by a route param, mix this into a `DetailAPI` view:\n\n```py\nclass BookDetailAPI(ActionAPI, DetailAPI):\n    model = Book\n    serializer = BookSerializer\n    actions = [\"publish\"]\n```\n\nActions must exist as a method on either the model or the view, they are passed the\ncontents of the bundle as kwargs, and if the method accepts a `user` kwarg then\n`request.user` will be passed through too.\n\n### DeleteAPI\n\n| Name                | Type   | Default             | Description                                                |\n| ------------------- | ------ | ------------------- | ---------------------------------------------------------- |\n| queryset            | object | model.objects.all() | Queryset used to retrieve the results.                     |\n| lookup_field        | str    | id                  | Lookup field used to filter the model.                     |\n| lookup_url_kwarg    | str    | id                  | Name of the parameter passed to the view by the URL route. |\n\nAdds a `delete` method to handle deletes, mix this into a `DetailAPI`.\n\n```py\nclass BookDetailAPI(DeleteAPI, DetailAPI):\n    model = Book\n```\n\nDeletes return a 204 no content response, no serializer is required.\n\n\nBrowsable API\n-------------\n\nSimilar to other popular REST frameworks; Worf exposes a browsable API which adds\nsyntax highlighting, linkified URLs and supports Django Debug Toolbar.\n\nTo override the default browser behaviour pass `?format=json`, or [disable the\nfeature entirely from settings](#settings).\n\n### Theme\n\nThe theme is built with [Tailwind](https://tailwindcss.com/), making it easy to customize the look-and-feel.\n\nFor quick and easy branding, there are a couple of [settings that tweak the navbar](#settings).\n\nTo customize the markup create a template called `worf/api.html` that extends from `worf/base.html`:\n\n```django\n# templates/worf/api.html\n{% extends \"worf/base.html\" %}\n\n{% block branding %}\n    {{ block.super }}\n    <div>A warrior's drink!</div>\n{% endblock %}\n```\n\nAll of the blocks available in the base template can be used in your `api.html`.\n\n| Name     | Description                     |\n| -------- | ------------------------------- |\n| body     | The entire html `<body>`.       |\n| branding | Branding section of the navbar. |\n| script   | JavaScript files for the page.  |\n| style    | CSS stylesheets for the page.   |\n| title    | Title of the page.              |\n\nFor more advanced customization you can choose not to have `api.html` extend `base.html`.\n\n\nBundle loading\n--------------\n\nThe `dispatch` method is run by Django when the view is called. In our version\nof dispatch, we interpret any `request.body` as JSON, and convert all values\nfrom camel to snake case at that time. You'll always be able to access bundle\nattributes by their snake case variable name, and these attributes will exactly\nmatch the model fields.\n\n`self.bundle` is set on a class level, it is available to all methods inside\nthe view. We perform type coercion during validation, so `self.bundle` will\nbe changed during processing. You may also append or remove attributes to the\nbundle before saving the object via `post`, `patch`, or other methods.\n\n\nDebugging\n---------\n\nWorf exposes the parsed bundle, lookup kwargs and skips some exception handling\n[when in debug mode](#settings).\n\n\nField casing\n------------\n\nWorf expects all your model fields to be defined in snake case \ud83d\udc0d, and JSON\nobjects to be camel case \ud83d\udc2a and that conversion is handled in `worf.casing`.\n\nWe interpret camelCase, _strictly_, based on the database model. This means that\ninappropriate naming of database fields will result in confusion.\n\nA quick example:\n\n```py\nfreelance_fulltime = models.CharField(...)\nfreelancer_id = models.UUIDField(...)\nAPI_strict = ...\n```\n\nThis will be strictly translated by the API, and acronyms are not considered:\n\n- `freelance_fulltime == freelanceFulltime`\n- `freelancer_id == freelancerId`\n- `API_strict == apiStrict`\n\n\nFile uploads\n------------\n\nFile uploads are supported via `multipart/form-data` requests.\n\n\nInternal naming\n---------------\n\nWe refer to the json object that is sent and received by the API differently in\nthis codebase for clarity:\n\n- `bundle` is what we send to the backend.\n- `payload` is what the backend returns.\n\n\nSettings\n--------\n\n| Name               | Default        | Description                         |\n| ------------------ | -------------- | ----------------------------------- |\n| WORF_API_NAME      | Worf API       | See [Browsable API](#browsable-api) |\n| WORF_API_ROOT      | /api/          | See [Browsable API](#browsable-api) |\n| WORF_BROWSABLE_API | True           | See [Browsable API](#browsable-api) |\n| WORF_DEBUG         | settings.DEBUG | See [Debugging](#debugging)         |\n\n\n\nCredits\n-------\n\n~Wanted dead or alive~ Made with \ud83e\udd43 at [Gun.io][gun.io]\n\n<a href=\"https://github.com/gundotio/worf/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=gundotio/worf\" alt=\"Contributors\">\n</a>\n\n[build-status-image]: https://github.com/gundotio/worf/actions/workflows/ci.yml/badge.svg\n[build-status]: https://github.com/gundotio/worf/actions/workflows/ci.yml\n[gun.io]: https://www.gun.io\n[pypi-version]: https://img.shields.io/pypi/v/worf.svg?color=blue\n[pypi]: https://pypi.org/project/worf/\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Wade's own REST Framework: A more Djangonic approach to REST APIs",
    "version": "0.5.30",
    "project_urls": {
        "Homepage": "https://github.com/gundotio/worf"
    },
    "split_keywords": [
        "django",
        "rest",
        "framework",
        "api"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "10f6ae226b660ba219e69146c5e7446b0e51ef8253aee7a624ece7ce094119ad",
                "md5": "71439198b1f8770ab919a784c5905ab0",
                "sha256": "9568b399187579350a061ed283a8f7586a130ed991f8efc6dfd1db7c6ce7fc13"
            },
            "downloads": -1,
            "filename": "worf-0.5.30-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "71439198b1f8770ab919a784c5905ab0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9,<4.0",
            "size": 28029,
            "upload_time": "2023-10-13T18:14:15",
            "upload_time_iso_8601": "2023-10-13T18:14:15.140988Z",
            "url": "https://files.pythonhosted.org/packages/10/f6/ae226b660ba219e69146c5e7446b0e51ef8253aee7a624ece7ce094119ad/worf-0.5.30-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d8e7731f8f81f1346d98dfc3e53dafc2949f7dc1643e93d74060f83b7d251d99",
                "md5": "ae93c4eed9fcd80070fc26cccd2acd0a",
                "sha256": "59a547f1e2ccb22935b86bc476d8b31e56495b6e725d898c60699df90c71afe2"
            },
            "downloads": -1,
            "filename": "worf-0.5.30.tar.gz",
            "has_sig": false,
            "md5_digest": "ae93c4eed9fcd80070fc26cccd2acd0a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9,<4.0",
            "size": 26927,
            "upload_time": "2023-10-13T18:14:16",
            "upload_time_iso_8601": "2023-10-13T18:14:16.705183Z",
            "url": "https://files.pythonhosted.org/packages/d8/e7/731f8f81f1346d98dfc3e53dafc2949f7dc1643e93d74060f83b7d251d99/worf-0.5.30.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-10-13 18:14:16",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "gundotio",
    "github_project": "worf",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "lcname": "worf"
}
        
Elapsed time: 0.13466s