这是我的用户对象
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 查询。