0

AccrediDoc - Multi-tenant Accreditation Management System

A comprehensive Django-based multi-tenant accreditation management system designed for healthcare organizations in India. Manage NABL, NABH, ISO 15189 and other healthcare accreditations with ease.

Features

  • Multi-tenant Architecture: Secure, isolated environments for multiple organizations
  • Document Management: Upload, version, and track accreditation documents with expiry alerts
  • Compliance Tracking: Monitor compliance status with interactive checklists and evidence tracking
  • User Management: Role-based access control with different user roles
  • Accreditation Types: Support for multiple accreditation standards and clauses
  • Reporting: Generate comprehensive compliance and performance reports
  • Audit Logging: Complete audit trail for all system activitieswhile running migration for sharred schema i got following error

it is multitenant Django app with five different apps

System check identified some issues:

WARNINGS:
?: (staticfiles.W004) The directory 'D:\workik_projects\AccrediDoc_V3\static' in the STATICFILES_DIRS setting does not exist.
[standard:public] === Starting migration
[standard:public] System check identified some issues:

WARNINGS:
?: (staticfiles.W004) The directory 'D:\workik_projects\AccrediDoc_V3\static' in the STATICFILES_DIRS setting does not exist.
[standard:public] Operations to perform:
[standard:public]   Apply all migrations: admin, auth, contenttypes, django_celery_beat, sessions
[standard:public] Running migrations:
[standard:public]   Applying admin.0001_initial...
Traceback (most recent call last):
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\utils.py", line 103, in _execute
    return self.cursor.execute(sql)
psycopg2.errors.UndefinedTable: relation "users_user" does not exist


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "D:\workik_projects\AccrediDoc_V3\manage.py", line 19, in <module>
    main()
  File "D:\workik_projects\AccrediDoc_V3\manage.py", line 16, in main
    execute_from_command_line(sys.argv)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\base.py", line 413, in run_from_argv
    self.execute(*args, **cmd_options)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\base.py", line 459, in execute
    output = self.handle(*args, **options)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django_tenants\management\commands\migrate_schemas.py", line 66, in handle
    executor.run_migrations(tenants=[self.PUBLIC_SCHEMA_NAME])
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django_tenants\migration_executors\standard.py", line 11, in run_migrations
    run_migrations(self.args, self.options, self.codename, self.PUBLIC_SCHEMA_NAME)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django_tenants\migration_executors\base.py", line 61, in run_migrations
    migrate_command_class(stdout=stdout, stderr=stderr).execute(*args, **options)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\base.py", line 459, in execute
    output = self.handle(*args, **options)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\base.py", line 107, in wrapper
    res = handle_func(*args, **kwargs)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\core\management\commands\migrate.py", line 356, in handle
    post_migrate_state = executor.migrate(
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\migrations\executor.py", line 135, in migrate
    state = self._migrate_all_forwards(
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\migrations\executor.py", line 167, in _migrate_all_forwards
    state = self.apply_migration(
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\migrations\executor.py", line 249, in apply_migration
    with self.connection.schema_editor(
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\base\schema.py", line 166, in __exit__
    self.execute(sql)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\postgresql\schema.py", line 48, in execute
    return super().execute(sql, None)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\base\schema.py", line 201, in execute
    cursor.execute(sql, params)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\utils.py", line 122, in execute
    return super().execute(sql, params)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\utils.py", line 79, in execute
    return self._execute_with_wrappers(
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\utils.py", line 100, in _execute
    with self.db.wrap_database_errors:
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "D:\workik_projects\AccrediDoc_V3\acc_venv\lib\site-packages\django\db\backends\utils.py", line 103, in _execute
    return self.cursor.execute(sql)
django.db.utils.ProgrammingError: relation "users_user" does not exis

Project Structure

accredidoc/
    ├── core/                 # Core app with tenant models
    ├── tenants/             # Tenant management
    ├── users/               # Custom user models and authentication
    ├── accreditation/       # Accreditation types and clauses
    ├── documents/           # Document management
    ├── checklists/          # Compliance checklists
    ├── reports/            # Reporting functionality
    ├── notifications/       # Notification system
    ├── audit/              # Audit logging
    └── templates/          # HTML templates

Setting.py

import os
from pathlib import Path
import environ

env = environ.Env()
environ.Env.read_env()

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = env('SECRET_KEY', default='insecure-secret-key-change-in-production')
DEBUG = env.bool('DEBUG', True)
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['localhost', '127.0.0.1'])

SHARED_APPS = [
    'django_tenants',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crispy_forms',
    'crispy_bootstrap5',
    'django_htmx',
    'django_celery_beat',
    'core',
    'tenants',
]

TENANT_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users',
    'accreditation',
    'documents',
    'checklists',
    'notifications',
    'reports',
    'audit',
]

INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS]

MIDDLEWARE = [
    'django_tenants.middleware.TenantMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django_htmx.middleware.HtmxMiddleware',
]

ROOT_URLCONF = 'accredidoc.urls_public'
PUBLIC_SCHEMA_URLCONF = 'accredidoc.urls_public'

DATABASE_ROUTERS = ('django_tenants.routers.TenantSyncRouter',)

TENANT_MODEL = "tenants.Tenant"
TENANT_DOMAIN_MODEL = "tenants.Domain"

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'core.context_processors.tenant_context',
            ],
        },
    },
]

DATABASES = {
    'default': {
        'ENGINE': 'django_tenants.postgresql_backend',
        'NAME': env('DB_NAME', default=''),
        'USER': env('DB_USER', default=''),
        'PASSWORD': env('DB_PASSWORD', default=''),
        'HOST': env('DB_HOST', default=''),
        'PORT': env('DB_PORT', default='5432'),
    }
}

AUTH_USER_MODEL = 'users.User'

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [BASE_DIR / 'static']

MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

CELERY_BROKER_URL = env('REDIS_URL', default='redis://localhost:6379/0')
CELERY_RESULT_BACKEND = env('REDIS_URL', default='redis://localhost:6379/0')

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'INFO',
    },
}

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'public_home'

users/models.py

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

class User(AbstractUser):
    ROLE_CHOICES = [
        ('super_admin', 'Super Admin'),
        ('org_admin', 'Organization Admin'),
        ('dept_user', 'Department User'),
        ('auditor', 'Auditor'),
    ]
    
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='dept_user')
    tenant = models.ForeignKey('tenants.Tenant', on_delete=models.CASCADE, null=True, blank=True)
    phone = models.CharField(max_length=15, blank=True)
    department = models.CharField(max_length=100, blank=True)

    class Meta:
        db_table = 'users_user'

    def __str__(self):
        return f"{self.username} ({self.role})"
5
  • Did you run python manage.py makemigrations followed by python manage.py migrate? Commented Nov 7 at 17:16
  • yes even after deleting and creating new database Commented Nov 7 at 18:12
  • I think your middleware configuration might be wrong. You have django_tenants.middleware.TenantMiddleware but according to the docs, it should be django_tenants.middleware.main.TenantMainMiddleware Commented Nov 8 at 2:38
  • Fix that and run migrations. If issue persists, and you're still in development, then you might want to consider dropping the database. Commented Nov 8 at 2:41
  • BTW see if this helps stackoverflow.com/questions/39963346/… Commented Nov 8 at 5:56

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.