# apps/knowledge_base/models.py from django.db import models from django.utils import timezone from django.core.exceptions import ValidationError import uuid from apps.accounts.models import User class KnowledgeBase(models.Model): """知识库模型""" KNOWLEDGE_BASE_TYPES = [ ('admin', '管理级知识库'), ('leader', '部门级知识库'), ('member', '成员级知识库'), ('private', '私有知识库'), ('secret', '公司级别私密知识库'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user_id = models.UUIDField(verbose_name='创建者ID') name = models.CharField(max_length=100, unique=True, verbose_name='知识库名称') desc = models.TextField(verbose_name='知识库描述', null=True, blank=True) type = models.CharField( max_length=20, choices=KNOWLEDGE_BASE_TYPES, default='private', verbose_name='知识库类型' ) department = models.CharField(max_length=50, null=True, blank=True) group = models.CharField(max_length=50, null=True, blank=True) documents = models.JSONField(default=list) char_length = models.IntegerField(default=0) document_count = models.IntegerField(default=0) external_id = models.UUIDField(null=True, blank=True) create_time = models.DateTimeField(auto_now_add=True) update_time = models.DateTimeField(auto_now=True) def is_owner(self, user): """检查用户是否是所有者(通过权限表检查)""" from apps.permissions.models import KnowledgeBasePermission return str(user.id) == str(self.user_id) or KnowledgeBasePermission.objects.filter( knowledge_base=self, user=user, can_read=True, can_edit=True, can_delete=True, status='active' ).exists() def get_owners(self): """获取所有所有者(包括创建者和具有完整权限的用户)""" from apps.accounts.models import User from apps.permissions.models import KnowledgeBasePermission # 获取创建者 owners = [self.user_id] # 获取具有完整权限的用户 permission_owners = KnowledgeBasePermission.objects.filter( knowledge_base=self, can_read=True, can_edit=True, can_delete=True, status='active' ).values_list('user_id', flat=True) owners.extend(permission_owners) return User.objects.filter(id__in=set(owners)) def calculate_stats(self): """计算文档统计信息""" total_chars = 0 doc_count = 0 if self.documents: doc_count = len(self.documents) for doc in self.documents: if 'paragraphs' in doc: for para in doc['paragraphs']: if 'content' in para: total_chars += len(para['content']) if 'title' in para: total_chars += len(para['title']) return doc_count, total_chars def save(self, *args, **kwargs): """重写保存方法""" # 只在创建时计算统计信息 if not self.pk: # 如果是新实例 doc_count, char_count = self.calculate_stats() self.document_count = doc_count self.char_length = char_count # 直接调用Model的save方法 models.Model.save(self, *args, **kwargs) @classmethod def update_external_id(cls, instance_id, external_id): """更新外部ID的静态方法""" cls.objects.filter(id=instance_id).update(external_id=external_id) class Meta: indexes = [ models.Index(fields=['type']), models.Index(fields=['department']), models.Index(fields=['group']) ] def __str__(self): return f"{self.name} ({self.get_type_display()})" def clean(self): """验证知识库类型与创建者权限是否匹配""" try: user = User.objects.get(id=self.user_id) if user.role == 'member' and self.type != 'private': raise ValidationError('组员只能创建私人知识库') if user.role == 'leader' and self.type not in ['member', 'private']: raise ValidationError('组长只能创建成员级或私人知识库') except User.DoesNotExist: raise ValidationError('创建者不存在') def to_response_dict(self): """转换为API响应格式""" return { "create_time": self.create_time.isoformat(), "update_time": self.update_time.isoformat(), "id": str(self.id), "name": self.name, "desc": self.desc, "type": self.type, "user_id": str(self.user_id), "char_length": self.char_length, "document_count": self.document_count } def to_external_format(self): """转换为外部接口格式""" return { "name": self.name, "desc": self.desc, "documents": self.documents } class KnowledgeBaseDocument(models.Model): """知识库文档关联模型""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) knowledge_base = models.ForeignKey( KnowledgeBase, on_delete=models.CASCADE, related_name='kb_documents', verbose_name='知识库' ) document_id = models.CharField(max_length=100, verbose_name='文档ID') document_name = models.CharField(max_length=255, verbose_name='文档名称') external_id = models.CharField(max_length=100, verbose_name='外部文档ID') uploader_name = models.CharField(max_length=100, default="未知用户", verbose_name='上传者姓名') status = models.CharField( max_length=20, default='active', choices=[ ('active', '有效'), ('deleted', '已删除') ], verbose_name='状态' ) create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间') class Meta: unique_together = ['knowledge_base', 'document_id'] indexes = [ models.Index(fields=['knowledge_base', 'status']), models.Index(fields=['document_id']), models.Index(fields=['external_id']) ] verbose_name = '知识库文档' verbose_name_plural = '知识库文档' def __str__(self): return f"{self.knowledge_base.name} - {self.document_name}"