
求职者端–基本信息编辑#更新求职者个人信息 staticmethod async def update_job_seeker_info( job_seeker_id: str, mobile:str, nickname:str, password:str, email:str, wechat:str, avatar:UploadFile): jobseekerawait JobSeeker.get_or_none(idjob_seeker_id) dict_info{ mobile:mobile, nickname:nickname, password:password, email:email, wechat:wechat, } if avatar is not None: file_content await avatar.read() filename avatar.filename oss AliyunOSSTool() is_success, success_res oss.upload_single_file(file_content, filename, oss_pathjob_seeker_avatar/) if is_success: dict_info[avatar] success_res[access_url] jobseeker.mobiledict_info[mobile] if dict_info[mobile] is not None else jobseeker.mobile jobseeker.nicknamedict_info[nickname] if dict_info[nickname] is not None else jobseeker.nickname jobseeker.passworddict_info[password] if dict_info[password] is not None else jobseeker.password jobseeker.emaildict_info[email] if dict_info[email] is not None else jobseeker.email jobseeker.wechatdict_info[wechat] if dict_info[wechat] is not None else jobseeker.wechat jobseeker.avatardict_info.get(avatar) if dict_info.get(avatar) is not None else jobseeker.avatar await jobseeker.save() return jobseekerAI写代码python运行service层实现求职者个人信息更新逻辑。首先根据求职者 ID 查询用户数据构建基础更新字典针对头像文件做特殊处理如果前端传入UploadFile头像读取文件二进制流调用封装好的阿里云 OSS 工具上传至job_seeker_avatar/目录上传成功则将 OSS 返回的资源访问链接存入更新字典。字段赋值采用非空判断策略入参不为空才覆盖原有数据库值有效避免前端不传参时清空已有数据全部字段赋值完成后执行save()持久化更新并返回更新后的求职者实例。job_seeker_router.post(“/job_seeker_info”, summary“更新用户信息”, description“更新用户信息”)async def update_job_seeker_info(job_seeker_idDepends(get_job_seeker_info),mobile: str Form(None, description“手机号”),nickname: str Form(None, description“昵称”),password: str Form(None, description“密码”),email: str Form(None, description“邮箱”),wechat: str Form(None, description“微信”),avatar: UploadFile File(None, description“头像”)):await JobSeekerService.update_job_seeker_info(job_seeker_id,mobile,nickname,password,email,wechat,avatar)return {“code”: 1,“message”: “更新成功”}AI写代码python运行apsi层用于求职者更新个人信息。接口采用表单提交方式普通文本字段通过Form()接收文件头像使用File()接收所有参数默认值设为None支持选择性局部更新前端无需一次性传递全部字段。利用依赖注入Depends(get_job_seeker_info)自动获取当前登录求职者 ID避免前端手动传递 ID 引发越权风险。路由层只负责接收请求参数、调用 Service 业务方法遵循路由与业务解耦的开发规范不编写任何数据库、文件上传逻辑执行更新完成后统一返回自定义格式成功 JSON 响应。求职者端-添加和编辑简历基本信息async def saveorupdateResumeBasicInfo(job_seeker_id: int, request: ResumeBasicInfoSaveRequest):job_seeker await JobSeeker.get_or_none(idjob_seeker_id)if job_seeker is None:raise Exception(“求职者不存在”)resumeBasicInfoawait ResumeBasicInfo.get_or_none(job_seekerjob_seeker) if resumeBasicInfo is None: resumeBasicInfoawait ResumeBasicInfo.create( namerequest.name, genderrequest.gender, nationrequest.nation, birth_daterequest.birth_date, residencerequest.residence, marital_statusrequest.marital_status, political_statusrequest.political_status, job_seekerjob_seeker, ) else: resume_basic_info_dictrequest.model_dump(exclude_unsetTrue) await resumeBasicInfo.update_from_dict(resume_basic_info_dict) await resumeBasicInfo.save() return resumeBasicInfoAI写代码python运行resume_router.post(“/basic/save”, summary“保存/更新基本信息”)async def saveorupdateResumeBasicInfo(resume_basic_request: ResumeBasicInfoSaveRequest,job_seeker_idDepends(get_job_seeker_info)):await ResumeService.saveorupdateResumeBasicInfo(job_seeker_id, resume_basic_request)return {“code”: 1, “message”: “成功”}AI写代码python运行这里是实现简历基础信息新增 / 更新合一upsert 接口。路由层接收前端传入的简历基础信息请求体ResumeBasicInfoSaveRequest通过依赖注入自动获取当前登录求职者 ID将参数交给 Service 层处理严格做到路由只负责接收参数、响应结果业务逻辑下沉至 Service分层清晰。Service 层先校验求职者是否存在不存在直接抛出异常。随后根据求职者关联关系查询简历基础信息记录若无记录则执行create()新建简历信息如果已有记录则利用model_dump(exclude_unsetTrue)只提取前端实际传递的字段配合 Tortoise ORM 的update_from_dict进行局部更新避免未传参数覆盖数据库原有数据最后执行 save 持久化。这种设计支持前端按需提交字段实现简历信息保存与更新复用同一个接口减少接口数量。求职者端-求职意向编辑resume_router.post(“/job/intention”, summary“保存/更新职位意向”)async def saveorUpdateJobIntention(jobIntentionSaveRequest: JobIntentionSaveRequest,job_seeker_idDepends(get_job_seeker_info)):resawait ResumeService.saveorUpdateJobIntention(jobIntentionSaveRequest,job_seeker_id)return {“code”: 1, “message”: “成功”}AI写代码python运行staticmethodasync def saveorUpdateJobIntention(jobIntentionSaveRequest: JobIntentionSaveRequest,job_seeker_id:int):jobSeekerawait JobSeeker.get_or_none(idjob_seeker_id)if jobSeeker is None:raise Exception(“求职者不存在”)resumeBasicInfoawait ResumeBasicInfo.get_or_none(job_seekerjobSeeker)if resumeBasicInfo is None:raise Exception(“请先保存基本信息”)jobIntentionawait JobIntention.get_or_none(job_seekerjobSeeker)if jobIntention is None:jobIntentionawait JobIntention.create(job_seekerjobSeeker,expect_positionjobIntentionSaveRequest.expect_position,expect_salaryjobIntentionSaveRequest.expect_salary,work_typejobIntentionSaveRequest.work_type,expect_cityjobIntentionSaveRequest.expect_city,job_statusjobIntentionSaveRequest.job_status,expect_industryjobIntentionSaveRequest.expect_industry,resumeresumeBasicInfo)else:jobIntention_dictjobIntentionSaveRequest.model_dump(exclude_unsetTrue)await jobIntention.update_from_dict(jobIntention_dict)await jobIntention.save()return jobIntentionAI写代码python运行这里是实现简历职位意向信息新增与更新复用接口。路由层接收前端封装好的JobIntentionSaveRequest请求实体通过依赖注入Depends(get_job_seeker_info)获取当前登录求职者 ID仅负责转发参数与返回统一格式 JSON所有业务逻辑交由 Service 层处理严格遵守路由与业务分层规范。Service 层增加前置业务校验首先判断求职者是否存在接着校验求职者是否已经填写简历基础信息若未填写直接抛出提示强制业务填写顺序。随后查询当前求职者的职位意向记录无记录则执行新增操作已有记录时通过model_dump(exclude_unsetTrue)过滤前端实际传递的字段结合 Tortoise ORM 的update_from_dict完成局部更新不会使用未传递参数覆盖数据库原有数据实现按需更新。整体约束了简历填写流程保证数据业务完整性同一个接口同时支持首次新增意向和后续修改意向。求职者端-保存工作经历staticmethodasync def saveWorkExperience(workExperienceSaveRequest: WorkExperienceSaveRequest,job_seeker_id:int):jobSeeker await JobSeeker.get_or_none(idjob_seeker_id)if jobSeeker is None:raise Exception(“求职者不存在”)resumeBasicInfo await ResumeBasicInfo.get_or_none(job_seekerjobSeeker)if resumeBasicInfo is None:raise Exception(“请先保存基本信息”)await WorkExperience.create(company_nameworkExperienceSaveRequest.company_name,industryworkExperienceSaveRequest.industry,departmentworkExperienceSaveRequest.department,positionworkExperienceSaveRequest.position,entry_timeworkExperienceSaveRequest.entry_time,leave_timeworkExperienceSaveRequest.leave_time,work_contentworkExperienceSaveRequest.work_content,performanceworkExperienceSaveRequest.performance,skillsworkExperienceSaveRequest.skills,resumeresumeBasicInfo,job_seekerjobSeeker)return 1AI写代码python运行resume_router.post(“/work/experience”, summary“保存工作经历”)async def saveWorkExperience(workExperienceSaveRequest: WorkExperienceSaveRequest,job_seeker_idDepends(get_job_seeker_info)):await ResumeService.saveWorkExperience(workExperienceSaveRequest,job_seeker_id)return {“code”: 1, “message”: “成功”}AI写代码python运行该接口用于新增简历工作经历信息路由层接收前端提交的工作经历请求实体依靠依赖注入获取登录求职者 ID仅做参数转发和结果响应业务逻辑全部交由 Service 层处理遵循前后端分离分层开发思想。Service 层首先进行两层前置校验校验求职者账号是否存在同时校验求职者是否已完善简历基础信息强制规范简历填写流程。工作经历属于多条记录不存在新增 / 更新复用逻辑每次调用直接执行create()新增一条工作经历数据关联绑定求职者与简历基础信息外键。与求职意向一对一不同工作经历是一对多关系求职者可以新增多条工作经历记录因此没有查询判断是否存在的 upsert 逻辑。求职者端-编辑工作经历staticmethodasync def updateWorkExperience (workExperienceUpdateRequest: WorkExperienceUpdateRequest,job_seeker_id: int,id: int ):jobSeeker await JobSeeker.get_or_none (idjob_seeker_id)if jobSeeker is None:raise Exception (“求职者不存在”)workExperience await WorkExperience.get_or_none (idid)if workExperience is None:raise Exception (“工作经历不存在”)workExperience_dictworkExperienceUpdateRequest.model_dump (exclude_unsetTrue)await workExperience.update_from_dict (workExperience_dict)await workExperience.save ()return 1AI写代码python运行resume_router.post (“/work/experience/{id}”, summary“更新工作经历”)# 需要获取到具体某一条的工作经历因此需要传 idasync def updateWorkExperience (workExperienceUpdateRequest: WorkExperienceUpdateRequest,job_seeker_idDepends (get_job_seeker_info),id:intPath (…,title“工作经历 id”)):await ResumeService.updateWorkExperience (workExperienceUpdateRequest,job_seeker_id,id)return {“code”: 1, “message”: “成功”}AI写代码python运行该接口实现单条工作经历信息更新功能。路由通过路径参数Path接收目标工作经历主键 id搭配依赖注入获取当前登录求职者 ID路由层仅负责接收请求参数并调用 Service保持分层架构职责清晰。Service 层先后完成多层校验首先校验求职者账号有效性再根据传入 id 查询对应的工作经历记录校验记录是否存在。拿到记录实例后通过model_dump(exclude_unsetTrue)只提取前端实际传递的字段借助 Tortoise ORM 提供的update_from_dict实现局部更新不会用前端未传入参数覆盖数据库原有内容。求职者端-获取求职者的简历信息staticmethodasync def get_job_seeker_resume_info(job_seeker_id:int):job_seeker_resume_info{}#求职者信息jobSeekerawait JobSeeker.get_or_none(idjob_seeker_id)job_seeker_resume_info[‘jobSeeker’]{“id”: jobSeeker.id,“username”: jobSeeker.nickname,“phone”: jobSeeker.mobile,“email”: jobSeeker.email,“avatar”: jobSeeker.avatar if jobSeeker.avatar else “https://gips1.baidu.com/it/u436886321,1020119268fm3028app3028fJPEGfmtauto?w1280h960”,“gender”: jobSeeker.wechat,}#基本信息 resumeBasicInfo await ResumeBasicInfo.get_or_none(job_seekerjobSeeker) if resumeBasicInfo: job_seeker_resume_info[resumeBasicInfo]{ id: resumeBasicInfo.id, name: resumeBasicInfo.name, gender: resumeBasicInfo.gender, nation: resumeBasicInfo.nation, birth_date: resumeBasicInfo.birth_date, residence: resumeBasicInfo.residence, marital_status: resumeBasicInfo.marital_status, political_status: resumeBasicInfo.political_status, } else: job_seeker_resume_info[resumeBasicInfo]{ id: , name: , gender: , nation: , birth_date: , residence: , marital_status: , political_status: , } #职位意向 jobIntention await JobIntention.get_or_none(job_seekerjobSeeker) if jobIntention: job_seeker_resume_info[jobIntention]{ id: jobIntention.id, expect_position: jobIntention.expect_position, expect_salary: jobIntention.expect_salary, work_type: jobIntention.work_type, expect_city: jobIntention.expect_city, job_status: jobIntention.job_status, expect_industry: jobIntention.expect_industry, } else: job_seeker_resume_info[jobIntention]{ id: , expect_position: , expect_salary: , work_type: , expect_city: , job_status: , expect_industry: , } #工作经历(工作经历与简历是一对多的关系所以要存反正在列表里面因为工作经历也有增删改方法每条经历都是单独的一条字典数据也有id在这里用列表更方便) workExperiences await WorkExperience.filter(job_seekerjobSeeker) workExperience_list [] for workExperience in workExperiences: workExperience_dict { id: workExperience.id, company_name: workExperience.company_name, industry: workExperience.industry, department: workExperience.department, position: workExperience.position, entry_time: workExperience.entry_time, leave_time: workExperience.leave_time, work_content: workExperience.work_content, performance: workExperience.performance, skills: workExperience.skills } workExperience_list.append(workExperience_dict) job_seeker_resume_info[workExperiences]workExperience_list #教育经历 educationExperiences await EducationExperience.filter(job_seekerjobSeeker) education_list [] for education in educationExperiences: education_dict { id: education.id, school: education.school_name, major: education.major_name, degree: education.education_name, start_time: education.entry_date, end_time: education.graduate_date } education_list.append(education_dict) job_seeker_resume_info[educations]education_list return job_seeker_resume_infoAI写代码python运行resume_router.get(“/info”, summary“获取求职者简历信息”)async def get_job_seeker_resume_info(job_seeker_idDepends(get_job_seeker_info)):resawait ResumeService.get_job_seeker_resume_info(job_seeker_id)return {“code”: 1, “message”: “成功”, “data”:res}AI写代码python运行该接口用于一次性聚合返回求职者完整简历全套信息前端只需要调用一个接口就能拿到简历所有板块数据减少前端多次请求接口的开销。 路由层通过依赖注入Depends(get_job_seeker_info)获取当前登录求职者 ID仅负责接收请求、调用 Service、组装统一格式返回体严格遵循前后端分离分层架构。Service 层分步查询求职者主体信息、简历基础信息、求职意向、多条工作经历、多条教育经历。一对一数据简历基础信息、求职意向做判空处理若无数据库记录则返回空字段字典保证前端解构数据时不会出现key不存在报错一对多的工作经历、教育经历使用 filter 查询多条记录循环封装为字典存入列表返回契合多条履历可独立增删改的业务设计。