本文目录导读:

我来为你提供几个Python表单校验的完整案例,涵盖不同场景和校验方法。
基础表单校验(不使用框架)
import re
from typing import Dict, List, Optional
class FormValidator:
"""基础表单校验器"""
@staticmethod
def validate_required(value: str, field_name: str) -> Optional[str]:
"""校验必填字段"""
if not value or not value.strip():
return f"{field_name} 是必填项"
return None
@staticmethod
def validate_email(email: str) -> Optional[str]:
"""校验邮箱格式"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(pattern, email):
return "邮箱格式不正确"
return None
@staticmethod
def validate_phone(phone: str) -> Optional[str]:
"""校验手机号(中国)"""
pattern = r'^1[3-9]\d{9}$'
if not re.match(pattern, phone):
return "手机号格式不正确"
return None
@staticmethod
def validate_length(value: str, min_length: int = None, max_length: int = None, field_name: str = "") -> Optional[str]:
"""校验长度"""
if min_length and len(value) < min_length:
return f"{field_name} 长度不能少于{min_length}个字符"
if max_length and len(value) > max_length:
return f"{field_name} 长度不能超过{max_length}个字符"
return None
@staticmethod
def validate_password(password: str) -> List[str]:
"""校验密码强度"""
errors = []
if len(password) < 8:
errors.append("密码长度不能少于8位")
if not re.search(r'[A-Z]', password):
errors.append("密码需要包含大写字母")
if not re.search(r'[a-z]', password):
errors.append("密码需要包含小写字母")
if not re.search(r'\d', password):
errors.append("密码需要包含数字")
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
errors.append("密码需要包含特殊字符")
return errors
# 使用示例
def validate_registration_form(data: Dict) -> Dict:
"""校验注册表单"""
errors = {}
validator = FormValidator()
# 校验用户名
username_error = validator.validate_required(data.get('username', ''), '用户名')
if not username_error:
username_error = validator.validate_length(data.get('username', ''), 3, 20, '用户名')
if username_error:
errors['username'] = username_error
# 校验邮箱
email_error = validator.validate_required(data.get('email', ''), '邮箱')
if not email_error:
email_error = validator.validate_email(data.get('email', ''))
if email_error:
errors['email'] = email_error
# 校验手机号
phone_error = validator.validate_phone(data.get('phone', ''))
if phone_error:
errors['phone'] = phone_error
# 校验密码
password_errors = validator.validate_password(data.get('password', ''))
if password_errors:
errors['password'] = password_errors
return errors
# 测试
test_data = {
'username': 'ab',
'email': 'invalid-email',
'phone': '12345678901',
'password': 'weak'
}
errors = validate_registration_form(test_data)
print("表单校验结果:")
for field, error in errors.items():
if isinstance(error, list):
print(f"{field}: {', '.join(error)}")
else:
print(f"{field}: {error}")
使用Pydantic进行表单校验(推荐)
from pydantic import BaseModel, EmailStr, Field, validator, field_validator
from typing import Optional
from datetime import date, datetime
class UserRegistrationForm(BaseModel):
"""用户注册表单 - Pydantic版本"""
username: str = Field(..., min_length=3, max_length=20, description="用户名")
email: EmailStr = Field(..., description="邮箱")
password: str = Field(..., min_length=8, description="密码")
confirm_password: str = Field(..., description="确认密码")
age: int = Field(ge=0, le=150, default=18, description="年龄")
phone: Optional[str] = Field(None, description="手机号")
birthday: Optional[date] = Field(None, description="生日")
@field_validator('password')
@classmethod
def validate_password_strength(cls, v):
"""自定义密码强度校验"""
import re
if not re.search(r'[A-Z]', v):
raise ValueError('密码必须包含大写字母')
if not re.search(r'[a-z]', v):
raise ValueError('密码必须包含小写字母')
if not re.search(r'\d', v):
raise ValueError('密码必须包含数字')
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', v):
raise ValueError('密码必须包含特殊字符')
return v
@field_validator('confirm_password')
@classmethod
def passwords_match(cls, v, info):
"""校验两次密码一致"""
if 'password' in info.data and v != info.data['password']:
raise ValueError('两次密码不一致')
return v
@field_validator('phone')
@classmethod
def validate_phone(cls, v):
"""校验手机号"""
if v is not None:
import re
if not re.match(r'^1[3-9]\d{9}$', v):
raise ValueError('手机号格式不正确')
return v
@field_validator('username')
@classmethod
def validate_username(cls, v):
"""校验用户名格式"""
import re
if not re.match(r'^[a-zA-Z0-9_]+$', v):
raise ValueError('用户名只能包含字母、数字和下划线')
return v
# 使用示例
try:
# 正确的数据
valid_data = UserRegistrationForm(
username="john_doe",
email="john@example.com",
password="StrongP@ss1",
confirm_password="StrongP@ss1",
age=25,
phone="13812345678",
birthday=date(1998, 1, 1)
)
print("校验通过!")
print(f"用户名: {valid_data.username}")
except Exception as e:
print(f"校验失败: {e}")
# 错误的数据
try:
invalid_data = UserRegistrationForm(
username="ab", # 太短
email="invalid-email", # 邮箱格式错误
password="weak", # 密码太弱
confirm_password="different", # 密码不一致
age=200 # 年龄太大
)
except Exception as e:
print(f"\n校验失败: {e}")
使用WTForms(Flask常用)
from wtforms import Form, StringField, IntegerField, PasswordField, validators
from wtforms.validators import DataRequired, Email, Length, NumberRange, EqualTo, Regexp
class RegistrationForm(Form):
"""注册表单 - WTForms版本"""
username = StringField('用户名', [
DataRequired(message='用户名不能为空'),
Length(min=3, max=20, message='用户名长度需要在3-20个字符之间'),
Regexp(r'^[a-zA-Z0-9_]+$', message='用户名只能包含字母、数字和下划线')
])
email = StringField('邮箱', [
DataRequired(message='邮箱不能为空'),
Email(message='邮箱格式不正确')
])
password = PasswordField('密码', [
DataRequired(message='密码不能为空'),
Length(min=8, message='密码长度不能少于8个字符')
])
confirm_password = PasswordField('确认密码', [
DataRequired(message='请确认密码'),
EqualTo('password', message='两次密码不一致')
])
age = IntegerField('年龄', [
NumberRange(min=0, max=150, message='年龄必须在0-150之间')
])
def validate_password(self, field):
"""自定义密码校验规则"""
import re
if not re.search(r'[A-Z]', field.data):
raise validators.ValidationError('密码必须包含大写字母')
if not re.search(r'[a-z]', field.data):
raise validators.ValidationError('密码必须包含小写字母')
if not re.search(r'\d', field.data):
raise validators.ValidationError('密码必须包含数字')
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', field.data):
raise validators.ValidationError('密码必须包含特殊字符')
# 使用示例
def validate_wtforms_form(form_data: dict) -> dict:
"""校验WTForms表单"""
form = RegistrationForm(data=form_data)
if form.validate():
return {'valid': True, 'errors': {}}
else:
errors = {}
for field, field_errors in form.errors.items():
errors[field] = field_errors
return {'valid': False, 'errors': errors}
# 测试
test_data = {
'username': 'test_user',
'email': 'test@example.com',
'password': 'StrongP@ss1',
'confirm_password': 'StrongP@ss1',
'age': 25
}
result = validate_wtforms_form(test_data)
print(f"校验结果: {'通过' if result['valid'] else '失败'}")
if not result['valid']:
print(f"错误信息: {result['errors']}")
综合校验案例
from dataclasses import dataclass
from typing import Dict, Optional, List
import re
from datetime import datetime
@dataclass
class ValidationRule:
"""校验规则定义"""
required: bool = False
min_length: Optional[int] = None
max_length: Optional[int] = None
regex: Optional[str] = None
email: bool = False
phone: bool = False
custom_validator: Optional[callable] = None
class AdvancedFormValidator:
"""高级表单校验器"""
def __init__(self, rules: Dict[str, ValidationRule]):
self.rules = rules
def validate(self, data: Dict) -> Dict:
"""执行校验"""
errors = {}
for field_name, rule in self.rules.items():
value = data.get(field_name, '')
# 检查必填
if rule.required and (value is None or str(value).strip() == ''):
errors[field_name] = f'{field_name} 是必填项'
continue
# 如果值为空且非必填,跳过其他校验
if value is None or str(value).strip() == '':
continue
# 转换为字符串
str_value = str(value)
# 校验长度
if rule.min_length and len(str_value) < rule.min_length:
errors[field_name] = f'{field_name} 长度不能少于{rule.min_length}个字符'
continue
if rule.max_length and len(str_value) > rule.max_length:
errors[field_name] = f'{field_name} 长度不能超过{rule.max_length}个字符'
continue
# 校验正则
if rule.regex and not re.match(rule.regex, str_value):
errors[field_name] = f'{field_name} 格式不正确'
continue
# 校验邮箱
if rule.email:
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, str_value):
errors[field_name] = '邮箱格式不正确'
continue
# 校验手机号
if rule.phone:
phone_pattern = r'^1[3-9]\d{9}$'
if not re.match(phone_pattern, str_value):
errors[field_name] = '手机号格式不正确'
continue
# 自定义校验器
if rule.custom_validator:
try:
error_msg = rule.custom_validator(str_value)
if error_msg:
errors[field_name] = error_msg
except Exception as e:
errors[field_name] = str(e)
return errors
# 使用示例
def custom_password_validator(password: str) -> Optional[str]:
"""自定义密码校验"""
if not re.search(r'[A-Z]', password):
return '密码必须包含大写字母'
if not re.search(r'[a-z]', password):
return '密码必须包含小写字母'
if not re.search(r'\d', password):
return '密码必须包含数字'
return None
# 定义校验规则
registration_rules = {
'username': ValidationRule(
required=True,
min_length=3,
max_length=20,
regex=r'^[a-zA-Z0-9_]+$'
),
'email': ValidationRule(
required=True,
email=True
),
'phone': ValidationRule(
phone=True
),
'password': ValidationRule(
required=True,
min_length=8,
custom_validator=custom_password_validator
),
'bio': ValidationRule(
max_length=500
)
}
# 创建校验器
validator = AdvancedFormValidator(registration_rules)
# 测试数据
test_data = {
'username': 'test_user',
'email': 'test@example.com',
'phone': '13812345678',
'password': 'WeakPass1',
'bio': 'Hello, this is my bio!'
}
# 执行校验
errors = validator.validate(test_data)
if not errors:
print("所有字段校验通过!")
else:
print("校验失败:")
for field, error in errors.items():
print(f" {field}: {error}")
Web框架集成示例(FastAPI)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI()
class UserCreate(BaseModel):
"""创建用户请求模型"""
username: str = Field(..., min_length=3, max_length=50)
email: str = Field(...)
password: str = Field(..., min_length=8)
full_name: Optional[str] = None
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
"""自定义校验"""
if isinstance(v, dict):
# 校验邮箱格式
import re
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if 'email' in v and not re.match(email_pattern, v['email']):
raise ValueError('邮箱格式不正确')
# 校验密码强度
if 'password' in v:
if not re.search(r'[A-Z]', v['password']):
raise ValueError('密码必须包含大写字母')
if not re.search(r'[a-z]', v['password']):
raise ValueError('密码必须包含小写字母')
if not re.search(r'\d', v['password']):
raise ValueError('密码必须包含数字')
return v
@app.post("/users/")
async def create_user(user: UserCreate):
"""创建用户接口"""
# 如果校验失败,FastAPI会自动返回422状态码和错误信息
return {
"message": "用户创建成功",
"username": user.username,
"email": user.email
}
# 模拟请求
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
建议
- 生产环境推荐使用Pydantic或WTForms,它们提供了完善的校验机制和错误处理
- 自定义校验逻辑应该分离到独立的校验函数中
- 注意安全性:不要在前端完全信赖前端的校验,后端必须重新校验
- 提供友好的错误信息:错误提示应该清晰、具体
- 考虑国际化:如果需要支持多语言,错误信息应该支持翻译
选择哪种方式取决于你的项目需求:
- 简单项目:可以使用基础校验
- Flask项目:推荐WTForms
- FastAPI项目:推荐Pydantic
- 复杂的校验逻辑:可以综合使用多种方法
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播