76 lines
2.1 KiB
Python
76 lines
2.1 KiB
Python
"""租户范围模型的抽象基类。
|
||
|
||
所有业务表都应该继承 TenantScopedModel,自动获得:
|
||
- tenant_id 外键
|
||
- org_id 外键(可选,预留多组织)
|
||
- 标准审计字段(created_at, updated_at, created_by, updated_by, is_deleted)
|
||
- manager `for_tenant(tenant)` 自动加过滤
|
||
"""
|
||
|
||
from django.conf import settings
|
||
from django.db import models
|
||
|
||
|
||
class TenantScopedQuerySet(models.QuerySet):
|
||
def for_tenant(self, tenant):
|
||
return self.filter(tenant=tenant)
|
||
|
||
def for_org(self, org):
|
||
return self.filter(org=org)
|
||
|
||
def active(self):
|
||
return self.filter(is_deleted=False)
|
||
|
||
|
||
class TenantScopedModel(models.Model):
|
||
tenant = models.ForeignKey(
|
||
"core.Tenant",
|
||
on_delete=models.PROTECT,
|
||
related_name="+",
|
||
help_text="所属租户",
|
||
)
|
||
org = models.ForeignKey(
|
||
"core.Org",
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.PROTECT,
|
||
related_name="+",
|
||
help_text="所属组织(多机构预留)",
|
||
)
|
||
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
created_by = models.ForeignKey(
|
||
settings.AUTH_USER_MODEL,
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
related_name="+",
|
||
)
|
||
updated_by = models.ForeignKey(
|
||
settings.AUTH_USER_MODEL,
|
||
null=True,
|
||
blank=True,
|
||
on_delete=models.SET_NULL,
|
||
related_name="+",
|
||
)
|
||
|
||
# 软删除预留
|
||
is_deleted = models.BooleanField(default=False)
|
||
deleted_at = models.DateTimeField(null=True, blank=True)
|
||
|
||
# 扩展 JSON 字段:存自定义属性/第三方对接数据/AI 抽取结果
|
||
ext_data = models.JSONField(default=dict, blank=True)
|
||
|
||
# 来源渠道(预留 AI Agent / 电商对接):manual/api/web/miniprogram/ai_agent
|
||
source_channel = models.CharField(max_length=32, blank=True, default="manual")
|
||
|
||
objects = TenantScopedQuerySet.as_manager()
|
||
|
||
class Meta:
|
||
abstract = True
|
||
indexes = [
|
||
models.Index(fields=["tenant", "-created_at"]),
|
||
models.Index(fields=["tenant", "is_deleted"]),
|
||
]
|