Reputation: 1913
I have an sql alchemy model that references another model as a foreign key.
class BaseMixin(object):
@classmethod
def create(cls, **kw):
obj = cls(**kw)
db.session.add(obj)
db.session.commit()
@classmethod
def find(cls, id):
obj = db.session.query(cls).get(id)
return obj
class Node(db.Model, BaseMixin):
id = db.Column(db.Integer, primary_key=True)
label = db.Column(db.String(120), unique=True, nullable=False)
firsts = db.relationship('First', backref='node', lazy=True)
def __repr__(self):
return f'<Node {self.label} {self.id}>'
def __init__(self, label):
self.label = label
class First(db.Model, BaseMixin):
id = db.Column(db.Integer, primary_key=True)
node_id = db.Column(db.Integer, db.ForeignKey('node.id'), nullable=False)
def __init__(self, label):
if label is None:
raise Exception("A first must have a label")
node = db.session.query(Node).filter_by(label=label).first()
if node is None:
node = Node(label=label)
node.create()
self.node_id = node.id
Elsewhere in my code, I try to create a first with a brand new label
, which seems like it should create a new node
in the process and use it as a foreign key:
first = First(label=context.label)
first.create()
But I get the following error:
File "models.py", line 12, in create
obj = cls(**kw)
TypeError: __init__() missing 1 required positional argument: 'label'
It seems to me that I am passing label
to node when trying to create. So why am I getting this error message?
Upvotes: 0
Views: 244
Reputation: 55884
There are a few issues here.
Firstly, the code initialises entities and then calls create
on the instance. This would result in two entities being initialised, since create
creates a new entity. create
is a classmethod, so it can be called on the class directly.
Secondly, the label
argument is not being passed to create
where it is called, so you get the error when create calls cls(**kw)
.
Instead of doing this
first = First(label=some_label)
first.create()
do this
first = First.create(label=some_label)
or just
first = First(label=some_label)
db.session.add(first)
(note that create
is also called in First.__init__
).
Thirdly - and this more of a preference - I'd avoid calling commit
in the create
method. Commit once, at the end of the request. This is more efficient and avoids situations where some objects get committed but others don't due to an exception being raised part way through a request.
Upvotes: 1