使用 peewee 持久化 python 对象



这是我的用户对象

class User(BaseModel):
_email = CharField(max_length=255, unique=True)
_first_name = CharField(max_length=255)
_last_name = CharField(max_length=255)
_profile_image = CharField(max_length=500, default=None)
_gender = CharField(max_length=255, default=None)
def __init__(self, email, first_name, last_name):
self._email = email
self._first_name = first_name
self._last_name = last_name
self._profile_image = None
self._gender = None
def serialize(self):
user_map = {}
for attr, value in self.__dict__.items():
user_map[attr[1:]] = value
return user_map

这是基本模型对象

class BaseModel(Model):
_create_at = DateTimeField(default=datetime.now())
_modified_at = DateTimeField(default=datetime.now())
class Meta:
database = db

这就是数据库的定义方式,

db = SqliteDatabase('cmp_v0.db')

def before_request_handler():
db.connect()

def after_request_handler():
db.close()

这是用户资源,

class UserResource:
def on_get(self, req, res):
user = User('someone@email.com', 'Firstname', 'Lastname')
res.body = json.dumps(user.serialize())

这是创建 REST 终结点的代码

api = falcon.API()
api.add_route('/user', UserResource())

当我转到网址 http://127.0.0.1:8000/user 我收到以下错误,

instance._data[self.att_name] = value
TypeError: 'NoneType' object does not support item assignment

我做错了什么。

您看到的错误来自将值分配给_email_first_name等的User构造函数。这些是您的字段定义,不要将数据分配给这些名称 - 您应该使用相同的名称,但前面没有下划线。

当您设置诸如_email之类的内容时,您将覆盖字段定义,然后Peewee会感到非常困惑,因为当您尝试设置实例值时,它期望使用的字段定义已经消失了。

所以这个构造函数工作:

class User(BaseModel):
_email = CharField(max_length=255, unique=True)
_first_name = CharField(max_length=255)
_last_name = CharField(max_length=255)
_profile_image = CharField(max_length=500, default=None)
_gender = CharField(max_length=255, default=None)
def __init__(self, email, first_name, last_name):
self.email = email # note the lack of underscores
self.first_name = first_name
self.last_name = last_name
self.profile_image = None
self.gender = None

作为旁注,您的serialize方法也存在问题,因为它输出的 JSON 如下所示:

{"mail": "someone@email.com", "irst_name": "Firstname",
"rofile_image": null, "ast_name": "Lastname", "ender": null}

而我认为你想要这个:

{"gender": null, "first_name": "Firstname", 
"last_name": "Lastname", "profile_image": null, "email": "someone@email.com"}

其代码是这样的:

def serialize(self):
user_map = {}
for attr, value in self.__dict__.items():
user_map[attr] = value # note the change here
return user_map

Annnd 最后:通过覆盖__init__而不调用超类(您的BaseModel),您不会在UserModel上获得_create_at_modified_at的字段定义。

要使其正常工作,您需要执行以下操作:

def __init__(self, email, first_name, last_name):
super(User,self).__init__()
self.email = email

但后来我发现您的serialize功能停止工作 - 但是,最初的问题解决了!

更新

我回顾了 Peewee 的文档,包括它的快速入门,并决定有一种更好的方法:根本不使用自定义构造函数。

下面的代码功能齐全,避免了自定义构造函数。它不会在Falcon中包装任何东西,因为它与问题无关并保持更简单。

from datetime import datetime
from peewee import *
db = SqliteDatabase('cmp_v0.db')
db.connect()

class BaseModel(Model):
created_at = DateTimeField(default=datetime.now())
modified_at = DateTimeField(default=datetime.now())
class Meta:
database = db

class User(BaseModel):
# These are
email = CharField(max_length=255, unique=True)
first_name = CharField(max_length=255)
last_name = CharField(max_length=255)
profile_image = CharField(max_length=500, default=None)
gender = CharField(max_length=255, default=None)
def serialize(self):
user_map = {}
for attr, value in self.__dict__.items():
user_map[attr] = value
return user_map
db.create_tables([User], safe=True)
user_row_count = len(User.select())
user = User(email='someone{}@example.com'.format(user_row_count+1),
first_name='Firstname',
last_name='Lastname',
profile_image='',
gender='')
print 'User {} {} {}'.format(user.email, user.first_name, user.last_name)
print 'Timestamps {} {}'.format(user.created_at,
user.modified_at)
user.save()

这一切都通过Python和Peewee的魔力起作用。

我没有读过Peewee的源代码,但它会遵循一个熟悉的模式:

字段声明,即CharField是班级水平的;如果您使用 iPython 之类的东西检查User类,您将看到User.first_name存在。

当创建一个新的User时,Peewee 将在后台处理构造并生成一个User实例,该实例通过 Python 的__getattr____setattr__拦截属性值的所有读/写。

User实例save()调用时,它可能会使用类级字段声明来验证和构造要保存的 SQL 查询。

相关内容

  • 没有找到相关文章

最新更新