Skip to content

Django SwiftAPI, a fully async API framework, provides a powerful yet simple abstraction for automatically generating CRUD APIs, schema generation and robust file handling, built on top of django-ninja-extra.

License

Notifications You must be signed in to change notification settings

DeepDiverGuy/django-swiftapi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Django-SwiftAPI Documentation

Overview

Django SwiftAPI, a fully async API framework, provides a powerful yet simple abstraction for automatically generating CRUD APIs, schema generation and robust file handling, built on top of django-ninja-extra. Built for rapid development, it eliminates the need to write views or serializers manually — just configure your models & controllers and deploy. The core of this system is the use of:

  • SwiftBaseModel: A base model with built-in support for controlling request & responses, CRUD specifications, file fields, ownership, schema customization, object validations etc all out-of-the-box.
  • SwiftBaseModelController: A customizable controller that automates schema generations & CRUD operations. All you need to do is plug-in your SwiftBaseModel & it handles everything in the background.

This documentation explains how to use these components, configure your project, and extend the system for your needs.


Guide


Installation

Install it using:

pip install django-swiftapi

Then, add these in your INSTALLED_APPS:

INSTALLED_APPS = [
    ...,
    'ninja_extra',
    'django_swiftapi',
]

Database Recommendation

  • django-swiftapi heavily relies on the ArrayField for managing file-fields. So you need to use a database that supports ArrayField. Normally, PostgreSQL is a good fit.

Usage Guide for Django SwiftAPI

Welcome to the Django-SwiftAPI usage tutorial. This guide will walk you through setting up a fully functional async API server with minimal effort — from starting your project to building secure, filterable, paginated API endpoints backed by user authentication.

Django-SwiftAPI is designed for rapid API development. With just a few lines of code, you get models, controllers, CRUD, filtering, search, pagination, file-handling and authentication — all built on top of Django Ninja and Django Ninja Extra


Project Setup

Create and activate a virtual environment

python -m venv venv
source venv/bin/activate  # On Windows: source venv/Scripts/activate

Install django-swiftapi

pip install django-swiftapi

Start your project and an app like a regular django project

django-admin startproject myproject
cd myproject
python manage.py startapp api

Add required apps in settings.py

INSTALLED_APPS = [
    ...
    "ninja_extra",
    "django_swiftapi",
    "api",  # your app
]

Create Your Models

Extend SwiftBaseModel instead of models.Model

# api/models.py
from django.db import models
from django_swiftapi.modelcontrol.models import SwiftBaseModel

class Product(SwiftBaseModel):
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    category = models.CharField(max_length=50)

Run migrations:

python manage.py makemigrations
python manage.py migrate

Set up a Model-Controller

Full functional CRUD APIs with automatic files-handling support

Create api/modelcontrollers.py

# api/modelcontrollers.py
from ninja_extra import api_controller
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from .models import Product

@api_controller("/product",)
class ProductController(SwiftBaseModelController):
    model_to_control = Product

    create_enabled = True
    retrieve_one_enabled = True
    search_enabled = True
    filter_enabled = True
    update_enabled = True
    delete_enabled = True

Connect the model-controller to your project's root urls.py

from django.contrib import admin
from django.urls import path, include
from ninja_extra import NinjaExtraAPI
from api.modelcontrollers import ProductController

# Register the controller with your API
api_routes = NinjaExtraAPI(
    title="myproject",
    version="development",
    description="my cool project!",
)
api_routes.register_controllers(ProductController,)

urlpatterns = [
    path('admin/', admin.site.urls),
    path("api/", api_routes.urls),  # this is where all your endpoints live
]

✅ That's literally it! Now, Product is available at /api/product with full CRUD support!

First, let's start our server with uvicorn:

pip install uvicorn
uvicorn myproject.asgi:application --reload

Now, go to http://127.0.0.1:8000/api/docs to find all the routes with request-response examples.


Auto-Generated Documentation

Thanks to ninja & ninja-extra, your project's full api documentation is accessible at /api/docs.

Example url: http://127.0.0.1:8000/api/docs


Filtering (Out of the Box!)

You don't need to implement anything. Django-SwiftAPI automatically enables all filtering functionalities in the /filter route using Django Ninja’s features if filter_enabled = True in the model-controller.

Try accessing:

curl -X POST http://127.0.0.1:8000/api/product/filter \
     -H "Content-Type: application/json" \
     -d '{}'

This is basically a POST request to the route http://127.0.0.1:8000/api/product/filter with an empty json body. This will return all product instances with a default pagination of 100 items (you can change it here). You can easily filter items if a body is provided:

curl -X POST http://127.0.0.1:8000/api/product/filter \
     -H "Content-Type: application/json" \
     -d '{"name": "earbuds", "price": "10.0"}'

This will return all the results containing exact-matches with either the "name" or the "price" or both.

You can also control the pagination by putting parameters like:

http://127.0.0.1:8000/api/product/filter?limit=20&offset=0

It basically shows 20 results from the beginning. Go to Pagination for more details.

Reference


Searching (Out of the Box!)

Django-SwiftAPI comes with built-in search functionality — no manual implementation needed.

If you set search_enabled = True in your ModelController, SwiftAPI will automatically expose a /search route using Django Ninja Extra's powerful Searching integration.

Try accessing:

http://127.0.0.1:8000/api/product/search?search=earbuds

This will return all records where any searchable field contains the word earbuds, either fully or partially.

Django-SwiftAPI directly integrates Ninja-Extra’s searching system, so you can follow their official searching guide for advanced use-cases like customizing searchable fields or handling complex lookups.

As like in the /filter route, you can use controlled pagination here by using two parameters limit and offset.


Pagination

When you use any /filter or /search endpoint in Django-SwiftAPI, results are paginated by default. The following functionality is provided by django-ninja

Default Behavior

By default, 100 items per page are returned in each response. This is controlled by Django Ninja’s default setting.

You can change the default limit globally for your project by adding this to your settings.py:

NINJA_PAGINATION_PER_PAGE = 50  # or any number you prefer

Now, every paginated endpoint will return 50 items per page unless manually overridden.

Custom behavior

You can control pagination by passing the limit and offset query parameters.

Example:

/api/product/search?search=earbuds&limit=20&offset=40

This will return 20 results, starting from the 41st record.


Authentication

If you're using django-allauth, django_swiftapi has a built-in authentication class for it. You can use it directly in your modelcontrollers. Install it if you haven't already. Then use like this:

from ninja_extra import api_controller
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from django_swiftapi.modelcontrol.authenticators import djangoallauth_userauthentication

# Using allauth authentication
@api_controller("/product", permissions=[djangoallauth_userauthentication()])
class ProductController(SwiftBaseModelController):
    # your codes

This will enable authentication for all the routes in that modelcontroller.

If you prefer to allow certain routes without authentication, you can do it simply:

from ninja_extra import api_controller, permissions
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from django_swiftapi.modelcontrol.authenticators import djangoallauth_userauthentication

@api_controller("/product", permissions=[djangoallauth_userauthentication()])
class ProductController(SwiftBaseModelController):

    create_enabled= True
    create_custom_permissions_list = [permissions.AllowAny]

Now, the /create route can be accessed by anyone. If you wanna use a custom authentication class, follow this guideline.

Go to Authentication & Permissions for more details.


Extending API Routes

If the built-in functionalities don't meet your needs and you want your own routes & custom functionalities, simply define a method inside the model-controller class and put your own logics. Follow the official documentation from django-ninja-extra.


Admin Panel

One of the best features of Django is that it provides a robust and customizable Admin Panel. You can register the models in admin.py as usual:

from django.contrib import admin
from .models import Product

admin.site.register(Product)

To access the admin panel, first you need to create a superuser from your terminal:

python manage.py createsuperuser

The admin panel is accessible at http://127.0.0.1:8000/admin/


Final Words

Django-SwiftAPI removes boilerplate and makes you productive in minutes. Compared to Django Ninja or FastAPI, you write:

  • ✅ No manual schema or serializers
  • ✅ No explicit views
  • ✅ No filters setup
  • ✅ No pagination configuration
  • ✅ Everything is automatic via configuration and base classes

Happy Hacking 🚀


Model Definition

SwiftBaseModel

SwiftBaseModel is an abstract Django model that provides powerful hooks and configurations for automated CRUD operations, user ownership enforcement, and file upload/download/deletion handling when used with the SwiftBaseModelController from django-swiftapi.

Key Features

  • Auto-included created, updated, and created_by fields
  • Ownership-based object access control
  • Field-level validation before save/update
  • Built-in file handling for ArrayField-based file storage
  • Built-in integration with both local and S3-based file systems

Full Model Example Using SwiftBaseModel

from django.db import models
from django.contrib.postgres.fields import ArrayField
from django_swiftapi.modelcontrol.models import SwiftBaseModel
from django_swiftapi.crud_operation.file_operations.storage_operations import local_storage
from django_swiftapi.crud_operation.file_operations.files_handlers import Files_Param
from django_swiftapi.crud_operation.file_operations.files_validators import validate_images, validate_file_sizes

class Product(SwiftBaseModel):
    name = models.CharField(max_length=100)
    images = ArrayField(models.CharField(max_length=200), default=list, blank=True, null=True)

    files_fields = ["images"]
    files_params_list = [
        FilesParam(
            field_name="images",
            access="public",
            storage=local_storage,
            validator_funcs={
                validate_file_sizes: {"limit": 5},
                validate_images: {},
            }
        )
    ]

Model Fields

Field Type Description
created DateTimeField Auto timestamp when instance is created
updated DateTimeField Auto timestamp on every update
created_by ForeignKey(User) Automatically assigned user who created the object
created_by_field str (default: 'created_by') Custom field to use for ownership checking, the field referred here must point to a User model

Configuration Attributes

These are class-level attributes, not DB fields.

Attribute Type Description
required_to_create list[str] List of field names required during object creation
required_to_update list[str] List of field names required during update
exclude_in_request list[str] Fields to exclude while generating request schemas
exclude_in_response list[str] Fields to exclude from response schemas
obj_owner_check_before_save bool If True, ownership will be verified before saving. Meaning, only the user who created the object can save it
obj_fields_to_check_owner list[str] Field names pointing to related objects whose created_by must match request.user
files_fields list[str] Names of file fields (typically ArrayFields)
files_params_list list[FilesParam] Full configuration for file handling per field

File Handling Example

To manage file uploads, downloads, deletion etc (via ArrayField), follow this approach:

from django.contrib.postgres.fields import ArrayField
from django_swiftapi.crud_operation.file_operations.storage_operations import local_storage
from django_swiftapi.crud_operation.file_operations.files_handlers import Files_Param
from django_swiftapi.crud_operation.file_operations.files_validators import validate_images, validate_file_sizes

# Define file field in your model:
images = ArrayField(
    models.CharField(max_length=200), 
    default=list, 
    size=5, 
    blank=True, 
    null=True
)

# Register it as a file field:
files_fields = ["images"]

# Provide full configuration for how files should be handled:
files_params_list = [
    FilesParam(
        field_name="images",
        access="public",
        storage=local_storage,
        validator_funcs={
            validate_file_sizes: {"limit": 5},  # limit in MegaBytes
            validate_images: {},
        }
    ),
]

Ownership Enforcement

By default, created_by is used to check whether the requesting user has access to modify or delete the object.

To enable this behavior, set:

obj_owner_check_before_save = True

If you use a different field for ownership, specify it with:

created_by_field = "your_owner_field_name"

If you want to ensure that the requesting user is the owner not only of the main object but also of related objects referenced via ForeignKey fields, you can use the obj_fields_to_check_owner attribute.

  • obj_fields_to_check_owner:

    A list of string field names representing ForeignKey relationships on the main model. For each specified ForeignKey field, the ownership check will verify that the requesting user is also the owner of the related object.

This way, the permission or validation logic will recursively check ownership on those related objects as well, ensuring more secure and fine-grained access control.

This documentation outlines how to utilize the SwiftBaseModel to build models that seamlessly integrate with the CRUD operations and file handling mechanisms provided by django-swiftapi.

For more details on file validations and storage options, refer to the respective modules.


Model-Controller Setup

Create modelcontrollers by inheriting from SwiftBaseModelController:

Full Configurations Example:

from ninja_extra import api_controller
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from .models import MyDocument

@api_controller("/documents",)
class DocumentController(SwiftBaseModelController):

    model_to_control = MyDocument

    # These are default values
    create_enabled: bool = False
    create_path: str = 'create'
    create_info: str = 'create an item'
    create_request_schemas: list[tuple[str, str, Schema, bool]] = None
    create_response_schemas: dict[int, Schema] = None
    create_custom_permissions_list: list = []

    retrieve_one_enabled: bool = False
    retrieve_one_path: str = 'retrieveone/{id}'
    retrieve_one_info: str = 'retrieve an item'
    retrieve_one_depth = 0
    retrieve_one_response_schemas: dict[int, Schema] = None
    retrieve_one_custom_permissions_list: list = []
    retrieve_one_obj_permission_check: bool = False

    search_enabled: bool = False
    search_path: str = 'search'
    search_info: str = 'search & get the listed result'
    search_depth = 0
    search_response_schemas: dict[int, Schema] = None
    search_custom_permissions_list: list = []
    search_obj_permission_check: bool = False
    search_premium_check: bool = False

    filter_enabled: bool = False
    filter_path: str = 'filter'
    filter_info: str = 'filter & get the listed result'
    filter_depth = 0
    filter_request_schemas: list[tuple[str, str, Schema, bool]] = None
    filter_response_schemas: dict[int, Schema] = None
    filter_custom_permissions_list: list = []
    filter_obj_permission_check: bool = False

    update_enabled: bool = False
    update_path: str = '{id}/update'
    update_info: str = 'update or add files to an item'
    update_request_schemas: list[tuple[str, str, Schema, bool]] = None
    update_response_schemas: dict[int, Schema] = None
    update_custom_permissions_list: list = []
    update_obj_permission_check: bool = False

    file_retrieve_enabled: bool = False
    file_retrieve_path: str = '{id}/file/retrieve'
    file_retrieve_info: str = 'retrieve a single file of an item'
    file_retrieve_request_schemas: list[tuple[str, str, Schema, bool]] = None
    file_retrieve_response_schemas: dict[int, Schema] = None
    file_retrieve_custom_permissions_list: list = []
    file_retrieve_obj_permission_check: bool = False

    files_remove_enabled: bool = False
    files_remove_path: str = '{id}/files/remove'
    files_remove_info: str = 'remove files of an item', 
    files_remove_request_schemas: list[tuple[str, str, Schema, bool]] = None
    files_remove_response_schemas: dict[int, Schema] = None
    files_remove_custom_permissions_list: list = []
    files_remove_obj_permission_check: bool = False

    delete_enabled: bool = False
    delete_path: str = '{id}/delete'
    delete_info: str = 'delete an item with all its files'
    delete_response_schemas: dict[int, Schema] = None
    delete_custom_permissions_list: list = []
    delete_obj_permission_check: bool = False

Model-Controller Options

CRUD Operations

Option Type Default Description
create_enabled bool False Enable create endpoint
retrieve_one_enabled bool False Enable retrieve endpoint
search_enabled bool False Enable search endpoint
filter_enabled bool False Enable filter endpoint
update_enabled bool False Enable update endpoint
delete_enabled bool False Enable delete endpoint

File Operations

Option Type Default Description
file_retrieve_enabled bool False Enable file retrieval endpoint
files_remove_enabled bool False Enable file removal endpoint

Permission Options

Option Type Default Description
*_custom_permissions_list list [] Custom permissions for specific operation
*_obj_permission_check bool False Check object ownership for operation

Path Customization (You can leave it to the default)

Option Type Default Description
create_path str 'create' Custom path for create endpoint
retrieve_one_path str 'retrieveone/{id}' Custom path for retrieve endpoint
search_path str 'search' Custom path for search endpoint
filter_path str 'filter' Custom path for filter endpoint
update_path str '{id}/update' Custom path for update endpoint
delete_path str '{id}/delete' Custom path for delete endpoint
file_retrieve_path str '{id}/file/retrieve' Custom path for file retrieve
files_remove_path str '{id}/files/remove' Custom path for file removal

You can also customize their info and schemas. just set the variables properly.


URL Configuration

Configure your URLs to include the API endpoints (Reference).

Example:

# urls.py
from django.contrib import admin
from django.urls import path, include
from ninja_extra import NinjaExtraAPI
from your_app.controllers import DocumentController

api = NinjaExtraAPI()
api.register_controllers(DocumentController)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', api.urls),
]

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

That's it! Thanks to ninja & ninja-extra, now you can see the auto-generated documentation at http://127.0.0.1:8000/api/docs.


File Handling

Easier than ever!

Example

To manage file uploads, downloads, deletion etc (via ArrayField), follow this approach:

from django.contrib.postgres.fields import ArrayField
from django_swiftapi.crud_operation.file_operations.storage_operations import local_storage
from django_swiftapi.crud_operation.file_operations.files_handlers import Files_Param
from django_swiftapi.crud_operation.file_operations.files_validators import validate_images, validate_file_sizes

# Define file field in your model:
images = ArrayField(
    models.CharField(max_length=200), 
    default=list, 
    size=5, 
    blank=True, 
    null=True
)

# Register it as a file field:
files_fields = ["images"]

# Provide full configuration for how files should be handled:
files_params_list = [
    FilesParam(
        field_name="images",
        access="public",
        storage=local_storage,
        validator_funcs={
            validate_file_sizes: {"limit": 10},  # limit in MB
            validate_images: {}
        }
    ),
]

Configuration

Configure file-handling from inside your model's file configuration, specify a few attributes in setings.py like below and that's it! No extra work, no nothing. All CRUD functionalities (uploads, downloads, deletions etc) including authentications, permissions, individual-accesses are handled automatically by django-swiftapi.

For local storage

In your settings.py:

PUBLIC_LOCAL_FILE_WRITE_LOCATION = "" # ensure this directory is public in your production server, ex: 'dummy_site_files/public'
PUBLIC_LOCAL_FILE_URL_PREFIX = "/media" # this prefix will be used in the file links, ex: '/media'
PRIVATE_LOCAL_FILE_WRITE_LOCATION = "" # ensure this directory is not publicly accessible in your production server, ex: 'dummy_site_files/private'
MEDIA_ROOT = PUBLIC_LOCAL_FILE_WRITE_LOCATION
MEDIA_URL = '/media/'  # the value '/media/' is necessary for serving files during development according to django-docs

For AWS S3

First, you need to install boto3 and set some configurations following AWS's official docs

Then in your settings.py, set these attributes:

PUBLIC_AMAZONS3_BUCKET_NAME = ""
PUBLIC_AMAZONS3_FILE_WRITE_LOCATION = ""
PUBLIC_AMAZONS3_FILE_URL_PREFIX = ""
PRIVATE_AMAZONS3_BUCKET_NAME = ""
PRIVATE_AMAZONS3_FILE_WRITE_LOCATION = ""
MEDIA_URL = '/media/'  # the value '/media/' is necessary for serving files during development according to django-docs

Done!

File Operations

The system automatically provides these file operations:

  • Upload: Files are uploaded during create or update operations
  • Retrieve: Download files via /file/retrieve endpoint
  • Remove: Delete specific files via /files/remove endpoint

File Access Control

  • Public files: Accessible without authentication
  • Private files: Require authentication and if specified, ownership verification

Using Your Own Validation

It's super easy. Just define a function (django-swiftapi supports both sync & async) and put it into the dictionary variable validator_funcs like this:

# Define your validation function
async def your_validator(arg_name=default):
    # if it validates, then return None
    # if it fails to validate, return a single string containing the error message
    return "error occurred"

# Then, use it inside `FilesParam`
validator_funcs={
    your_validator: {"<arg_name>": <arg_value>}
}

Storage Support

django-swiftapi currently supports:

  • local storage (django_swiftapi.crud_operation.file_operations.storage_operations.local_storage)
  • aws s3 storage (django_swiftapi.crud_operation.file_operations.storage_operations.aws_s3_storage)

However, if you want to create support for new platforms, you can do it just by inheriting the BaseStorage class and defining these methods below:

from django.db.models import Model
from django_swiftapi.crud_operation.file_operations.storage_operations import BaseStorage

class custom_storage_class(BaseStorage):
    async def dir_maker(instance:Model, files_param):
        """
        Create and return the directory path for storing files related to the model instance.
        Used internally by the storage class.
        """
        pass

    async def url_maker(self,  abs_path:str, files_param, source_dir:str=""):
        """
        Generate a URL (or file identifier for private) from the absolute file path.
        Used internally by the storage class.
        """
        pass

    async def _files_writer(self, instance:Model, files_param):
        """
        Write uploaded files to the specified filesystem.

        Args:
            instance (Model): Django model instance.
            files_param (Files_Param): Contains uploaded file list, chunk size, access level, etc.

        Returns:
            Two lists:
            - List of successfully written file URLs.
            - List of failed file names.
        """
        pass

    async def _files_remover(self, instance:Model, files_param, remove_dir=False):
        """
        Remove files or entire directory from the specified filesystem.

        Args:
            instance (Model): Django model instance.
            files_param (Files_Param): Contains file_links to remove.
            remove_dir (bool, optional): Whether to remove the whole directory.

        Returns:
            Two lists:
            - List of successfully removed file links.
            - List of failed file links.
        """
        pass

    async def _files_retriever(self, instance:Model, files_param):
        """
        Yields chunks of file data from the specified path for streaming purposes.

        Args:
            instance (Model): Django model instance.
            files_param (Files_Param): Contains file_links to retrieve.

        Yields:
            Two lists:
            - List of dictionaries mapping file names to file streams for successfully retrieved files.
            - List of failed file names.
        """
        pass

Authentication & Permissions

django_swiftapi is highly compatible with django-allauth. So, if you're using django-allauth, you can validate authentications directly in your modelcontrollers.

Using django-allauth Authentication Class

from ninja_extra import api_controller
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from django_swiftapi.modelcontrol.authenticators import djangoallauth_userauthentication

# Using allauth authentication
@api_controller("/api", permissions=[djangoallauth_userauthentication()])
class MyController(SwiftBaseModelController):
    pass

Under the hood, djangoallauth_userauthentication takes the x-session-token header from the request and verifies if the user is logged-in. That's how django-allauth authenticates it's users.

IMPORTANT NOTE: Using @api_controller("/api", permissions=[djangoallauth_userauthentication()]) will enable authentication for all the routes of the corresponding modelcontroller. If you wish to allow certain routes to pass without authentication, you can do it simply like this:

from ninja_extra import api_controller, permissions
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from django_swiftapi.modelcontrol.authenticators import djangoallauth_userauthentication

@api_controller("/api", permissions=[djangoallauth_userauthentication()])
class MyController(SwiftBaseModelController):

    create_enabled= True
    create_custom_permissions_list = [permissions.AllowAny]

As simple as that! You can enable this functionality for other routes too or incorporate your own customized authentication classes for each operation, using:

retrieve_one_custom_permissions_list: list = []
filter_custom_permissions_list: list = []
update_custom_permissions_list: list = []
file_retrieve_custom_permissions_list: list = []
files_remove_custom_permissions_list: list = []
delete_custom_permissions_list: list = []

Extra Permission Check

You can enhance your endpoint protection by using the optional extra_permission_list.
This lets you specify a list of boolean fields from your user model — all of which must be True for a user to pass authentication.

Use Case Example

Suppose your User model has these custom fields:

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    is_verified = models.BooleanField(default=False)
    is_manager = models.BooleanField(default=False)

You can now protect any SwiftAPI controller like so:

from ninja_extra import api_controller
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController
from django_swiftapi.modelcontrol.authenticators import djangoallauth_userauthentication

@api_controller("/api", permissions=[djangoallauth_userauthentication(extra_permission_list=["is_verified", "is_manager"])])
class MyController(SwiftBaseModelController):
    pass

In this case, the authenticated user must have both is_verified=True and is_manager=True to access this controller’s endpoints.

How it Works

  • Each string in extra_permission_list refers to boolean fields on your user model.
  • All listed fields must be True — otherwise, authentication fails.
  • Perfect for staff-only, verified-user, or gated-feature access control.

Enabling Object-Level Permissions

If you wish to give object-specific permissions like only the creator of that object can rerieve, filter, update, remove or delete that object, you can do so like this:

retrieve_one_obj_permission_check = True
filter_obj_permission_check = True
update_obj_permission_check = True
file_retrieve_obj_permission_check = True
files_remove_obj_permission_check = True
delete_obj_permission_check = True

Example:

from ninja_extra import api_controller
from django_swiftapi.modelcontrol.modelcontrollers import SwiftBaseModelController

@api_controller("/api", permissions=[djangoallauth_userauthentication()])
class DocumentController(SwiftBaseModelController):
    retrieve_one_obj_permission_check = True  # Only owner can retrieve
    update_obj_permission_check = True        # Only owner can update
    delete_obj_permission_check = True        # Only owner can delete

Customizing Authentication Class

If you're using any other user authentication system, you need to define your own authentication class overriding just one function:

from django_swiftapi.modelcontrol.authenticators import BaseUserAuthentication

# Create custom authentication
class CustomAuthentication(BaseUserAuthentication):
    def has_permission(self, request, view):
        # Your custom logic for verifying if the user is authenticated
        # return the user object if authenticated else None

then use it like this:

@api_controller("/api", permissions=[CustomAuthentication()])
class MyController(SwiftBaseModelController):
    pass

Permission Levels

  1. Controller Level: Applied to all endpoints in the controller
  2. Operation Level: Specific permissions per CRUD operation
  3. Object Level: Ownership-based permissions

About

Django SwiftAPI, a fully async API framework, provides a powerful yet simple abstraction for automatically generating CRUD APIs, schema generation and robust file handling, built on top of django-ninja-extra.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages