Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with STI: __tablename__ automatically set (unwanted behaviour) #481

Closed
dizpers opened this issue Mar 3, 2017 · 7 comments
Closed
Milestone

Comments

@dizpers
Copy link

dizpers commented Mar 3, 2017

Hey, guys.

I'm using:

  • Flask-SQLAlchemy==2.2;
  • SQLAlchemy==1.1.5.

And have the problem, originally described in this SO question. My models setup looks like the following:

from flask_sqlalchemy import SQLAlchemy


db = SQLAlchemy()


class Item(db.Model):
    __tablename__ = 'item'

    id = db.Column(db.Integer, primary_key=True)
    info = db.Column(db.String(255))
    type = db.Column(db.String())

    __mapper_args__ = {
        'polymorphic_on': type
    }


class ItemA(Item):
    __mapper_args__ = {
        'polymorphic_identity': 'a'
    }


class ItemB(Item):
    __mapper_args__ = {
        'polymorphic_identity': 'b'
    }


class ItemC(Item):
    __mapper_args__ = {
        'polymorphic_identity': 'c'
    }

print(ItemB.query)

I want to use Single Table Inheritance (STI). So expected output of the print(ItemB.query) statement is something like:

SELECT item.id AS item_id, item.info AS item_info, item.type AS item_type FROM item WHERE item.type IN (?)

And at the same time I'm getting:

SELECT item.id AS item_id, item.info AS item_info, item.type AS item_type FROM item

@univerio (@univerio, is it you? 😃 ) has pointed that Flask-SQLAlchemy automatically set __tablename__ attribute. It means that my model setup, presented above, doesn't follow STI model.

Is there any way to disable such behaviour by default? From my POV that behaviour sounds like a wrong approach, having a developer (how doesn't know that fact) to spend hours to understand why something isn't working.

Thanks.

@dizpers
Copy link
Author

dizpers commented Mar 3, 2017

BTW, I've just noted that it's happening only with Flash-SQLAlchemy==2.2 (no problems at all with 2.1 version).

@davidism
Copy link
Member

davidism commented Mar 3, 2017

This is odd, because the tests for single table inheritance pass. I'll add it to the 2.2.1 milestone.

@davidism davidism added this to the 2.2.1 milestone Mar 3, 2017
@dizpers
Copy link
Author

dizpers commented Mar 4, 2017

I've just discovered that it becames broken on f4662ad.

@dizpers
Copy link
Author

dizpers commented Mar 4, 2017

@davidism, I've just comitted the test for single table inheritance setup (dizpers@d75506b). It checks that __table__ and __tablename__ is None for child models. I thought that this should be the expected behaviour for some cases (I would say STI only for now).

And in the meantime there are 2 facts:

  1. it was working with Flask-SQLAlchemy==2.1 (last working commit is 9eff8b6), __table__ and __tablename__ attributes were in child models;
  2. futher more with raw SQLAlchemy it works just fine and also has those attributes (please, check https://repl.it/GFDD/2).

So, it seems that problem is something more than just __table__ and __tablename__ values.

@Natureshadow
Copy link

The Veripeditus team and I just spent a full month finding out why everything broke all over the place, and it turned out to be this very bug, which breaks not only single table inheritance, but also joined table inheritance in our case (but that might be because we configure the polymorphic mapper with some advanced magic).

@vToMy
Copy link

vToMy commented May 6, 2017

I believe I have a solution for this. I changed the tablename definition as follows:

    @declared_attr
    def __tablename__(cls):
        if '_cached_tablename' not in cls.__dict__:
            if _should_set_tablename(cls):
                cls._cached_tablename = camel_to_snake_case(cls.__name__)
            else:
                cls._cached_tablename = None

        return cls._cached_tablename

The noticeable difference is that I explicitly set _cached_tablename to None if __should_set_tablename returns False. The reason being that, otherwise, the model uses the inherited cached name which caused this wrong behavior.

@davidism
Copy link
Member

davidism commented Sep 25, 2017

Duplicate of #478, although a slightly different error somehow. Should be covered by #541.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

4 participants