Many-to-One relationships in SQLAlchemy
I'm having trouble with Many-to-One relationships between my SQLAlchemy models. The relationship between ChangeOrder
(many) and Contract
(one) is fine, but the one between LineItem
(many) and ChangeOrder
(one) isn't working.
I've tried both approaches suggested in the basic relationships docs and both fail for the LineItem
to ChangeOrder
relationship.
# using back_populates
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
change_orders = relationship("ChangeOrder", back_populates="contract")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
line_items = relationship("LineItem", back_populates="change_order")
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", back_populates="change_orders")
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", back_populates="line_items")
def test_insert_change_order(db_session, item):
c = Contract()
db_session.add(c)
db_session.commit()
co = ChangeOrder(contract_id=c.id)
db_session.add(co)
db_session.commit()
row = db_session.query(Contract).get(c.id)
assert len(row.change_orders) == 1 # this Many-to-One works
li = LineItem(change_order_id=co.id)
db_session.add(li)
db_session.commit()
row = db_session.query(ChangeOrder).get(co.id)
assert len(row.line_items) == 1 # this Many-to-One does not
I also tried the backref
approach, but it has the same problem.
# using backref
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", backref="line_items")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", backref="change_orders")
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
conftest.py
import pytest
from flask_sqlalchemy import SQLAlchemy
from frontend.app import app
@pytest.fixture
def testapp():
db = SQLAlchemy()
app.config["SQLALCHEMY_ECHO"] = True
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
@pytest.fixture(scope="session")
def database():
db = SQLAlchemy()
with app.app_context():
db.create_all()
yield db
@pytest.fixture(scope="session")
def _db(database):
return database
sqlalchemy foreign-keys
add a comment |
I'm having trouble with Many-to-One relationships between my SQLAlchemy models. The relationship between ChangeOrder
(many) and Contract
(one) is fine, but the one between LineItem
(many) and ChangeOrder
(one) isn't working.
I've tried both approaches suggested in the basic relationships docs and both fail for the LineItem
to ChangeOrder
relationship.
# using back_populates
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
change_orders = relationship("ChangeOrder", back_populates="contract")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
line_items = relationship("LineItem", back_populates="change_order")
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", back_populates="change_orders")
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", back_populates="line_items")
def test_insert_change_order(db_session, item):
c = Contract()
db_session.add(c)
db_session.commit()
co = ChangeOrder(contract_id=c.id)
db_session.add(co)
db_session.commit()
row = db_session.query(Contract).get(c.id)
assert len(row.change_orders) == 1 # this Many-to-One works
li = LineItem(change_order_id=co.id)
db_session.add(li)
db_session.commit()
row = db_session.query(ChangeOrder).get(co.id)
assert len(row.line_items) == 1 # this Many-to-One does not
I also tried the backref
approach, but it has the same problem.
# using backref
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", backref="line_items")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", backref="change_orders")
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
conftest.py
import pytest
from flask_sqlalchemy import SQLAlchemy
from frontend.app import app
@pytest.fixture
def testapp():
db = SQLAlchemy()
app.config["SQLALCHEMY_ECHO"] = True
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
@pytest.fixture(scope="session")
def database():
db = SQLAlchemy()
with app.app_context():
db.create_all()
yield db
@pytest.fixture(scope="session")
def _db(database):
return database
sqlalchemy foreign-keys
Hi Jamie, both versions of your code are working for me. Are there any other specifics to your environment? Any session level configurations? If you setecho=True
on yourengine
do all of the queries look right?
– SuperShoot
Nov 9 at 20:50
Also, if you setuse_list=False
on the one side of the relationship your relationship attribute will either beNone
orobject
as opposed toor
[object]
which saves you from having to index out an object from a single length list every time you want to use it. Unrelated to your problem but just thought I'd mention.
– SuperShoot
Nov 9 at 20:55
Queries look fine to me. I've made sure all my migrations are up to date. Testing is usingpytest-flask-sqlalchemy
which provides thedb_session
and I've added myconftest.py
to the question
– Jamie Bull
Nov 9 at 21:17
1
Sorry but I can't see where your original example and that conftest file intersect. All I did was put at the bottom of your original examples engine = create_engine('sqlite://', echo=True); Session = sessionmaker(bind=engine); Base.metadata.drop_all(engine); Base.metadata.create_all(engine); test_insert_change_order(Session(), None)
– SuperShoot
Nov 9 at 21:25
1
Ok, I guess it's some problem in my testing setup then. I'll dig into that
– Jamie Bull
Nov 9 at 21:33
add a comment |
I'm having trouble with Many-to-One relationships between my SQLAlchemy models. The relationship between ChangeOrder
(many) and Contract
(one) is fine, but the one between LineItem
(many) and ChangeOrder
(one) isn't working.
I've tried both approaches suggested in the basic relationships docs and both fail for the LineItem
to ChangeOrder
relationship.
# using back_populates
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
change_orders = relationship("ChangeOrder", back_populates="contract")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
line_items = relationship("LineItem", back_populates="change_order")
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", back_populates="change_orders")
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", back_populates="line_items")
def test_insert_change_order(db_session, item):
c = Contract()
db_session.add(c)
db_session.commit()
co = ChangeOrder(contract_id=c.id)
db_session.add(co)
db_session.commit()
row = db_session.query(Contract).get(c.id)
assert len(row.change_orders) == 1 # this Many-to-One works
li = LineItem(change_order_id=co.id)
db_session.add(li)
db_session.commit()
row = db_session.query(ChangeOrder).get(co.id)
assert len(row.line_items) == 1 # this Many-to-One does not
I also tried the backref
approach, but it has the same problem.
# using backref
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", backref="line_items")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", backref="change_orders")
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
conftest.py
import pytest
from flask_sqlalchemy import SQLAlchemy
from frontend.app import app
@pytest.fixture
def testapp():
db = SQLAlchemy()
app.config["SQLALCHEMY_ECHO"] = True
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
@pytest.fixture(scope="session")
def database():
db = SQLAlchemy()
with app.app_context():
db.create_all()
yield db
@pytest.fixture(scope="session")
def _db(database):
return database
sqlalchemy foreign-keys
I'm having trouble with Many-to-One relationships between my SQLAlchemy models. The relationship between ChangeOrder
(many) and Contract
(one) is fine, but the one between LineItem
(many) and ChangeOrder
(one) isn't working.
I've tried both approaches suggested in the basic relationships docs and both fail for the LineItem
to ChangeOrder
relationship.
# using back_populates
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
change_orders = relationship("ChangeOrder", back_populates="contract")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
line_items = relationship("LineItem", back_populates="change_order")
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", back_populates="change_orders")
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", back_populates="line_items")
def test_insert_change_order(db_session, item):
c = Contract()
db_session.add(c)
db_session.commit()
co = ChangeOrder(contract_id=c.id)
db_session.add(co)
db_session.commit()
row = db_session.query(Contract).get(c.id)
assert len(row.change_orders) == 1 # this Many-to-One works
li = LineItem(change_order_id=co.id)
db_session.add(li)
db_session.commit()
row = db_session.query(ChangeOrder).get(co.id)
assert len(row.line_items) == 1 # this Many-to-One does not
I also tried the backref
approach, but it has the same problem.
# using backref
class LineItem(Base):
__tablename__ = "lineitem"
id = Column(Integer, primary_key=True)
change_order_id = Column(Integer, ForeignKey("changeorder.id"))
change_order = relationship("ChangeOrder", backref="line_items")
class ChangeOrder(Base):
__tablename__ = "changeorder"
id = Column(Integer, primary_key=True)
contract_id = Column(Integer, ForeignKey("contract.id"))
contract = relationship("Contract", backref="change_orders")
class Contract(Base):
__tablename__ = "contract"
id = Column(Integer, primary_key=True)
conftest.py
import pytest
from flask_sqlalchemy import SQLAlchemy
from frontend.app import app
@pytest.fixture
def testapp():
db = SQLAlchemy()
app.config["SQLALCHEMY_ECHO"] = True
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
@pytest.fixture(scope="session")
def database():
db = SQLAlchemy()
with app.app_context():
db.create_all()
yield db
@pytest.fixture(scope="session")
def _db(database):
return database
sqlalchemy foreign-keys
sqlalchemy foreign-keys
edited Nov 9 at 21:17
asked Nov 9 at 19:42
Jamie Bull
5,77384789
5,77384789
Hi Jamie, both versions of your code are working for me. Are there any other specifics to your environment? Any session level configurations? If you setecho=True
on yourengine
do all of the queries look right?
– SuperShoot
Nov 9 at 20:50
Also, if you setuse_list=False
on the one side of the relationship your relationship attribute will either beNone
orobject
as opposed toor
[object]
which saves you from having to index out an object from a single length list every time you want to use it. Unrelated to your problem but just thought I'd mention.
– SuperShoot
Nov 9 at 20:55
Queries look fine to me. I've made sure all my migrations are up to date. Testing is usingpytest-flask-sqlalchemy
which provides thedb_session
and I've added myconftest.py
to the question
– Jamie Bull
Nov 9 at 21:17
1
Sorry but I can't see where your original example and that conftest file intersect. All I did was put at the bottom of your original examples engine = create_engine('sqlite://', echo=True); Session = sessionmaker(bind=engine); Base.metadata.drop_all(engine); Base.metadata.create_all(engine); test_insert_change_order(Session(), None)
– SuperShoot
Nov 9 at 21:25
1
Ok, I guess it's some problem in my testing setup then. I'll dig into that
– Jamie Bull
Nov 9 at 21:33
add a comment |
Hi Jamie, both versions of your code are working for me. Are there any other specifics to your environment? Any session level configurations? If you setecho=True
on yourengine
do all of the queries look right?
– SuperShoot
Nov 9 at 20:50
Also, if you setuse_list=False
on the one side of the relationship your relationship attribute will either beNone
orobject
as opposed toor
[object]
which saves you from having to index out an object from a single length list every time you want to use it. Unrelated to your problem but just thought I'd mention.
– SuperShoot
Nov 9 at 20:55
Queries look fine to me. I've made sure all my migrations are up to date. Testing is usingpytest-flask-sqlalchemy
which provides thedb_session
and I've added myconftest.py
to the question
– Jamie Bull
Nov 9 at 21:17
1
Sorry but I can't see where your original example and that conftest file intersect. All I did was put at the bottom of your original examples engine = create_engine('sqlite://', echo=True); Session = sessionmaker(bind=engine); Base.metadata.drop_all(engine); Base.metadata.create_all(engine); test_insert_change_order(Session(), None)
– SuperShoot
Nov 9 at 21:25
1
Ok, I guess it's some problem in my testing setup then. I'll dig into that
– Jamie Bull
Nov 9 at 21:33
Hi Jamie, both versions of your code are working for me. Are there any other specifics to your environment? Any session level configurations? If you set
echo=True
on your engine
do all of the queries look right?– SuperShoot
Nov 9 at 20:50
Hi Jamie, both versions of your code are working for me. Are there any other specifics to your environment? Any session level configurations? If you set
echo=True
on your engine
do all of the queries look right?– SuperShoot
Nov 9 at 20:50
Also, if you set
use_list=False
on the one side of the relationship your relationship attribute will either be None
or object
as opposed to
or [object]
which saves you from having to index out an object from a single length list every time you want to use it. Unrelated to your problem but just thought I'd mention.– SuperShoot
Nov 9 at 20:55
Also, if you set
use_list=False
on the one side of the relationship your relationship attribute will either be None
or object
as opposed to
or [object]
which saves you from having to index out an object from a single length list every time you want to use it. Unrelated to your problem but just thought I'd mention.– SuperShoot
Nov 9 at 20:55
Queries look fine to me. I've made sure all my migrations are up to date. Testing is using
pytest-flask-sqlalchemy
which provides the db_session
and I've added my conftest.py
to the question– Jamie Bull
Nov 9 at 21:17
Queries look fine to me. I've made sure all my migrations are up to date. Testing is using
pytest-flask-sqlalchemy
which provides the db_session
and I've added my conftest.py
to the question– Jamie Bull
Nov 9 at 21:17
1
1
Sorry but I can't see where your original example and that conftest file intersect. All I did was put at the bottom of your original examples engine = create_engine('sqlite://', echo=True); Session = sessionmaker(bind=engine); Base.metadata.drop_all(engine); Base.metadata.create_all(engine); test_insert_change_order(Session(), None)
– SuperShoot
Nov 9 at 21:25
Sorry but I can't see where your original example and that conftest file intersect. All I did was put at the bottom of your original examples engine = create_engine('sqlite://', echo=True); Session = sessionmaker(bind=engine); Base.metadata.drop_all(engine); Base.metadata.create_all(engine); test_insert_change_order(Session(), None)
– SuperShoot
Nov 9 at 21:25
1
1
Ok, I guess it's some problem in my testing setup then. I'll dig into that
– Jamie Bull
Nov 9 at 21:33
Ok, I guess it's some problem in my testing setup then. I'll dig into that
– Jamie Bull
Nov 9 at 21:33
add a comment |
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53232317%2fmany-to-one-relationships-in-sqlalchemy%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53232317%2fmany-to-one-relationships-in-sqlalchemy%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Hi Jamie, both versions of your code are working for me. Are there any other specifics to your environment? Any session level configurations? If you set
echo=True
on yourengine
do all of the queries look right?– SuperShoot
Nov 9 at 20:50
Also, if you set
use_list=False
on the one side of the relationship your relationship attribute will either beNone
orobject
as opposed toor
[object]
which saves you from having to index out an object from a single length list every time you want to use it. Unrelated to your problem but just thought I'd mention.– SuperShoot
Nov 9 at 20:55
Queries look fine to me. I've made sure all my migrations are up to date. Testing is using
pytest-flask-sqlalchemy
which provides thedb_session
and I've added myconftest.py
to the question– Jamie Bull
Nov 9 at 21:17
1
Sorry but I can't see where your original example and that conftest file intersect. All I did was put at the bottom of your original examples engine = create_engine('sqlite://', echo=True); Session = sessionmaker(bind=engine); Base.metadata.drop_all(engine); Base.metadata.create_all(engine); test_insert_change_order(Session(), None)
– SuperShoot
Nov 9 at 21:25
1
Ok, I guess it's some problem in my testing setup then. I'll dig into that
– Jamie Bull
Nov 9 at 21:33