Skip to main content

Flexible and Extensible Lists of Options for Django

Project description

django-tenant-options

PyPI Status Python Version [License][license]

Read the documentation at https://django-tenant-options.readthedocs.io/ Tests Codecov

pre-commit Black

Empowering Your SaaS Tenants with Custom Options and Sane Defaults

django-tenant-options provides a powerful and flexible way for your SaaS application’s tenants to customize the selectable options in user-facing forms. This package allows you to offer a balance between providing default options—either mandatory or optional—and giving your tenants the freedom to define their own custom choices, all within a structured framework that ensures consistency and ease of use.

Why Use django-tenant-options?

In a SaaS environment, one size doesn't fit all. Tenants often have unique needs for the choices they offer in user-facing forms, but building an entirely custom solution for each tenant - or requiring each tenant to define their own options from scratch - can be complex and time-consuming. django-tenant-options addresses this challenge by offering:

  • Flexibility: Tenants can tailor the options available in forms to better meet their specific needs.
  • Control: Provide mandatory defaults to maintain a consistent experience across all tenants, while still allowing for customization.
  • Scalability: Easily manage multiple tenants with differing requirements without compromising on performance or maintainability.
  • Simplicity: Avoid the complexity of dynamic models or JSON fields, offering a more structured and maintainable solution.

Key Features

  • Customizable Options: Allow tenants to define their own sets of values for form input while still offering global defaults.
  • Mandatory and Optional Defaults: Define which options are mandatory for all tenants and which can be optionally used by tenants in their forms.
  • Seamless Integration: Designed to work smoothly with your existing Django models, making it easy to integrate into your project.
  • Tenant-Specific Logic: Built-in support for tenant-specific logic, ensuring that each tenant’s unique needs are met.

Potential Use-Cases

django-tenant-options is versatile and can be applied to a wide range of scenarios across different industries. Here are some examples to illustrate its utility:

1. Project Management for Engineering Firms

Scenario: A Django-based project management tool used by multiple engineering firms.

  • Tenant Structure: Each engineering firm acts as a tenant, with employees as end-users.
  • Implementation: The app developer sets mandatory task statuses like "Assigned" and "Completed" for all firms. Each firm can then choose whether to include optional statuses like "In Review" or "Pending Approval," and even create their own unique statuses to fit their workflow. Likewise, the developer can provide mandatory task priorities like "High" and "Low," with firms able to add optional priorities like "Urgent" or "Deferred."

2. HR Management System

Scenario: An HR management system used within a large organization.

  • Tenant Structure: The HR department is the tenant, and different departments within the organization are the end-users.
  • Implementation: Mandatory job titles like "Manager" or "Team Lead" are predefined by the developer. The HR department can choose whether to include optional titles that were provided by the developer, and can create custom roles titles specific to their organizational structure.

3. Real Estate Management

Scenario: A property management tool for real estate companies.

  • Tenant Structure: Real estate companies are tenants, and agents are the end-users.
  • Implementation: Some property types like "Residential" are mandatorily available to agents in all companies. Companies can choose to make optional property types like "Commercial" available, and can also create custom categories like "Luxury" or "Affordable Housing" to match market segments.

4. Municipal Building Permit Management

Scenario: A system for managing building permits in various municipalities.

  • Tenant Structure: Municipalities are tenants, and residents or businesses are the end-users.
  • Implementation: Each municipality has mandatory permit types, required by Federal or State law, but they can also offer optional and custom permit types specific to local regulations.

5. Other Use-Cases

See additional use cases in the documentation for more inspiration.

Example Implementation

Consider a scenario where your SaaS provides project management tools for businesses. Each User is associated with a Tenant, and can create Tasks. You want each tenant to be able to customize the available task "priorities" and "status" provided in user-facing task tracking forms. Here’s how you can implement this with django-tenant-options.

🟩 Note

See the example project for the more detailed demonstration of how to set up a multi-tenant application with custom options using django-tenant-options.

Existing Models

We will define a very basic Tenant model and a Task model to illustrate the implementation. You can adapt this to your project's models as needed. In this example, it is assumed that the project already has a User model and the User model has a ForeignKey to the Tenant model. Your project's tenant architecture may (and probably will) differ.

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


User = get_user_model()


class Tenant(models.Model):
    """A very simplistic example of how one might implement a Tenant architecture."""
    name = models.CharField(max_length=100)
    subdomain = models.CharField(max_length=100, unique=True)

    def __str__(self):
        return self.name


class Task(models.Model):
    """A very simplistic example of a Task model."""

    title = models.CharField(max_length=100)
    description = models.TextField()
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="tasks")

Customizable Task Priorities

Each Set of options in django-tenant-options is defined by two models: an Option model, which stores all mandatory, optional, and custom options, and a Selection model, which identifies which options are currently associated with a tenant.

With a Tenant model and a Task model in your project, you can implement the TaskPriorityOption and TaskPrioritySelection models as follows:

from django.db import models

from django_tenant_options.models import AbstractOption, AbstractSelection, OptionType


class TaskPriorityOption(AbstractOption):
    """Concrete implementation of AbstractOption for TaskPriority."""
    tenant_model = "example.Tenant"  # Can be defined in settings.py for global use
    selection_model = "example.TaskPrioritySelection"
    default_options = {
        "Critical": {"option_type": OptionType.OPTIONAL},
        "High": {"option_type": OptionType.MANDATORY},
        "Medium": {"option_type": OptionType.OPTIONAL},
        "Low": {"option_type": OptionType.MANDATORY},
    }

    class Meta(AbstractOption.Meta):
        verbose_name = "Task Priority Option"
        verbose_name_plural = "Task Priority Options"


class TaskPrioritySelection(AbstractSelection):
    """Concrete implementation of AbstractSelection for TaskPriority."""
    tenant_model = "example.Tenant"  # Can be defined in settings.py for global use
    option_model = "example.TaskPriorityOption"

    class Meta(AbstractSelection.Meta):
        verbose_name = "Task Priority Selection"
        verbose_name_plural = "Task Priority Selections"

In each tenant's forms, the "High" and "Low" priorities will always be available for users to select in forms. Each tenant can also choose whether to make "Critical" and "Medium" priorities available to users, and they can create new priorities to meet their needs, offering a balance between predefined options and tenant-specific customization.

Finally, add priority and status ForeignKey fields on the Task model to the TaskPriorityOption and TaskStatusOption models respectively, allowing users to select from the various task priorities available to the tenant they belong to.

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

from example.models import TaskPriorityOption, TaskStatusOption, User


User = get_user_model()


class Tenant(models.Model):
    """A very simplistic example of how one might implement a Tenant architecture."""
    name = models.CharField(max_length=100)
    subdomain = models.CharField(max_length=100, unique=True)

    def __str__(self):
        return self.name


class Task(models.Model):
    """A very simplistic example of a Task model with priority and status."""

    title = models.CharField(max_length=100)
    description = models.TextField()
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="tasks")

    priority = models.ForeignKey(
        "example.TaskPriorityOption",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="tasks",
    )
    status = models.ForeignKey(
        "example.TaskStatusOption",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="tasks",
    )

Forms

django-tenant-options provides a set of forms to manage the options and selections for each tenant. You can use these forms in your views to allow tenants to customize their options.

from django import forms

from django_tenant_options.forms import OptionForm, SelectionForm

Management Commands

django-tenant-options provides management commands for easy maintenance:

  • listoptions: Lists all available options in the database.
  • syncoptions: Synchronizes the defaults in each model with the database when a change in the model has been made. Should always be run after any migrations have been completed.
  • maketriggers: Creates database trigger migrations to ensure there can never be mismatch between a Tenant and an associated Option.
python manage.py syncoptions

Conclusion

django-tenant-options makes it easy to provide your SaaS application’s tenants with customizable form options, while still maintaining the consistency and control needed to ensure a smooth user experience. Whether you're managing project tasks, HR roles, marketplace filters, or any other customizable value sets, this package offers a robust solution.

Explore the full documentation for more details and start empowering your tenants today!

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

django_tenant_options-2024.8.1.tar.gz (23.6 kB view details)

Uploaded Source

Built Distribution

django_tenant_options-2024.8.1-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file django_tenant_options-2024.8.1.tar.gz.

File metadata

File hashes

Hashes for django_tenant_options-2024.8.1.tar.gz
Algorithm Hash digest
SHA256 7ef878a95cd4393adaf3799cad7e1a057e0f5c8c41732d1ecb19e1b6f1816e15
MD5 485f7dfc442cfe10af3b8294ab191841
BLAKE2b-256 cd9c05f927b41315a651aa84a2f0c1780c1e6ec7ddb4e00b5c6f024c45908a45

See more details on using hashes here.

File details

Details for the file django_tenant_options-2024.8.1-py3-none-any.whl.

File metadata

File hashes

Hashes for django_tenant_options-2024.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 566ea6d80de9182c8938d690e58367606f69eaee00fd87dffa39586b989e9f52
MD5 cbe9c1c6fb1410505a1db65eaf115128
BLAKE2b-256 0d13f24b7edaf666078c89d95ef1d56ee0c2459418a9848b0664f7037a8eb69d

See more details on using hashes here.

Supported by

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