我的问题实际上与sqlalchemy没有太大关系,而是与纯python有关。
我想控制sqlalchemy模型实例的实例化。这是我的代码片段:
class Tag(db.Model):
__tablename__ = 'tags'
query_class = TagQuery
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), unique=True, nullable=False)
def __init__(self, name):
self.name = name
我想实现的是,每当一个条目被实例化(
Tag('django')
)时,只有在数据库中还没有另一个名为django
的标记时,才应该创建一个新的实例。否则,不是初始化一个新对象,而是通过(Tag('django')
)返回对数据库中已经存在的行的引用。目前,我正在确保
Post
模型中标记的唯一性:class Post(db.Model):
# ...
# code code code
# ...
def _set_tags(self, taglist):
"""Associate tags with this entry. The taglist is expected to be already
normalized without duplicates."""
# Remove all previous tags
self._tags = []
for tag_name in taglist:
exists = Tag.query.filter(Tag.name==tag_name).first()
# Only add tags to the database that don't exist yet
# TODO: Put this in the init method of Tag (if possible)
if not exists:
self._tags.append(Tag(tag_name))
else:
self._tags.append(exists)
它完成了它的工作,但我仍然想知道如何确保标记类本身中标记的唯一性,以便我可以编写这样的
_set_tags
方法:def _set_tags(self, taglist):
# Remove all previous tags
self._tags = []
for tag_name in taglist:
self._tags.append(Tag(tag_name))
在写这个问题和测试时,我了解到我需要使用
__new__
方法。这就是我所想到的(它甚至通过了单元测试,而且我没有忘记更改_set_tags
方法):class Tag(db.Model):
__tablename__ = 'tags'
query_class = TagQuery
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(), unique=True, nullable=False)
def __new__(cls, *args, **kwargs):
"""Only add tags to the database that don't exist yet. If tag already
exists return a reference to the tag otherwise a new instance"""
exists = Tag.query.filter(Tag.name==args[0]).first() if args else None
if exists:
return exists
else:
return super(Tag, cls).__new__(cls, *args, **kwargs)
困扰我的有两件事:
第一:我得到一个警告:
DeprecationWarning: object.__new__() takes no parameters
第二:当我像这样写时,我得到了错误(我也试图将参数
name
重命名为n
,但它没有改变任何东西):def __new__(cls, name):
"""Only add tags to the database that don't exist yet. If tag already
exists return a reference to the tag otherwise a new instance"""
exists = Tag.query.filter(Tag.name==name).first()
if exists:
return exists
else:
return super(Tag, cls).__new__(cls, name)
错误(或类似):
TypeError: __new__() takes exactly 2 arguments (1 given)
我希望你能帮助我!
最佳答案
我用类方法。
class Tag(Declarative):
...
@classmethod
def get(cls, tag_name):
tag = cls.query.filter(cls.name == tag_name).first()
if not tag:
tag = cls(tag_name)
return tag
然后
def _set_tags(self, taglist):
self._tags = []
for tag_name in taglist:
self._tags.append(Tag.get(tag_name))
至于
__new__
,您不应将其与__init__
混淆。它应该被称为w/out参数,所以即使您自己的构造函数需要一些参数,也不应该将它们传递给super/object,除非您知道您的super需要它们。典型的调用是:def __new__(cls, name=None):
tag = cls.query.filter(cls.name == tag_name).first()
if not tag:
tag = object.__new__(cls)
return tag
但是,这在您的情况下不会像预期的那样工作,因为如果
__init__
返回__new__
的实例,它会自动调用cls
。您需要使用元类或在__init__
中添加一些检查。关于python - 控制python对象的实例化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3506498/