Skip to main content

User management module for Bazis framework.

Project description

Bazis Users

PyPI version Python Versions License

An extension package for Bazis that provides advanced capabilities for user management and authentication.

Quick Start

# Install the package
uv add bazis-users

# Create user model
from bazis.contrib.users.models_abstract import UserAbstract
from bazis.core.models_abstract import DtMixin, UuidMixin, JsonApiMixin

class User(UserAbstract, DtMixin, UuidMixin, JsonApiMixin):
    """Custom user model"""
    
    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'

# Create user route
from bazis.contrib.users.routes import UserRouteSet
from django.apps import apps

class MyUserRouteSet(UserRouteSet):
    model = apps.get_model('myapp.User')

Table of Contents

Description

Bazis Users is an extension package for the Bazis framework that provides a complete toolkit for user management and authentication. The package includes:

  • Abstract user models with JWT authentication support
  • Ready-to-use routes for user operations
  • Services for token and authentication management
  • Mixins for linking models to users
  • Integration with Swagger UI for API testing

This package requires the base bazis package to be installed.

Requirements

  • Python: 3.12+
  • bazis: latest version
  • PostgreSQL: 12+
  • Redis: For caching

Installation

Using uv (recommended)

uv add bazis-users

Using pip

pip install bazis-users

Core Components

Abstract Models

UserAbstract

Abstract user model implementing methods required for extended work with Bazis.

Location: bazis.contrib.users.models_abstract.UserAbstract

Methods:

  • get_full_name() - returns user's full name
  • jwt_build() - creates JWT token for the user
  • find_or_create() - finds or creates a user
  • raw_password - works with raw password

Example usage:

from bazis.contrib.users.models_abstract import UserAbstract
from bazis.core.models_abstract import DtMixin, UuidMixin, JsonApiMixin

class User(UserAbstract, DtMixin, UuidMixin, JsonApiMixin):
    """Application user model"""
    
    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'
    
    def __str__(self):
        return self.get_full_name()

AnonymousUserAbstract

Abstract anonymous user model for handling unauthenticated requests.

Location: bazis.contrib.users.models_abstract.AnonymousUserAbstract

Methods:

  • get_full_name() - returns name for anonymous user

Mixins

UserMixin

Mixin for entity models that should be associated with a user.

Location: bazis.contrib.users.models_abstract.UserMixin

Features:

  • User is stored in context variable CTX_USER_REQUEST
  • Automatically links model to current user from request

Example usage:

from bazis.contrib.users.models_abstract import UserMixin
from bazis.core.models_abstract import DtMixin, UuidMixin, JsonApiMixin
from django.db import models

class Article(UserMixin, DtMixin, UuidMixin, JsonApiMixin):
    """Article linked to a user"""
    title = models.CharField(max_length=255)
    content = models.TextField()
    
    class Meta:
        verbose_name = 'Article'
        verbose_name_plural = 'Articles'

Base Routes

UserRouteBase

Base class for routes associated with users.

Location: bazis.contrib.users.routes_abstract.UserRouteBase

Provides base functionality for creating routes that work with user models.

Built-in Routes

token_auth

Basic token authentication (JWT), applied in Swagger UI.

Location: bazis.contrib.users.routes.token_auth

Enables JWT token authentication in Swagger UI.

UserRouteSet

Base route class for working with users.

Location: bazis.contrib.users.routes.UserRouteSet

Provides ready-to-use endpoints for user operations:

  • List users
  • Get specific user information
  • Create user
  • Update user
  • Delete user

Example usage:

from bazis.contrib.users.routes import UserRouteSet
from django.apps import apps

class MyUserRouteSet(UserRouteSet):
    model = apps.get_model('myapp.User')

Services

Services for working with users and tokens.

Location: bazis.contrib.users.services

get_token_data

Extracts data from JWT token.

from bazis.contrib.users.services import get_token_data

def my_endpoint(token: str = Depends(get_token_data)):
    user_id = token.get('user_id')
    # Work with token data

get_user_from_token

Gets user from token.

from bazis.contrib.users.services import get_user_from_token

def my_endpoint(user = Depends(get_user_from_token)):
    # user - user object or AnonymousUser
    print(user.get_full_name())

get_user_required

Gets user from request (authentication required).

from bazis.contrib.users.services import get_user_required

def my_endpoint(user = Depends(get_user_required)):
    # user - authenticated user
    # Returns 401 if token is invalid
    return {"user": user.get_full_name()}

get_user_optional

Gets user from request (authentication optional).

from bazis.contrib.users.services import get_user_optional

def my_endpoint(user = Depends(get_user_optional)):
    # user - user or AnonymousUser
    if user.is_authenticated:
        return {"user": user.get_full_name()}
    return {"user": "Anonymous"}

Usage

Creating User Model

from bazis.contrib.users.models_abstract import UserAbstract
from bazis.core.models_abstract import DtMixin, UuidMixin, JsonApiMixin
from django.db import models

class User(UserAbstract, DtMixin, UuidMixin, JsonApiMixin):
    """Custom user model"""
    
    # Additional fields
    phone = models.CharField('Phone', max_length=20, null=True, blank=True)
    department = models.CharField('Department', max_length=100, null=True, blank=True)
    
    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'
    
    def __str__(self):
        return self.get_full_name()

Creating User Route

# routes.py
from bazis.contrib.users.routes import UserRouteSet
from bazis.core.schemas.fields import SchemaField, SchemaFields
from django.apps import apps

class MyUserRouteSet(UserRouteSet):
    model = apps.get_model('myapp.User')
    
    # Add additional fields to schema
    fields = {
        None: SchemaFields(
            include={
                'phone': None,
                'department': None,
            },
        ),
    }
# router.py
from bazis.core.routing import BazisRouter
from . import routes

router = BazisRouter(tags=['Users'])
router.register(routes.MyUserRouteSet.as_router())

Using Authentication Services

Required Authentication

Use get_user_required for endpoints that require authentication:

from bazis.contrib.users.services import get_user_required
from fastapi import APIRouter, Depends
from pydantic import BaseModel

router = APIRouter()

class NewPasswordRequest(BaseModel):
    old_password: str
    new_password: str

@router.post('/user/change_password/', response_model=dict)
def change_password(
    data: NewPasswordRequest,
    user: User = Depends(get_user_required)
):
    # user - guaranteed authenticated user
    # Returns 401 if token is invalid
    return user.change_password(data)

Optional Authentication

Use get_user_optional for endpoints available to everyone:

from bazis.contrib.users.services import get_user_optional, get_token_data
from fastapi import Depends

@router.get('/auth/', response_model=AuthResponse)
def auth(
    auth_store: AuthStore = Depends(),
    user: User = Depends(get_user_optional),
    token_data: dict = Depends(get_token_data),
):
    # user can be AnonymousUser
    if user.is_anonymous:
        if user_id := auth_store.user_id:
            user = User.objects.filter(id=user_id).first()
    
    # Logic for working with user or anonymous
    return {"user": user.get_full_name() if not user.is_anonymous else "Anonymous"}

Using get_token_data

Getting data from JWT token without loading the user:

from bazis.contrib.users.services import get_token_data
from fastapi import Depends

@router.get('/token-info/')
def token_info(token_data: dict = Depends(get_token_data)):
    # token_data contains decoded data from JWT
    return {
        "user_id": token_data.get("user_id"),
        "exp": token_data.get("exp"),
    }

Linking Models to Users

from bazis.contrib.users.models_abstract import UserMixin
from bazis.core.models_abstract import DtMixin, UuidMixin, JsonApiMixin
from django.db import models

class Document(UserMixin, DtMixin, UuidMixin, JsonApiMixin):
    """Document automatically linked to user"""
    title = models.CharField(max_length=255)
    content = models.TextField()
    
    class Meta:
        verbose_name = 'Document'
        verbose_name_plural = 'Documents'

API Authentication

Getting Token

After setting up routes, users can obtain JWT tokens through the authentication endpoint.

Example request:

POST /api/v1/auth/login
Content-Type: application/json

{
  "username": "user@example.com",
  "password": "password123"
}

Example response:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}

Using Token in Requests

GET /api/v1/protected-resource
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Authentication in Swagger UI

  1. Open /api/swagger/
  2. Click "Authorize" button
  3. Enter token in format: Bearer <your_token>
  4. Click "Authorize"
  5. Now all requests will be executed with authentication

Examples

Complete Application Example with Users

models.py:

from bazis.contrib.users.models_abstract import UserAbstract, UserMixin
from bazis.core.models_abstract import DtMixin, UuidMixin, JsonApiMixin
from django.db import models

class User(UserAbstract, DtMixin, UuidMixin, JsonApiMixin):
    """System user"""
    phone = models.CharField('Phone', max_length=20, null=True, blank=True)
    
    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'

class Task(UserMixin, DtMixin, UuidMixin, JsonApiMixin):
    """Task linked to user"""
    title = models.CharField('Title', max_length=255)
    description = models.TextField('Description')
    is_completed = models.BooleanField('Completed', default=False)
    assigned_to = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='tasks',
        verbose_name='Assigned To'
    )
    
    class Meta:
        verbose_name = 'Task'
        verbose_name_plural = 'Tasks'

routes.py:

from bazis.contrib.users.routes import UserRouteSet
from bazis.contrib.users.services import get_user_required
from django.apps import apps
from fastapi import APIRouter, Depends
from pydantic import BaseModel

class MyUserRouteSet(UserRouteSet):
    model = apps.get_model('myapp.User')

# Additional endpoints for working with tasks
router = APIRouter()

class TaskCreateRequest(BaseModel):
    title: str
    description: str

@router.get('/my-tasks/')
def get_my_tasks(user: User = Depends(get_user_required)):
    # Return only current user's tasks
    tasks = Task.objects.filter(assigned_to=user)
    return {"tasks": [{"id": str(t.id), "title": t.title} for t in tasks]}

@router.post('/tasks/')
def create_task(
    data: TaskCreateRequest,
    user: User = Depends(get_user_required)
):
    # Create task for current user
    task = Task.objects.create(
        title=data.title,
        description=data.description,
        assigned_to=user
    )
    return {"id": str(task.id), "title": task.title}

router.py:

from bazis.core.routing import BazisRouter
from . import routes

# Register user routes
user_router = BazisRouter(tags=['Users'])
user_router.register(routes.MyUserRouteSet.as_router())

# Register additional task endpoints
user_router.include_router(routes.router, prefix='/api/v1')

admin.py:

from django.contrib import admin
from bazis.core.admin_abstract import DtAdminMixin
from .models import User, Task

@admin.register(User)
class UserAdmin(DtAdminMixin, admin.ModelAdmin):
    list_display = ('id', 'username', 'email', 'phone', 'is_active')
    search_fields = ('username', 'email', 'phone')
    list_filter = ('is_active', 'is_staff')

@admin.register(Task)
class TaskAdmin(DtAdminMixin, admin.ModelAdmin):
    list_display = ('id', 'title', 'assigned_to', 'is_completed')
    search_fields = ('title', 'description')
    list_filter = ('is_completed',)
    raw_id_fields = ('assigned_to',)

License

Apache License 2.0

See LICENSE file for details.

Links

Support

If you have questions or issues:


Made with ❤️ by the Bazis team

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bazis_users-2.2.0.tar.gz (36.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bazis_users-2.2.0-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file bazis_users-2.2.0.tar.gz.

File metadata

  • Download URL: bazis_users-2.2.0.tar.gz
  • Upload date:
  • Size: 36.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for bazis_users-2.2.0.tar.gz
Algorithm Hash digest
SHA256 767ebea2b2e2669eff9fa3112a9eddbc61008d6a7ab9df5a77e0f5f2b12ef629
MD5 fc8465f9ba8326a90c9d96407ee303f7
BLAKE2b-256 164d5be7542e8b02e6745efbe440dbe3986715fd0bd41690a4c6bb39689e566a

See more details on using hashes here.

File details

Details for the file bazis_users-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: bazis_users-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for bazis_users-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bc0ed4da2cba1535bb71e496c97c413a0b0b54d17bcd9452197b2d9363303b07
MD5 e27901e80248c39f8c17253bda955459
BLAKE2b-256 61c0f05f11c33de692f649d3eff16c635208c3a28ebdacf3a3df1b3218fb702e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page