在使用Peewee作为ORM框架开发应用时,用户提交的数据往往会在字符串字段中携带首尾空白字符,比如用户输入的用户名、地址等信息,手动逐个处理这些空白字符效率很低,还容易出现遗漏。我们可以通过Peewee的扩展能力,让Model自动完成字段空白字符的去除,保证入库数据的整洁性。

方案一:自定义字段类实现自动去空白
Peewee的所有字段都继承自Field基类,我们可以自定义一个字符串字段类,在字段处理数据的时候自动去除首尾空白字符。这种方式可以针对特定字段类型生效,灵活性比较高。
自定义去空白字符串字段
我们继承CharField类,重写coerce方法,这个方法会在字段接收数据的时候被调用,我们可以在这里处理空白字符。
from peewee import *
# 自定义自动去除空白的CharField
class TrimCharField(CharField):
def coerce(self, value):
# 如果值是字符串,去除首尾空白,否则返回原值
if isinstance(value, str):
return value.strip()
return value
# 定义测试Model
class User(Model):
username = TrimCharField(max_length=50, null=False)
email = TrimCharField(max_length=100, null=True)
class Meta:
database = SqliteDatabase('test.db')
# 初始化数据库和表
db = SqliteDatabase('test.db')
db.connect()
db.create_tables([User])
# 测试插入带空白的数据
user = User(username=' test_user ', email=' test@ippipp.com ')
user.save()
# 查询验证数据
saved_user = User.get(User.username == 'test_user')
print(saved_user.username) # 输出 test_user
print(saved_user.email) # 输出 test@ippipp.com
方案优缺点
- 优点:只需要在定义字段的时候使用自定义字段,不需要额外写处理逻辑,对现有代码侵入性小,还可以根据需要扩展其他数据清洗逻辑。
- 缺点:如果需要处理非字符串类型的字段,或者需要更复杂的清洗规则,可能需要定义多个不同的自定义字段类。
方案二:重写Model的save方法
另一种方式是在Model层面统一处理,重写save方法,在保存数据之前遍历所有字段,对字符串类型的字段自动去除空白字符。这种方式可以覆盖Model的所有字符串字段,不需要逐个定义字段类型。
重写save方法实现
我们在Model的save方法中,先获取所有字段的对象,判断字段类型是否为字符串类型,如果是则对对应的值进行strip操作。
from peewee import *
# 定义基础Model,重写save方法
class BaseModel(Model):
def save(self, *args, **kwargs):
# 遍历当前实例的所有字段
for field_name, field_obj in self._meta.fields.items():
# 判断字段是否为字符串类型
if isinstance(field_obj, (CharField, TextField)):
value = getattr(self, field_name)
# 如果值不为空且是字符串,去除首尾空白
if value is not None and isinstance(value, str):
setattr(self, field_name, value.strip())
# 调用父类的save方法完成保存
return super().save(*args, **kwargs)
# 定义测试Model,继承BaseModel
class Product(BaseModel):
name = CharField(max_length=100, null=False)
description = TextField(null=True)
class Meta:
database = SqliteDatabase('test.db')
# 初始化数据库和表
db = SqliteDatabase('test.db')
db.connect()
db.create_tables([Product])
# 测试插入带空白的数据
product = Product(name=' Wireless Mouse ', description=' Ergonomic design ')
product.save()
# 查询验证数据
saved_product = Product.get(Product.name == 'Wireless Mouse')
print(saved_product.name) # 输出 Wireless Mouse
print(saved_product.description) # 输出 Ergonomic design
方案优缺点
- 优点:一次重写就可以覆盖所有继承该Model的字符串字段,不需要逐个修改字段定义,适合需要统一处理所有字符串字段的场景。
- 缺点:如果某些字段不需要去除空白,需要额外加判断逻辑,对Model的侵入性比自定义字段类更高。
两种方案的选择建议
如果只有部分字段需要去除空白,或者不同字段需要不同的处理逻辑,优先选择自定义字段类的方案。如果需要所有字符串字段都统一去除空白,不需要特殊例外,重写Model的save方法会更高效。实际开发中可以根据业务需求灵活选择,也可以两种方案结合使用,比如基础字段用自定义类,特殊场景在save方法中补充处理。