can not get one-to-many relations right with flask_sqlalchemy, getting sqlalchemy.exc.InvalidRequestError

Question:

I’m most probably missing some basic concept here, but I have tried to create something like simple code review application and trying to follow this docs when designing DB schema:

http://flask-sqlalchemy.pocoo.org/2.1/models/#one-to-many-relationships

Part (which can be used to reproduce) of my model is:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# all the imports
from flask import Flask, request, session, g, redirect, url_for, 
     abort, render_template, flash
from flask_sqlalchemy import SQLAlchemy

# configuration
DEBUG = True
SECRET_KEY = 'development key'
SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/test.db'


# create our little application :)
app = Flask(__name__)
app.config.from_object(__name__)   # load all uppercase constants here (see configuration section above)
db = SQLAlchemy(app)

class Repo(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    repo = db.Column(db.String(120), unique=True)
    commits = db.relationship('Commit',
        backref=db.backref('repo', lazy='dynamic'))

    def __init__(self, repo=None):
        self.repo = repo

    def __repr__(self):
        return '<Repo %r>' % (self.repo)


class Commit(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    repo_id = db.Column(db.Integer, db.ForeignKey('repo.id'))
    commit = db.Column(db.String(64))

    def __init__(self, repo_id=None, commit=None):
        self.repo_id = repo_id
        self.commit = commit

    def __repr__(self):
        return '<Commit %r (repo %r)>' % (self.commit, self.repo_id)

if __name__ == '__main__':
    app.run()

I get traceback when I attempt to create first repo:

>>> import code_review
>>> code_review.db.create_all()
>>> code_review.Repo('Pokus.git')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 2, in __init__
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/instrumentation.py", line 347, in _new_state_if_none
    state = self._state_constructor(instance, self)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 747, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/instrumentation.py", line 177, in _state_constructor
    self.dispatch.first_init(self, self.class_)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/event/attr.py", line 256, in __call__
    fn(*args, **kw)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2860, in _event_on_first_init
    configure_mappers()
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2756, in configure_mappers
    mapper._post_configure_properties()
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1710, in _post_configure_properties
    prop.init()
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/interfaces.py", line 183, in init
    self.do_init()
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1632, in do_init
    self._generate_backref()
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1863, in _generate_backref
    mapper._configure_property(backref_key, relationship)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1614, in _configure_property
    prop.post_instrument_class(self)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/interfaces.py", line 526, in post_instrument_class
    self.strategy.init_class_attribute(mapper)
  File "/usr/lib64/python2.7/site-packages/sqlalchemy/orm/dynamic.py", line 33, in init_class_attribute
    "uselist=False." % self.parent_property)
sqlalchemy.exc.InvalidRequestError: On relationship Commit.repo, 'dynamic' loaders cannot be used with many-to-one/one-to-one relationships and/or uselist=False.
Asked By: jhutar

||

Answers:

OK, I was confused by various guides and looks like this is what I want:

-    commits = db.relationship('Commit',
-        backref=db.backref('repo', lazy='dynamic'))
+    commits = db.relationship('Commit',
+        backref='repo', lazy='dynamic')
Answered By: jhutar

I also encounter this error while trying to typehint properly my code in python 3.8.

Previous code looked like this:

class Dealer(Base):
    """DB representation of a dealer"""

    __tablename__ = "dealers_dealer"

    id = Column(
        BigInteger,
        primary_key=True,
        server_default=text("nextval('dealers_dealer_id_seq'::regclass)"),
    )
    name = Column(String(100), nullable=False)
    invoice_email = Column(Text)


class User(Base):
    __tablename__ = "users_user"

    id = Column(
        BigInteger,
        primary_key=True,
        server_default=text("nextval('users_user_id_seq'::regclass)"),
    )
    email = Column(String(254), nullable=False, unique=True)
    dealer: Relationship[Dealer] = relationship(
        "Dealer", primaryjoin="User.dealer_id == Dealer.id"
    )

And was throwing two errors

sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'Mapper[User(users_user)]'. Original exception was: On relationship User.dealer, 'dynamic' loaders cannot be used with many-to-one/one-to-one relationships and/or uselist=False.

sqlalchemy.exc.InvalidRequestError: On relationship User.dealer, 'dynamic' loaders cannot be used with many-to-one/one-to-one relationships and/or uselist=False.

Once I removed the typehint for the dealer, the error disappeared.

Answered By: Samuel RIGAUD
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.