Excelの状態欄を選択リストにしても、Pythonから書き込む不正な値までは自動で止まりません。openpyxlは入力規則をファイルへ設定できますが、その規則を使ってセル値を検証する処理は行わないためです。
状態をopenとdoneだけにするなら、Excelの入力補助とPython側の許可値検査をそろえる形にします。別の入力経路から値が入る場合も、同じ条件で確認できるようにします。
選択リストと検査関数を分ける
次は架空のブックです。B2:B20に選択リストを設定し、Pythonの関数では許可した文字だけを返します。B3には検査を通さずunknownを入れ、規則があるだけでは保存を止めないことも比べます。
from io import BytesIO
from openpyxl import Workbook, load_workbook
from openpyxl.worksheet.datavalidation import DataValidation
allowed = ("open", "done")
def checked_status(value):
if value not in allowed:
raise ValueError("許可していない状態です")
return value
book = Workbook()
sheet = book.active
rule = DataValidation(
type="list", formula1='"open,done"', allow_blank=False
)
rule.showErrorMessage = True
rule.errorStyle = "stop"
rule.errorTitle = "状態を確認"
rule.error = "openかdoneを選択してください"
sheet.add_data_validation(rule)
rule.add("B2:B20")
sheet["B2"] = checked_status("open")
try:
checked_status("unknown")
except ValueError:
print("Python側で不正な状態を拒否")
sheet["B3"] = "unknown" # 規則が値を自動検査しないことの確認用
buffer = BytesIO()
book.save(buffer)
book.close()
check = load_workbook(BytesIO(buffer.getvalue()))
print("保存された規則数:", len(check.active.data_validations.dataValidation))
print("検査を通さず書いた値:", check.active["B3"].value)
assert check.active["B3"].value == "unknown"
check.close()
規則は一件保存され、検査を通さず書いたunknownも残ります。Windows・Python 3.12.10・openpyxl 3.1.5で、保存後の構造と値を確認しました。Excel画面の選択操作を確認した例ではありません。
実際の出力コードでは確認用のB3への直接書き込みを入れず、必要な経路を検査関数へ通します。不正な値を既定値へ置き換えて続けるより、入力元へ理由を返す形にできます。
適用範囲を置き忘れない
DataValidationを作るだけでは、どのセルへ使う規則かが決まりません。シートへ追加した後に、rule.addで適用範囲を指定します。明細が増える場合は、出力する範囲と規則の範囲が合うかも確認してください。
選択肢を別シートなどで管理する設計へ変えるなら、名前や参照範囲も保存後に確かめます。この例はopenとdoneという短い固定の選択肢だけを扱っています。
空欄や状態変更の条件も決める
許可値に含まれることと、状態を変更してよいことは別です。doneをopenへ戻せるか、誰が変更できるかといった業務の条件は、入力規則のリストだけでは表せません。
空欄を許すか、大文字や前後の空白をそろえるかも、入力元ごとに揺らさず決めます。選択肢を変更した場合は、Pythonの許可値、Excelの表示、既存データの扱いを一緒に見直してください。
セルを操作する基本はopenpyxl入門、状態や入力を整理する考え方は在庫・台帳の自動化設計で確認できます。
参考資料
openpyxlの入力規則公式資料を2026年11月1日に確認しました。
