django-tenants added, and configurated customers app
This commit is contained in:
@@ -13,27 +13,32 @@ ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
|
||||
|
||||
|
||||
# APPS
|
||||
SHARED_APPS = [
|
||||
'django_tenants',
|
||||
'core.apps.customers',
|
||||
'django.contrib.contenttypes',
|
||||
]
|
||||
|
||||
DJANGO_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
|
||||
TENANT_APPS = [
|
||||
'core.apps.shared',
|
||||
]
|
||||
|
||||
PACKAGES = [
|
||||
PACKAGES = []
|
||||
|
||||
]
|
||||
|
||||
INSTALLED_APPS = DJANGO_APPS + PACKAGES + LOCAL_APPS
|
||||
INSTALLED_APPS = SHARED_APPS + DJANGO_APPS + PACKAGES + TENANT_APPS
|
||||
|
||||
# Middlewares
|
||||
MIDDLEWARE = [
|
||||
'django_tenants.middleware.main.TenantMainMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
@@ -65,7 +70,7 @@ WSGI_APPLICATION = 'config.wsgi.application'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'ENGINE': 'django_tenants.postgresql_backend',
|
||||
'NAME': env.str('POSTGRES_DB'),
|
||||
'USER': env.str('POSTGRES_USER'),
|
||||
'PASSWORD': env.str('POSTGRES_PASSWORD'),
|
||||
@@ -74,6 +79,10 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
|
||||
DATABASE_ROUTERS = (
|
||||
'django_tenants.routers.TenantSyncRouter',
|
||||
)
|
||||
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
@@ -103,3 +112,8 @@ MEDIA_ROOT = BASE_DIR / 'resources/media'
|
||||
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
# Django tenants
|
||||
TENANT_MODEL = "customers.Client"
|
||||
|
||||
TENANT_DOMAIN_MODEL = "customers.Domain"
|
||||
|
||||
0
core/apps/customers/__init__.py
Normal file
0
core/apps/customers/__init__.py
Normal file
2
core/apps/customers/admin/__init__.py
Normal file
2
core/apps/customers/admin/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .domain import *
|
||||
from .client import *
|
||||
11
core/apps/customers/admin/client.py
Normal file
11
core/apps/customers/admin/client.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from core.apps.customers.models import Client
|
||||
from core.apps.customers.admin.domain import DomainInline
|
||||
|
||||
|
||||
@admin.register(Client)
|
||||
class ClientAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'name', 'schema_name']
|
||||
search_fields = ['name']
|
||||
inlines = [DomainInline]
|
||||
8
core/apps/customers/admin/domain.py
Normal file
8
core/apps/customers/admin/domain.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from core.apps.customers.models import Domain
|
||||
|
||||
|
||||
class DomainInline(admin.TabularInline):
|
||||
model = Domain
|
||||
extra = 0
|
||||
10
core/apps/customers/apps.py
Normal file
10
core/apps/customers/apps.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CustomersConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'core.apps.customers'
|
||||
|
||||
def ready(self):
|
||||
import core.apps.customers.admin
|
||||
|
||||
22
core/apps/customers/management/commands/create_client.py
Normal file
22
core/apps/customers/management/commands/create_client.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from django.core.management import BaseCommand
|
||||
|
||||
from core.apps.customers.models import Client, Domain
|
||||
|
||||
class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
client_name = input('Mijoz nomini kiriting: ')
|
||||
schema_name = input('Schema nomini kiriting: ').lower()
|
||||
domain = input('Domain kiriting: ').lower()
|
||||
|
||||
client, created = Client.objects.get_or_create(
|
||||
name=client_name,
|
||||
schema_name=schema_name,
|
||||
)
|
||||
Domain.objects.get_or_create(
|
||||
domain=domain,
|
||||
tenant=client,
|
||||
is_primary=True
|
||||
)
|
||||
|
||||
self.stdout("Mijoz qo'shildi")
|
||||
|
||||
42
core/apps/customers/migrations/0001_initial.py
Normal file
42
core/apps/customers/migrations/0001_initial.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Generated by Django 5.2 on 2025-11-19 10:53
|
||||
|
||||
import django.db.models.deletion
|
||||
import django_tenants.postgresql_backend.base
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Client',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('schema_name', models.CharField(db_index=True, max_length=63, unique=True, validators=[django_tenants.postgresql_backend.base._check_schema_name])),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('paid_until', models.DateField()),
|
||||
('on_trial', models.BooleanField()),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Domain',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('domain', models.CharField(db_index=True, max_length=253, unique=True)),
|
||||
('is_primary', models.BooleanField(db_index=True, default=True)),
|
||||
('tenant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='domains', to='customers.client')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 5.2 on 2025-11-19 10:57
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('customers', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='client',
|
||||
name='on_trial',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='client',
|
||||
name='paid_until',
|
||||
),
|
||||
]
|
||||
0
core/apps/customers/migrations/__init__.py
Normal file
0
core/apps/customers/migrations/__init__.py
Normal file
2
core/apps/customers/models/__init__.py
Normal file
2
core/apps/customers/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from .client import *
|
||||
from .domain import *
|
||||
10
core/apps/customers/models/client.py
Normal file
10
core/apps/customers/models/client.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.db import models
|
||||
|
||||
from django_tenants.models import TenantMixin
|
||||
|
||||
|
||||
class Client(TenantMixin):
|
||||
name = models.CharField(max_length=100)
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
|
||||
auto_create_schema = True
|
||||
7
core/apps/customers/models/domain.py
Normal file
7
core/apps/customers/models/domain.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.db import models
|
||||
|
||||
from django_tenants.models import DomainMixin
|
||||
|
||||
|
||||
class Domain(DomainMixin):
|
||||
pass
|
||||
6
core/apps/customers/urls.py
Normal file
6
core/apps/customers/urls.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.urls import path
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
]
|
||||
0
core/apps/shared/__init__.py
Normal file
0
core/apps/shared/__init__.py
Normal file
6
core/apps/shared/apps.py
Normal file
6
core/apps/shared/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SharedConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'core.apps.shared'
|
||||
0
core/apps/shared/migrations/__init__.py
Normal file
0
core/apps/shared/migrations/__init__.py
Normal file
1
core/apps/shared/models/__init__.py
Normal file
1
core/apps/shared/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .base import *
|
||||
9
core/apps/shared/models/base.py
Normal file
9
core/apps/shared/models/base.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
0
core/apps/shared/urls.py
Normal file
0
core/apps/shared/urls.py
Normal file
@@ -1,5 +1,11 @@
|
||||
asgiref==3.10.0
|
||||
click==8.3.1
|
||||
Django==5.2
|
||||
django-environ==0.12.0
|
||||
django-tenants==3.9.0
|
||||
gunicorn==23.0.0
|
||||
h11==0.16.0
|
||||
packaging==25.0
|
||||
psycopg2-binary==2.9.11
|
||||
sqlparse==0.5.3
|
||||
uvicorn==0.38.0
|
||||
django-environ
|
||||
psycopg2-binary
|
||||
Reference in New Issue
Block a user