一、工作进度汇报
本周主要完成后端数据模型的设计工作,数据模型定义了数据库表结构,是整个后端系统的核心,所有的业务数据都存储在这些表中。
在模型设计方面,我们完成了5个核心数据模型的设计。TeacherScore模型是教师评分表,存储教师对项目的评分记录,包含5个评分维度和评语字段。Submission模型是项目提交表,存储学生提交的项目信息,包含基本信息、文件信息、状态等字段。Repository模型是项目仓库表,存储Git仓库信息,包含仓库URL、类型、状态等字段。CodeAnalysis模型是代码分析表,存储代码分析结果,包含代码行数、语言分布、质量指标等字段。Course模型是课程表,存储课程信息,包含课程名称、描述等字段。每个模型都包含了完整的字段定义、关系映射、时间戳处理等功能。模型之间建立了清晰的关系映射,使用SQLAlchemy的relationship实现关联查询。
本周共设计5张数据表,约50个数据库字段,定义了8个表关系。每个模型都包含创建时间、更新时间等审计字段,便于后续的问题排查和数据追溯。
二、项目处理思路
数据模型之间的关系设计是数据库设计的核心。在本项目中,我们设计了以下关系:用户(User)和项目提交(Submission)是一对多关系,一个用户可以提交多个项目,但一个项目只属于一个用户。教师评分(TeacherScore)和项目提交(Submission)是一对多关系,一个项目可以被多个教师评分,但每个评分记录只属于一个项目。教师评分(TeacherScore)和用户(User)是一对多关系,一个教师可以给多个项目评分,但每个评分记录只属于一个教师。项目提交(Submission)和仓库(Repository)是一对一关系,一个项目对应一个Git仓库。这种关系设计既保证了数据的完整性,又避免了数据冗余。使用外键约束可以确保引用的数据存在,避免出现孤立记录。使用Cascade可以自动处理关联数据的级联操作。
字段类型的选择需要考虑数据的特性和存储效率。整数类型(Integer)用于ID、主键等数值,查询效率最高,是最常用的字段类型。字符串类型(String)用于短文本如名称、邮箱等,占用空间适中。文本类型(Text)用于长文本如项目描述,可以存储大量内容。枚举类型(Enum)用于有限状态如项目状态,类型安全且便于扩展。时间类型(DateTime)用于时间戳,自动记录创建和更新时间。JSON类型(JSON)用于动态数据如扩展信息,可以存储不固定结构的字段。这种字段类型选择既满足了数据存储需求,又优化了存储空间。选择合适的字段类型可以提高查询性能,减少存储空间。
外键是保证数据完整性的重要手段。在本项目中,所有需要关联的表都使用了外键。外键可以确保引用的数据存在,避免出现孤立记录。外键配合Cascade可以自动处理关联数据的级联操作,例如删除项目时自动删除相关的评分记录。这种外键设计既保证了数据完整性,又简化了业务代码。不需要在业务逻辑中手动检查关联数据是否存在,数据库会自动处理。
三、框架搭建思路
数据库相关的文件放在了models目录下,每个模型一个文件,方便管理和维护。db目录存放数据库连接和初始化配置。
技术选型方面,SQLAlchemy选择了因为它是Python最流行的ORM框架,提供了强大的数据库操作能力,支持多种数据库包括MySQL、PostgreSQL、SQLite等主流数据库。MySQL选择了因为它是最流行的开源关系型数据库,性能稳定可靠,文档丰富。
四、关键代码思路
4.1 模型定义
每个模型都继承自Base基类,使用SQLAlchemy的ORM方式定义。
classTeacherScore(Base):__tablename__="teacher_scores"id=Column(Integer,primary_key=True,index=True)submission_id=Column(Integer,ForeignKey("submissions.id"),nullable=False)teacher_id=Column(Integer,ForeignKey("users.id"),nullable=False)# 评分项innovation=Column(Integer,nullable=False,default=0)completeness=Column(Integer,nullable=False,default=0)feasibility=Column(Integer,nullable=False,default=0)code_quality=Column(Integer,nullable=False,default=0)documentation=Column(Integer,nullable=False,default=0)# 计算字段total_score=Column(Float,nullable=False,default=0)# 评语feedback=Column(Text,default="")# 时间戳created_at=Column(DateTime,server_default=func.now())updated_at=Column(DateTime,server_default=func.now(),onupdate=func.now())# 关系submission=relationship("Submission",back_populates="scores")teacher=relationship("User",back_populates="scores_given")字段定义使用Column类,第一个参数是数据类型,可选参数包括是否为主键(primary_key)、是否允许为空(nullable)、是否有索引(index)等。关系映射使用relationship类,定义与其他模型的关系。
4.2 总分计算
总分计算放在了模型的方法中,而不是在业务代码中计算。
defcalculate_total(self):weights={'innovation':0.25,'completeness':0.25,'feasibility':0.20,'code_quality':0.15,'documentation':0.15}self.total_score=(self.innovation*weights['innovation']+self.completeness*weights['completeness']+self.feasibility*weights['feasibility']+self.code_quality*weights['code_quality']+self.documentation*weights['documentation'])returnself.total_score这种设计的优势是业务逻辑封装在模型中,复用方便,也便于测试。当需要计算总分时,只需要调用模型的方法即可,不需要在业务代码中重复编写计算逻辑。
五、代码设计优点
外键约束的优势:外键约束可以保证数据的完整性。当插入数据时,如果引用的ID不存在会报错,阻止无效数据的插入。当删除主记录时,可以配置级联删除相关的从记录,自动清理数据。这种约束比业务代码实现更可靠。
自动时间戳的优势:使用数据库的server_default和onupdate实现时间戳,比业务代码更准确。业务代码可能因为时区、网络延迟等原因导致时间不准确,数据库自动管理更可靠。时间戳对于问题排查和数据追溯非常重要。
关系映射的优势:使用SQLAlchemy的关系映射,可以方便地通过对象获取关联数据。例如score.submission可以获取评分对应的项目,score.teacher可以获取评分对应的教师。这种设计让代码更简洁,不需要手动写JOIN查询。
六、遇到的问题与解决
关系复杂问题:问题描述是表之间关系复杂,难以理解。解决方案是绘制ER图辅助设计,明确每个关系的作用。复杂的关系会增加维护成本,需要在设计阶段充分考虑。
字段过多问题:问题描述是某些表字段过多,难以维护解决方案是使用JSON类型存储扩展字段,减少固定字段数量。JSON类型可以存储不固定结构的数据,灵活性高。
七、后续优化方向
后续优化主要考虑以下几个方面:索引优化为常用查询字段添加索引可以大幅提升查询性能。分表策略当数据量大时考虑分表,减少单表数据量。缓存模型使用Redis缓存热点数据减少数据库压力。
八、本周总结
本周完成了数据模型的设计工作。通过这个项目,我深入学习了数据库设计的基本原则,掌握了SQLAlchemy ORM的使用方法,学会了表关系的设计思路。
整个设计过程让我认识到,数据库设计是后端开发的核心技能。关系型数据库仍然是最常用的数据存储方式,良好的表结构设计可以让后续的开发更加高效。这些经验对后续的开发工作很有帮助,也是区分初级工程师和中高级工程师的重要标志。