feat: 完成 SyncHistory 和 FileAttribute 的迁移
数据库迁移内容: 1. 新增 FileAttribute 表(文件属性) - 支持键值对存储 - 支持嵌套属性(点号分隔的路径) - 支持属性类型(string/integer/float/boolean/json) - 支持属性分类和元数据 2. 更新 LobsterMemory 表 - 新增 has_attributes 字段 - 关联 FileAttribute 3. 更新 SyncHistory 表 - 新增 attributes_changed 字段(属性变更记录) - 新增 is_attribute_sync 字段(属性同步标记) 属性目录结构逻辑: - 使用点号分隔的键名(如 'author.name', 'metadata.tags') - 支持属性继承和嵌套查询 - 支持属性分类和索引优化 已完成迁移文件: - 0003_add_file_attribute.py
This commit is contained in:
@@ -36,6 +36,8 @@ class LobsterMemory(models.Model):
|
||||
|
||||
summary = models.TextField(null=True, blank=True, max_length=1000, help_text='语义摘要')
|
||||
|
||||
has_attributes = models.BooleanField(default=False, help_text='是否有属性')
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, db_index=True, help_text='创建时间')
|
||||
|
||||
updated_at = models.DateTimeField(auto_now=True, db_index=True, help_text='更新时间')
|
||||
@@ -74,6 +76,69 @@ class LobsterMemory(models.Model):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class FileAttribute(models.Model):
|
||||
"""文件属性模型(支持属性目录结构)"""
|
||||
|
||||
VALUE_TYPE_CHOICES = [
|
||||
('string', '字符串'),
|
||||
('integer', '整数'),
|
||||
('float', '浮点数'),
|
||||
('boolean', '布尔值'),
|
||||
('json', 'JSON'),
|
||||
]
|
||||
|
||||
lobster_id = models.CharField(max_length=50, db_index=True, help_text='龙虾ID')
|
||||
|
||||
file_path = models.CharField(max_length=500, db_index=True, help_text='文件相对路径')
|
||||
|
||||
key = models.CharField(max_length=200, db_index=True, help_text='属性键(支持点号分隔的嵌套路径)')
|
||||
|
||||
value = models.TextField(null=True, blank=True, help_text='属性值')
|
||||
|
||||
value_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=VALUE_TYPE_CHOICES,
|
||||
default='string',
|
||||
help_text='值类型'
|
||||
)
|
||||
|
||||
category = models.CharField(max_length=100, db_index=True, null=True, blank=True, help_text='属性分类')
|
||||
|
||||
metadata = models.JSONField(default=dict, help_text='元数据')
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, db_index=True, help_text='创建时间')
|
||||
|
||||
updated_at = models.DateTimeField(auto_now=True, help_text='更新时间')
|
||||
|
||||
class Meta:
|
||||
db_table = 'file_attribute'
|
||||
unique_together = ('lobster_id', 'file_path', 'key')
|
||||
ordering = ['lobster_id', 'file_path', 'key']
|
||||
indexes = [
|
||||
models.Index(fields=['lobster_id', 'file_path']),
|
||||
models.Index(fields=['lobster_id', 'category']),
|
||||
models.Index(fields=['lobster_id', 'updated_at']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.lobster_id}/{self.file_path}.{self.key} = {self.value}"
|
||||
|
||||
def get_parsed_value(self):
|
||||
"""根据类型解析值"""
|
||||
if self.value_type == 'string':
|
||||
return self.value
|
||||
elif self.value_type == 'integer':
|
||||
return int(self.value) if self.value else None
|
||||
elif self.value_type == 'float':
|
||||
return float(self.value) if self.value else None
|
||||
elif self.value_type == 'boolean':
|
||||
return self.value.lower() in ('true', '1', 'yes') if self.value else False
|
||||
elif self.value_type == 'json':
|
||||
import json
|
||||
return json.loads(self.value) if self.value else None
|
||||
return self.value
|
||||
|
||||
|
||||
class SyncHistory(models.Model):
|
||||
"""同步操作历史记录"""
|
||||
|
||||
@@ -83,6 +148,7 @@ class SyncHistory(models.Model):
|
||||
('auto_sync', '自动同步'),
|
||||
('manual_merge', '手动合并'),
|
||||
('conflict_resolved', '冲突解决'),
|
||||
('attribute_sync', '属性同步'),
|
||||
]
|
||||
|
||||
STATUS_CHOICES = [
|
||||
@@ -138,6 +204,10 @@ class SyncHistory(models.Model):
|
||||
|
||||
execution_time = models.FloatField(default=0, help_text='执行时间(秒)')
|
||||
|
||||
attributes_changed = models.JSONField(default=dict, help_text='属性变更记录')
|
||||
|
||||
is_attribute_sync = models.BooleanField(default=False, help_text='是否为属性同步')
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, db_index=True, help_text='操作时间')
|
||||
|
||||
class Meta:
|
||||
|
||||
Reference in New Issue
Block a user