New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

worf

Package Overview
Dependencies
Maintainers
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

worf

Wade's own REST Framework: A more Djangonic approach to REST APIs

  • 0.5.30
  • PyPI
  • Socket score

Maintainers
3

Worf

build-status-image pypi-version

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

Worf

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

Table of contents

Installation

Install using pip:

pip install worf

Add worf to your INSTALLED_APPS setting:

INSTALLED_APPS = [
    ...
    "worf",
]

Requirements

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

Roadmap

  • Abstracting serializers away from model methods
  • Browsable API
  • Declarative marshmallow-based serialization
  • File upload support
  • 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.

# models.py
class Book(models.Model):
    title = models.CharField(max_length=128)
    author_name = models.CharField(max_length=128)
    published_at = models.DateField()
# serializers.py
from worf.serializers import Serializer

class BookSerializer(Serializer):
    class Meta:
        fields = [
            "id",
            "title",
            "author_name",
            "published_at",
        ]
# 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"]
# 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 with some tweaks to improve support for Django models, and supply extra defaults.

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:

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.

NameTypeDefaultDescription
modelclassNoneModel class.
permissionslist[]List of permissions classes.
serializerobjectNoneSerializer class or instance.

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

ListAPI

NameTypeDefaultDescription
querysetobjectmodel.objects.all()Queryset used to retrieve the results.
lookup_fieldstrNoneFilter queryset based on a URL param, lookup_url_kwarg is required if this is set.
lookup_url_kwargstrNoneFilter queryset based on a URL param, lookup_field is required if this is set.
payload_keystrverbose_name_pluralUse in order to rename the key for the results array.
orderinglist[]Fields to default the queryset order by.
filter_fieldslist[]Fields to support filtering via query params.
include_fieldsdict/list[]Fields to support optionally including via the include query param.
search_fieldslist[]Fields to full text search via the q query param.
sort_fieldslist[]Fields to support sorting via the sort query param.
per_pageint25Number of results returned for each page.
max_per_pageintper_pageMax 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.

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

NameTypeDefaultDescription
querysetobjectmodel.objects.all()Queryset used to retrieve the results.
lookup_fieldstridLookup field used to filter the model.
lookup_url_kwargstridName 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

NameTypeDefaultDescription
create_serializerobjectserializerSerializer class or instance.

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

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

NameTypeDefaultDescription
querysetobjectmodel.objects.all()Queryset used to retrieve the results.
lookup_fieldstridLookup field used to filter the model.
lookup_url_kwargstridName of the parameter passed to the view by the URL route.
update_serializerobjectserializerSerializer class or instance.

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

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

NameTypeDefaultDescription
querysetobjectmodel.objects.all()Queryset used to retrieve the results.
lookup_fieldstridLookup field used to filter the model.
lookup_url_kwargstridName of the parameter passed to the view by the URL route.
actionslist[]List of action methods to support.

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

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

NameTypeDefaultDescription
querysetobjectmodel.objects.all()Queryset used to retrieve the results.
lookup_fieldstridLookup field used to filter the model.
lookup_url_kwargstridName of the parameter passed to the view by the URL route.

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

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.

Theme

The theme is built with Tailwind, making it easy to customize the look-and-feel.

For quick and easy branding, there are a couple of settings that tweak the navbar.

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

# 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.

NameDescription
bodyThe entire html <body>.
brandingBranding section of the navbar.
scriptJavaScript files for the page.
styleCSS stylesheets for the page.
titleTitle 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.

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:

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

NameDefaultDescription
WORF_API_NAMEWorf APISee Browsable API
WORF_API_ROOT/api/See Browsable API
WORF_BROWSABLE_APITrueSee Browsable API
WORF_DEBUGsettings.DEBUGSee Debugging

Credits

Wanted dead or alive Made with 🥃 at Gun.io

Contributors

Keywords

FAQs


Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc