如何将CSV时间戳字符串转为Pydantic模型的TimeStamp列表?
解决CSV转Pydantic对象时时间戳字符串转模型列表的问题
问题场景
现有包含YouTube链接和时间戳的CSV文件,格式如下:
https://www.youtube.com/watch?v=dsnLcaNhXd6o,0:13-0:20;0:25-0:31;0:36-0:40 https://www.youtube.com/watch?v=d8InLcaNhXd6o,0:43-0:52;0:56-1:07 https://www.youtube.com/watch?v=Inji8LcaNhXd6o,0:13-0:20;0:25-0:31;0:36-0:40;0:43-0:52;0:56-1:07;1:15-1:25;1:28-1:40
通过csv.reader读取并结合enumerate得到带行索引的元组列表后,无法直接将时间戳字符串映射到定义好的TimeStamp模型列表字段,添加验证器时因类型不匹配报错。
已定义的Pydantic模型:
class TimeStamp(BaseModel): start_min: int start_sec: int end_min: int end_sec: int class VideoDetail(BaseModel): row_index: int url: str timestamps: List[TimeStamp] class VideoList(BaseModel): entry: List[VideoDetail]
解决方案
核心思路是在Pydantic字段验证流程中,提前将时间戳字符串转换为符合TimeStamp模型结构的字典列表,再由Pydantic自动解析为模型对象。以下分Pydantic v2和v1两种版本给出实现:
版本1:Pydantic v2(推荐)
使用Annotated结合BeforeValidator,在字段验证前完成字符串解析:
from pydantic import BaseModel, BeforeValidator, ValidationError from typing import List, Annotated class TimeStamp(BaseModel): start_min: int start_sec: int end_min: int end_sec: int # 自定义时间戳字符串解析函数 def parse_timestamp_str(timestamp_str: str) -> List[dict]: timestamps = [] # 拆分多个时间戳片段 for ts_part in timestamp_str.split(';'): # 拆分开始/结束时间 start_str, end_str = ts_part.split('-') # 拆分分/秒并转为整数 start_min, start_sec = map(int, start_str.split(':')) end_min, end_sec = map(int, end_str.split(':')) timestamps.append({ 'start_min': start_min, 'start_sec': start_sec, 'end_min': end_min, 'end_sec': end_sec }) return timestamps class VideoDetail(BaseModel): row_index: int url: str # 用Annotated标记字段,指定前置验证器 timestamps: Annotated[List[TimeStamp], BeforeValidator(parse_timestamp_str)] class VideoList(BaseModel): entry: List[VideoDetail]
版本2:Pydantic v1
使用@validator装饰器并设置pre=True,开启前置验证:
from pydantic import BaseModel, validator, ValidationError from typing import List class TimeStamp(BaseModel): start_min: int start_sec: int end_min: int end_sec: int class VideoDetail(BaseModel): row_index: int url: str timestamps: List[TimeStamp] @validator('timestamps', pre=True) def parse_timestamps(cls, value): # 仅当输入为字符串时进行解析 if isinstance(value, str): timestamps = [] for ts_part in value.split(';'): start_str, end_str = ts_part.split('-') start_min, start_sec = map(int, start_str.split(':')) end_min, end_sec = map(int, end_str.split(':')) timestamps.append({ 'start_min': start_min, 'start_sec': start_sec, 'end_min': end_min, 'end_sec': end_sec }) return timestamps # 非字符串输入直接返回,交给后续验证 return value class VideoList(BaseModel): entry: List[VideoDetail]
CSV数据转换与验证
将读取的CSV元组列表转换为符合VideoDetail结构的字典列表,再传入VideoList完成验证:
import csv csv_file = 'your_youtube_data.csv' with open(csv_file, mode='r') as file: csv_reader = csv.reader(file) video_data = [] for row_idx, row in enumerate(csv_reader): # 跳过无效行(确保每行有2个元素:链接+时间戳) if len(row) != 2: print(f"警告:第{row_idx}行格式无效,已跳过") continue url, timestamp_str = row video_data.append({ 'row_index': row_idx, 'url': url, 'timestamps': timestamp_str }) # 验证并生成模型对象 try: video_list = VideoList(entry=video_data) # 输出验证后的JSON格式数据 print(video_list.model_dump_json(indent=2)) except ValidationError as e: print(f"验证错误:{e}")
关键说明
- 前置验证器(
BeforeValidator或pre=True的@validator)会在Pydantic进行类型检查前执行,将字符串转换为List[dict],此时Pydantic可以自动将字典解析为TimeStamp模型对象。 - 解析函数中加入了基础的格式拆分逻辑,若需要更严格的时间格式验证(比如秒数不超过59),可以在
TimeStamp模型中添加额外的字段验证器。
内容的提问来源于stack exchange,提问作者rangarajan
相关产品推荐
相关产品推荐

