Peewee 模型中的 Getter 和 setter 方法
Getter and setter methods in a Peewee model
我在 Peewee 中有以下简单模型:
class SiteText(BaseModel):
url = TextField()
text = TextField()
my_counter = IntegerField()
def get_text_by_url(url):
d = [s.text for s in SiteText.select(SiteText.url == url)]
d = d[0] if len(d) > 0 else None
return d
def save_text(updates):
# updates is a dict containing, url, text, my_counter
SiteText.upsert(**updates)
def get_outage_counter(url):
c = [c.my_counter for c in SiteText.select(SiteText.url == url)]
c = c[0] if len(c) > 0 else None
return c
def set_outage_counter(url, counter):
c = SiteText.get(SiteText.url == url)
c.counter = counter
c.save()
但是有些属性写getter和setter感觉比较奇怪。有没有更Pythonic的方式来做到这一点?例如,我是否应该使用一种方法来获取和设置指定 URL 的中断计数器?我是否应该将 getter 和 setter 函数转换为属性(尽管它们会与实际属性发生冲突)。欢迎反馈!
实际上使用属性不会与您的属性名称冲突,因为它们可能与 getter/setter 函数不同。
class Example:
def __init__(self):
self.value = 5
@property
def value(self):
print('Entering value getter')
return self._value
@value.setter
def value(self, val):
print('Entering value setter')
self._value = val
假设我们有上面的 class。您可以看到 getter 函数正在返回 _value
这对于那些在 __init__
方法中看到只有 self.value = 5
而没有 self._value
的人来说可能会很奇怪].
假设我们接下来要这样做:
a = Example()
在实例化 class 对象之后,由于 self.value = 5
,__init__
正在调用 value.setter
函数,因此,我们得到:
a = Example()
Entering value setter
print(a.value)
Entering value getter
5
print(a.__dict__)
{'_value': 5} # _value was created in setter function
因此,如您所见,您可以这样使用属性,并且没有问题。
由于 peewee 使用 metaclasses 和 class 变量的方式,无法在 __init__
中定义您的字段,您必须替换名称
class SiteText(db.Model):
url = CharField()
@property
def gs_url(self):
return self.url
@gs_url.setter
def gs_url(self, val):
self.url = val
Peewee 的 playhouse
扩展包括 hybrid attributes,这可能正是您要找的。它们基本上是 @properties
,但经过修改以与 peewee 一起使用。
这是我自己的代码示例:
from peewee import *
from playhouse import hybrid # <-- imports the hybrid extension
class User(BaseModel):
username = CharField()
_password = CharField() # <-- note the underscore
# ... other fields come here ...
@hybrid.hybrid_property
def password(self):
return self._password
@password.setter
def set_password(self, plaintext):
self._password = generate_password_hash(plaintext)
这是为了存储散列密码:因此 setter 使用函数 (generate_password_hash
) 在存储密码之前对其进行处理。
在您的情况下,您将改用自己的函数
class SiteText(BaseModel):
_counter = IntegerField()
@hybrid.property
def counter(self):
# code to process output can come here
return _counter
@counter.setter
def set_counter(self, counter):
# code to process counter comes here
self._counter = counter
然后,如果 s
是一个 SiteData
对象,您可以 运行 命令,如 s.counter = 1
、print s.counter
等。在将数据保存为对象中的 _counter
之前,将使用 getter 和 setter 自动预处理数据。
最后,我建议您不要在 getter 和 setter 中 运行 save()
。相反,让属性保存在对象中,然后手动 运行 save()
将它们提交到数据库。否则你最终可能会不必要地多次访问数据库,或者保存你不想要的东西。
我在 Peewee 中有以下简单模型:
class SiteText(BaseModel):
url = TextField()
text = TextField()
my_counter = IntegerField()
def get_text_by_url(url):
d = [s.text for s in SiteText.select(SiteText.url == url)]
d = d[0] if len(d) > 0 else None
return d
def save_text(updates):
# updates is a dict containing, url, text, my_counter
SiteText.upsert(**updates)
def get_outage_counter(url):
c = [c.my_counter for c in SiteText.select(SiteText.url == url)]
c = c[0] if len(c) > 0 else None
return c
def set_outage_counter(url, counter):
c = SiteText.get(SiteText.url == url)
c.counter = counter
c.save()
但是有些属性写getter和setter感觉比较奇怪。有没有更Pythonic的方式来做到这一点?例如,我是否应该使用一种方法来获取和设置指定 URL 的中断计数器?我是否应该将 getter 和 setter 函数转换为属性(尽管它们会与实际属性发生冲突)。欢迎反馈!
实际上使用属性不会与您的属性名称冲突,因为它们可能与 getter/setter 函数不同。
class Example:
def __init__(self):
self.value = 5
@property
def value(self):
print('Entering value getter')
return self._value
@value.setter
def value(self, val):
print('Entering value setter')
self._value = val
假设我们有上面的 class。您可以看到 getter 函数正在返回 _value
这对于那些在 __init__
方法中看到只有 self.value = 5
而没有 self._value
的人来说可能会很奇怪].
假设我们接下来要这样做:
a = Example()
在实例化 class 对象之后,由于 self.value = 5
,__init__
正在调用 value.setter
函数,因此,我们得到:
a = Example()
Entering value setter
print(a.value)
Entering value getter
5
print(a.__dict__)
{'_value': 5} # _value was created in setter function
因此,如您所见,您可以这样使用属性,并且没有问题。
由于 peewee 使用 metaclasses 和 class 变量的方式,无法在 __init__
中定义您的字段,您必须替换名称
class SiteText(db.Model):
url = CharField()
@property
def gs_url(self):
return self.url
@gs_url.setter
def gs_url(self, val):
self.url = val
Peewee 的 playhouse
扩展包括 hybrid attributes,这可能正是您要找的。它们基本上是 @properties
,但经过修改以与 peewee 一起使用。
这是我自己的代码示例:
from peewee import *
from playhouse import hybrid # <-- imports the hybrid extension
class User(BaseModel):
username = CharField()
_password = CharField() # <-- note the underscore
# ... other fields come here ...
@hybrid.hybrid_property
def password(self):
return self._password
@password.setter
def set_password(self, plaintext):
self._password = generate_password_hash(plaintext)
这是为了存储散列密码:因此 setter 使用函数 (generate_password_hash
) 在存储密码之前对其进行处理。
在您的情况下,您将改用自己的函数
class SiteText(BaseModel):
_counter = IntegerField()
@hybrid.property
def counter(self):
# code to process output can come here
return _counter
@counter.setter
def set_counter(self, counter):
# code to process counter comes here
self._counter = counter
然后,如果 s
是一个 SiteData
对象,您可以 运行 命令,如 s.counter = 1
、print s.counter
等。在将数据保存为对象中的 _counter
之前,将使用 getter 和 setter 自动预处理数据。
最后,我建议您不要在 getter 和 setter 中 运行 save()
。相反,让属性保存在对象中,然后手动 运行 save()
将它们提交到数据库。否则你最终可能会不必要地多次访问数据库,或者保存你不想要的东西。