Files
flask_rulebase_serve/app/models.py
2026-04-22 13:35:40 +08:00

515 lines
20 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime
import enum
from sqlalchemy import JSON, DateTime, Enum, ForeignKey, Index, func
from app import db
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(50), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
status = db.Column(db.Integer, default=1, comment="用户状态1-正常0-禁用")
created_at = db.Column(db.DateTime, default=datetime.now, comment="创建时间")
updated_at = db.Column(
db.DateTime, default=datetime.now, onupdate=datetime.now, comment="更新时间"
)
# 自引用外键
created_by = db.Column(db.Integer, db.ForeignKey("users.id"))
updated_by = db.Column(db.Integer, db.ForeignKey("users.id"))
# 关系定义
creator = db.relationship(
"User", foreign_keys=[created_by], remote_side=[id], backref="created_users"
)
updater = db.relationship(
"User", foreign_keys=[updated_by], remote_side=[id], backref="updated_users"
)
# 关联关系
roles = db.relationship(
"Role",
secondary="user_roles",
back_populates="users",
foreign_keys="[UserRole.user_id, UserRole.role_id]",
) # 明确指定外键)
created_roles = db.relationship(
"Role", backref="creator", foreign_keys="Role.created_by"
)
updated_roles = db.relationship(
"Role", backref="updater", foreign_keys="Role.updated_by"
)
def __repr__(self):
return f"<User {self.username}>"
class Role(db.Model):
__tablename__ = "roles"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), unique=True, nullable=False, comment="角色名称")
description = db.Column(db.String(255), comment="角色描述")
status = db.Column(db.Integer, default=1, comment="状态1-启用0-禁用")
created_at = db.Column(db.DateTime, default=datetime.now)
updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
# 外键字段
created_by = db.Column(db.Integer, db.ForeignKey("users.id"))
updated_by = db.Column(db.Integer, db.ForeignKey("users.id"))
# 关系定义
users = db.relationship(
"User",
secondary="user_roles",
back_populates="roles",
foreign_keys="[UserRole.role_id, UserRole.user_id]",
)
permissions = db.relationship(
"Permission", secondary="role_permissions", back_populates="roles"
)
def __repr__(self):
return f"<Role {self.name}>"
class UserRole(db.Model):
__tablename__ = "user_roles"
user_id = db.Column(db.Integer, db.ForeignKey("users.id"), primary_key=True)
role_id = db.Column(db.Integer, db.ForeignKey("roles.id"), primary_key=True)
created_at = db.Column(db.DateTime, default=datetime.now)
created_by = db.Column(db.Integer, db.ForeignKey("users.id"))
# 关系定义
user = db.relationship("User", foreign_keys=[user_id], backref="role_assignments")
role = db.relationship("Role", foreign_keys=[role_id], backref="user_assignments")
creator_rel = db.relationship(
"User", foreign_keys=[created_by], backref="created_assignments"
)
def __repr__(self):
return f"<UserRole user={self.user_id} role={self.role_id}>"
class Permission(db.Model):
__tablename__ = "permissions"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
code = db.Column(
db.String(100), unique=True, nullable=False, comment="权限码(资源:操作)"
)
description = db.Column(db.String(255), comment="权限描述")
category = db.Column(db.String(50), comment="权限分类(如用户管理、系统设置)")
created_at = db.Column(db.DateTime, default=datetime.now)
updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)
# 外键字段
created_by = db.Column(db.Integer, db.ForeignKey("users.id"))
updated_by = db.Column(db.Integer, db.ForeignKey("users.id"))
# 关系定义
roles = db.relationship(
"Role", secondary="role_permissions", back_populates="permissions"
)
creator = db.relationship(
"User", foreign_keys=[created_by], backref="created_permissions"
)
updater = db.relationship(
"User", foreign_keys=[updated_by], backref="updated_permissions"
)
def __repr__(self):
return f"<Permission {self.code}>"
class RolePermission(db.Model):
__tablename__ = "role_permissions"
role_id = db.Column(db.Integer, db.ForeignKey("roles.id"), primary_key=True)
permission_id = db.Column(
db.Integer, db.ForeignKey("permissions.id"), primary_key=True
)
created_at = db.Column(db.DateTime, default=datetime.now)
created_by = db.Column(db.Integer, db.ForeignKey("users.id"))
# 关系定义
role = db.relationship(
"Role", foreign_keys=[role_id], backref="permission_assignments"
)
permission = db.relationship(
"Permission", foreign_keys=[permission_id], backref="role_assignments"
)
creator = db.relationship(
"User", foreign_keys=[created_by], backref="created_role_permissions"
)
def __repr__(self):
return f"<RolePermission role={self.role_id} perm={self.permission_id}>"
class Fst(db.Model):
__tablename__ = "fst"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255, collation="utf8mb4_unicode_ci"), nullable=False)
parent_id = db.Column(db.Integer, db.ForeignKey("fst.id"))
update_time = db.Column(
db.DateTime, default=func.current_timestamp(), nullable=False
)
reserved_json = db.Column(JSON)
bag_sum = db.Column(db.Integer)
level = db.Column(
db.SmallInteger, comment="标签层级0最高1=一级, 2=二级, 3=三级, 4=四级"
)
name_cn = db.Column(db.String(255, collation="utf8mb4_unicode_ci"), comment="中文")
annotation = db.Column(
db.String(500, collation="utf8mb4_unicode_ci"), comment="标签注释"
)
# 自引用关系(树形结构)
children = db.relationship(
"Fst", backref=db.backref("parent", remote_side=[id]), lazy="dynamic"
)
def __repr__(self):
return f"<Fst {self.name}>"
class OperationHistory(db.Model):
__tablename__ = "operation_history"
id = db.Column(
db.BigInteger, primary_key=True, autoincrement=True, comment="主键ID"
)
user_id = db.Column(db.BigInteger, nullable=False, comment="用户ID")
username = db.Column(db.String(50), nullable=False, comment="用户名")
api_path = db.Column(db.String(255), nullable=False, comment="接口路径")
http_method = db.Column(db.String(10), nullable=False, comment="HTTP方法")
operation_time = db.Column(db.DateTime, default=datetime.now, comment="操作时间")
request_params = db.Column(db.Text, comment="请求参数")
response_code = db.Column(db.Integer, comment="响应状态码")
ip_address = db.Column(db.String(45), comment="客户端IP地址")
user_agent = db.Column(db.String(255), comment="用户代理信息")
operation_result = db.Column(db.Integer, default=1, comment="1=成功,0=失败")
error_message = db.Column(db.String(255), comment="错误信息")
trace_id = db.Column(db.String(50), comment="请求追踪ID")
# 索引在SQLAlchemy中通过__table_args__定义
__table_args__ = (
db.Index("idx_user_id", "user_id"),
db.Index("idx_operation_time", "operation_time"),
db.Index("idx_api_path", "api_path"),
db.Index("idx_user_operation", "user_id", "operation_time"),
)
def __repr__(self):
return f"<OperationHistory {self.api_path} by {self.username}>"
# ===== 枚举类型定义 =====
class BagStatus(enum.Enum):
UNPROCESSED = "UNPROCESSED"
PROCESSED_NOT_A_CANDIDATE = "PROCESSED_NOT_A_CANDIDATE"
PROCESSED_NOT_REVIEWED = "PROCESSED_NOT_REVIEWED"
REVIEW_IN_PROGRESS = "REVIEW_IN_PROGRESS"
RULE_BASED_ACCEPTED = "RULE_BASED_ACCEPTED"
MANUAL_OVERRIDE_ACCEPTED = "MANUAL_OVERRIDE_ACCEPTED"
REVIEWED_BUT_INVALID = "REVIEWED_BUT_INVALID"
class EventSource(enum.Enum):
RULE = "RULE"
MANUAL = "MANUAL"
class VerdictStatus(enum.Enum):
ACCEPTED = "ACCEPTED"
OVERRIDDEN = "OVERRIDDEN"
class OperationResult(enum.Enum):
SUCCESS = 1
FAILURE = 0
class QaStatus(enum.Enum):
QA_NOT_REVIEWED = "QA_NOT_REVIEWED"
QA_PASSED = "QA_PASSED"
QA_MODIFY = "QA_MODIFY"
QA_INVALID = "QA_INVALID"
class SyncStatus(enum.Enum):
SYNC_NOT_READY = "SYNC_NOT_READY"
SYNCED = "SYNCED"
# ===== 核心数据模型 =====
class RuleVersions(db.Model):
"""规则版本表"""
__tablename__ = "rule_versions"
rule_version_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
ruleset_name = db.Column(db.String(128), nullable=False)
version_str = db.Column(db.String(32), nullable=False)
description = db.Column(db.Text)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
__table_args__ = (
db.UniqueConstraint("ruleset_name", "version_str", name="uk_ruleset_version"),
)
class Reviewers(db.Model):
"""审核人员表"""
__tablename__ = "reviewers"
reviewer_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
login_name = db.Column(db.String(64), unique=True, nullable=False)
display_name = db.Column(db.String(128))
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
# ===== 业务数据模型 =====
class BagFile(db.Model):
"""BAG文件主表"""
__tablename__ = "bag_file"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
file_name = db.Column(db.String(255), nullable=False, comment="bag名称")
event = db.Column(db.String(255), comment="event")
file_path = db.Column(db.String(500))
capture_datetime = db.Column(
db.DateTime, nullable=False, comment="采集时间(含时分秒)"
)
vehicle_status = db.Column(JSON, comment="车辆状态JSON")
user_id = db.Column(db.Integer, ForeignKey("users.id"), comment="操作用户id")
create_time = db.Column(
db.DateTime, default=db.func.current_timestamp(), comment="标签的创建时间"
)
update_time = db.Column(
db.DateTime,
default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp(),
comment="标签的更新时间",
)
car_state = db.Column(db.SmallInteger, comment="车辆状态: 0=静止, 1=运动")
frame_url = db.Column(db.String(500), comment="图片url")
video_url = db.Column(db.String(500), comment="视频url")
level1_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="一级标签id")
level2_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="二级标签id")
level3_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="三级标签id")
level4_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="四级标签id")
batch_name = db.Column(db.String(255), comment="批次名称")
status = db.Column(
Enum(BagStatus),
nullable=False,
default=BagStatus.PROCESSED_NOT_REVIEWED,
comment="处理的状态",
)
last_time = db.Column(db.DateTime, comment="最后处理的时间")
last_rule_version_id = db.Column(
db.Integer,
ForeignKey("rule_versions.rule_version_id"),
comment="rule_versions的外键",
)
front_starttime = db.Column(db.DateTime, comment="前摄像头的开始时间")
front_endtime = db.Column(db.DateTime, comment="前摄像头的结束时间")
case_type = db.Column(db.Integer, comment="1简单场景;2复杂场景")
comment1 = db.Column(db.String(255), comment="注释1")
comment2 = db.Column(db.String(255), comment="注释2")
comment3 = db.Column(db.String(255), comment="注释3")
bag_status = db.Column(db.Integer, comment="标签状态0开始1更新")
# 新增字段
qa_status = db.Column(
Enum(QaStatus),
nullable=False,
default=QaStatus.QA_NOT_REVIEWED,
comment="质检的状态",
)
sync_status = db.Column(
Enum(SyncStatus),
nullable=False,
default=SyncStatus.SYNC_NOT_READY,
comment="同步的状态",
)
fst_version = db.Column(db.String(255), comment="fst版本")
front_start_sec = db.Column(db.Integer, comment="前摄的开始秒")
front_end_sec = db.Column(db.Integer, comment="前摄的结束秒")
bag_update_time = db.Column(
db.DateTime, default=db.func.current_timestamp(), comment="bag的更新时间"
)
qa_confirm_time = db.Column(
db.DateTime, default=db.func.current_timestamp(), comment="qa的确认时间"
)
db_time = db.Column(
db.DateTime,
default=db.func.current_timestamp(),
comment="更新到远程数据库的时间",
)
qa_id = db.Column(db.Integer, ForeignKey("users.id"),comment="操作用户id")
high_speed = db.Column(db.Integer, comment="高速,1是,0否")
urban = db.Column(db.Integer, comment="城区,1是,0否")
parking = db.Column(db.Integer, comment="停车,1是,0否")
# 关系定义
user = db.relationship("User", foreign_keys=[user_id],backref="bag_files")
rule_version = db.relationship("RuleVersions", backref="bag_files")
level1_tag = db.relationship("Fst", foreign_keys=[level1_tag_id])
level2_tag = db.relationship("Fst", foreign_keys=[level2_tag_id])
level3_tag = db.relationship("Fst", foreign_keys=[level3_tag_id])
level4_tag = db.relationship("Fst", foreign_keys=[level4_tag_id])
qa_user = db.relationship('User', foreign_keys=[qa_id], backref='qa_bag_files')
__table_args__ = (
db.Index("idx_capture_time", "capture_datetime"),
db.Index("status", "status"),
db.Index("idx_bag_file_name", "file_name"),
)
class TaggingEvents(db.Model):
"""标签事件记录表"""
__tablename__ = "tagging_events"
event_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
bag_id = db.Column(
db.Integer, ForeignKey("bag_file.id"), nullable=False, comment="bag的id"
)
source = db.Column(Enum(EventSource), nullable=False, comment="来源")
rule_version_id = db.Column(
db.Integer, ForeignKey("rule_versions.rule_version_id"), comment="rule版本id"
)
# reviewer_id = db.Column(db.Integer, ForeignKey('reviewers.reviewer_id'),
# comment='审核人id')
reviewer_id = db.Column(db.Integer, ForeignKey("users.id"), comment="审核人id")
verdict = db.Column(Enum(VerdictStatus), comment="结论")
ts_event = db.Column(
db.DateTime, default=db.func.current_timestamp(), comment="当前时间"
)
level1_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="一级标签id")
level2_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="二级标签id")
level3_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="三级标签id")
level4_tag_id = db.Column(db.Integer, ForeignKey("fst.id"), comment="四级标签id")
case_type = db.Column(db.Integer, comment="1简单场景;2复杂场景")
front_starttime = db.Column(db.DateTime, comment="前摄像头开始时间")
front_endtime = db.Column(db.DateTime, comment="前摄像头结束时间")
front_start_sec = db.Column(db.Integer, comment="前摄的开始秒")
front_end_sec = db.Column(db.Integer, comment="前摄的结束秒")
high_speed = db.Column(db.Integer, comment="高速,1是,0否")
urban = db.Column(db.Integer, comment="城区,1是,0否")
parking = db.Column(db.Integer, comment="停车,1是,0否")
qa_status = db.Column(
Enum(QaStatus),
nullable=False,
default=QaStatus.QA_NOT_REVIEWED,
comment="质检状态",
)
is_deleted = db.Column(
db.Boolean,
nullable=False,
default=False,
comment="soft delete flag",
)
note = db.Column(db.Text, comment="备注")
# 关系定义
bag = db.relationship("BagFile", backref="tagging_events")
rule_version = db.relationship("RuleVersions")
reviewer = db.relationship("User")
level1_tag = db.relationship("Fst", foreign_keys=[level1_tag_id])
level2_tag = db.relationship("Fst", foreign_keys=[level2_tag_id])
level3_tag = db.relationship("Fst", foreign_keys=[level3_tag_id])
level4_tag = db.relationship("Fst", foreign_keys=[level4_tag_id])
__table_args__ = (db.Index("idx_evt_bag_ts", "bag_id", "ts_event"),)
class VlmFilter(db.Model):
__tablename__ = 'vlm_filter'
id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键')
bag_name = db.Column(db.String(255), nullable=True, comment='bag的名称')
level1_tag_id = db.Column(db.Integer, db.ForeignKey('fst.id', ondelete='CASCADE', onupdate='CASCADE'),
nullable=True, index=True, comment='一级标签id')
level2_tag_id = db.Column(db.Integer, db.ForeignKey('fst.id', ondelete='CASCADE', onupdate='CASCADE'),
nullable=True, index=True, comment='二级标签id')
level3_tag_id = db.Column(db.Integer, db.ForeignKey('fst.id', ondelete='CASCADE', onupdate='CASCADE'),
nullable=True, index=True, comment='三级标签id')
level4_tag_id = db.Column(db.Integer, db.ForeignKey('fst.id', ondelete='CASCADE', onupdate='CASCADE'),
nullable=True, index=True, comment='四级标签id')
video_url = db.Column(db.String(255), nullable=True, comment='视频路径')
comment = db.Column(db.String(255), nullable=True, comment='备注')
user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE', onupdate='CASCADE'),
nullable=True, index=True, comment='写入的用户')
collection_time = db.Column(db.DateTime, nullable=True, comment='标签采集时间')
create_time = db.Column(db.DateTime, nullable=True, comment='写入的时间')
init_label = db.Column(db.Integer, nullable=True, comment='入库的状态0是标注1是质检')
status = db.Column(db.Integer, nullable=True, comment='入库的状态0是标注1是质检')
# 可以根据需要添加关系引用
level1_tag = db.relationship('Fst', foreign_keys=[level1_tag_id])
level2_tag = db.relationship('Fst', foreign_keys=[level2_tag_id])
level3_tag = db.relationship('Fst', foreign_keys=[level3_tag_id])
level4_tag = db.relationship('Fst', foreign_keys=[level4_tag_id])
user = db.relationship('User', foreign_keys=[user_id])
class BagMergeRecord(db.Model):
__tablename__ = "bag_merge_record"
id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键')
joined_name = db.Column(
db.String(255),
nullable=False,
index=True,
comment="合并后 bag 名称joined_name"
)
src_name = db.Column(
db.String(255),
nullable=False,
index=True,
comment="参与合并的原始 bag 名称"
)
is_initiator = db.Column(
db.Boolean,
nullable=False,
default=False,
comment="是否为本次合并操作的主 bag发起合并的那个 src",
)
create_time = db.Column(
db.DateTime,
default=db.func.current_timestamp(),
comment="记录创建时间",
)
created_by = db.Column(
db.Integer,
db.ForeignKey("users.id"),
index=True,
comment="操作用户 id",
)
# 可选:反向关系,如果有需要
creator = db.relationship("User", backref="bag_merge_records")
__table_args__ = (
# 如果希望避免“同一个 joined_name + src_name 被插入多次”,可以加一个联合唯一约束:
# db.UniqueConstraint("joined_name", "src_name", name="uk_joined_src"),
)