Python Excel数据验证做下拉选择框方法详解
用openpyxl的DataValidation给Excel单元格做下拉选择框,支持固定选项、引用其他sheet的选项列表、限制输入范围、中文错误提示,避免手输错。
场景痛点
做登记表、信息采集表时,"性别""部门""是否在职"这种字段,如果让人随便敲,就会出现"男/男 /M/male"一大堆写法,后面透视统计全乱。正确做法是把它做成下拉框,只能选不能填。手动一个个点数据验证、复制区域,表一多就累。用Python批量生成,下拉框规则一次写完,谁填都只能选规定选项。
用到的库
pip install openpyxl
完整代码
# -*- coding: utf-8 -*-
"""
openpyxl 给 Excel 加数据验证(下拉框 / 数值范围 / 日期范围)
"""
from openpyxl import Workbook
from openpyxl.worksheet.datavalidation import DataValidation
def build_form(path: str):
wb = Workbook()
# ===== Sheet1:登记表 =====
ws = wb.active
ws.title = "登记表"
headers = ["姓名", "性别", "部门", "年龄", "入职日期"]
ws.append(headers)
ws.append(["张三", None, None, None, None])
ws.append(["李四", None, None, None, None])
ws.append(["王五", None, None, None, None])
# 1) 性别下拉:固定列表,选项之间用英文逗号
dv_gender = DataValidation(
type="list",
formula1='"男,女,保密"',
allow_blank=True, # 允许空着不选
showDropDown=False, # 注意:False 才显示下拉箭头
showErrorMessage=True, # 输入非法值时弹错误框
errorTitle="输入有误",
error="性别只能选:男、女、保密",
)
dv_gender.add("B2:B100")
ws.add_data_validation(dv_gender)
# 2) 部门下拉:选项放在"选项表"sheet里,引用区域
ws_opt = wb.create_sheet("选项表")
departments = ["技术部", "产品部", "市场部", "人事部", "财务部"]
for i, dep in enumerate(departments, start=1):
ws_opt.cell(row=i, column=1, value=dep)
dv_dept = DataValidation(
type="list",
formula1="=选项表!$A$1:$A$5", # 引用其他 sheet 的区域
allow_blank=True,
showDropDown=False,
)
dv_dept.add("C2:C100")
ws.add_data_validation(dv_dept)
# 3) 年龄:限制 18~60 的整数
dv_age = DataValidation(
type="whole",
operator="between",
formula1="18",
formula2="60",
allow_blank=True,
showErrorMessage=True,
errorTitle="年龄不合法",
error="年龄必须是 18 到 60 之间的整数",
)
dv_age.add("D2:D100")
ws.add_data_validation(dv_age)
# 4) 入职日期:限制在 2000-01-01 之后
dv_date = DataValidation(
type="date",
operator="greaterThan",
formula1="DATE(2000,1,1)",
allow_blank=True,
showErrorMessage=True,
errorTitle="日期不合法",
error="入职日期不能早于 2000-01-01",
)
dv_date.add("E2:E100")
ws.add_data_validation(dv_date)
# 表头加个温馨提示
ws["G1"] = "提示:性别/部门点单元格右侧箭头选择,年龄 18-60,日期不早于2000年"
wb.save(path)
print("下拉框已生成:", path)
def main():
build_form("form_with_dropdown.xlsx")
if __name__ == "__main__":
main()
代码讲解
DataValidation(type=..., ...)是数据验证的核心。type决定验证类型:list是下拉列表,whole是整数,decimal小数,date日期,textLength文本长度等。- 下拉列表
formula1='"男,女,保密"':选项必须用英文双引号包起来,选项之间英文逗号分隔。这里三层引号别搞混:Python 外层双引号,里面再套 Excel 公式的双引号。 - 引用其他 sheet 的选项区域时,
formula1="=选项表!$A$1:$A$5",加=号,区域绝对引用。这种方式适合选项很多、或者选项本身要经常改的场景。 showDropDown=False是个反直觉的坑:openpyxl 文档里这个字段名和 Excel 界面相反,False 才显示下拉箭头,True 反而隐藏。照着写就行。showErrorMessage=True+errorTitle+error:用户手输非法内容时弹错误框,阻止录入。dv.add("B2:B100")把规则套到一片区域,ws.add_data_validation(dv)注册到 sheet 上,两步都不能少。- 年龄、日期这种非下拉类验证,用
operator(between/greaterThan/lessThan)+formula1、formula2限定上下界。
运行结果
生成 form_with_dropdown.xlsx。打开后点 B2~B100 任意单元格,右边出现下拉箭头,可选"男/女/保密";C 列部门下拉来自"选项表"sheet;D 列手填 17 或 61 会弹"年龄不合法";E 列填 1999 年的日期会被拦下。
注意事项
showDropDown的语义反直觉,照抄False即可;这是 openpyxl 沿用 OOXML 旧字段命名导致的。- 下拉选项直接写在
formula1里时,总长度(含逗号和引号)不能超过 255 字符,选项多了就改用"引用其他 sheet 区域"的方式。 - 跨 sheet 引用中文 sheet 名时,要写成
='选项表'!$A$1:$A$5加单引号;本例 sheet 名"选项表"是中文,建议加引号更稳。 - 数据验证是"Excel 端的约束",openpyxl 自己写数据时不会校验;也就是说你用脚本往 D 列写个 999,文件里照样存得进去,只是打开 Excel 时会看到绿色错误提示。
allow_blank=True表示允许该单元格留空;要强制必填就设 False。

更新时间:2026-09-15 09:11:07