当JOIN和LIMIT

时间:2015-10-12 20:54:32

标签: python sql orm sqlalchemy flask-sqlalchemy

我的应用程序具有可重现的错误published on github

错误的简短描述:SQLAlchemy使用子查询,但忽略ORDER_BY表达式中的子查询别名。

型号:

from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String)

class Genre(db.Model):
    __tablename__ = 'genres'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

class Magazine(db.Model):
    __tablename__ = 'magazines'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    genre_id = db.Column(db.Integer, db.ForeignKey('genres.id'))

    author = db.relationship(User,
                             backref=db.backref('magazines',
                                                order_by=id,
                                                lazy='joined'))
    genre = db.relationship(Genre,
                            backref=db.backref('magazines',
                                               order_by=id,
                                               lazy='joined'))

class WorkType(db.Model):
    __tablename__ = 'work_types'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

class WorkEvent(db.Model):
    __tablename__ = 'work_events'
    id = db.Column(db.Integer, primary_key=True)
    start_date = db.Column(db.DateTime, nullable=False)
    end_date = db.Column(db.DateTime, nullable=False)
    work_type_id = db.Column(db.Integer, db.ForeignKey('work_types.id'))
    work_type = db.relationship(WorkType,
                                backref=db.backref('work_events'), order_by=id,
                                lazy='joined')

class AuthorRate(db.Model):
    __tablename__ = 'author_rates'
    id = db.Column(db.Integer, primary_key=True)
    amount = db.Column(db.Float, nullable=False)
    work_type_id = db.Column(db.Integer, db.ForeignKey('work_types.id'))
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    work_type = db.relationship(WorkType,
                                backref=db.backref('author_rates'), order_by=id,
                                lazy='joined')

    author = db.relationship(User,
                             backref=db.backref('author_rates'),
                             order_by=id, lazy='joined')

的观点:

@app.route('/')
def index():
    for i in range(5):
        some_key = str(random.randint(1000000, 9000000))
        work_type = WorkType(name='work_type' + some_key)
        db.session.add(work_type)
        for j in range(8):
            some_other_key = str(random.randint(1000000, 9000000))
            user = User(username='user' + some_key + some_other_key)
            db.session.add(user)
            rate = AuthorRate(
                amount=1 + random.random(),
                work_type=work_type,
                author=user)
            db.session.add(rate)
    db.session.commit()
    print('========')
    rates = AuthorRate.query
    print(rates)
    rates = rates.limit(10)
    print('+++++++')
    print(rates)
    print('=========')
    rates = rates.offset(0)
    return render_template('limit.html', rates=rates)

模板:

{% for rate in rates %}
   <p>{{ rate.id }} - {{ rate.amount }} - {{ rate.work_type }} - {{ rate.author }}</p>
{% endfor %}

这是调用.limit()之前和之后的SQL表达式。

-- Initial
SELECT 
    author_rates.id AS author_rates_id, author_rates.amount AS author_rates_amount, author_rates.work_type_id AS author_rates_work_type_id, author_rates.author_id AS author_rates_author_id, work_types_1.id AS work_types_1_id, work_types_1.name AS work_types_1_name, users_1.id AS users_1_id, users_1.username AS users_1_username, magazines_1.id AS magazines_1_id, magazines_1.name AS magazines_1_name, magazines_1.author_id AS magazines_1_author_id, magazines_1.genre_id AS magazines_1_genre_id 
FROM author_rates 
LEFT OUTER JOIN work_types AS work_types_1 ON work_types_1.id = author_rates.work_type_id 
LEFT OUTER JOIN users AS users_1 ON users_1.id = author_rates.author_id 
LEFT OUTER JOIN magazines AS magazines_1 ON users_1.id = magazines_1.author_id ORDER BY author_rates.id, author_rates.id, magazines_1.id


-- Final
SELECT 
    anon_1.author_rates_id AS anon_1_author_rates_id, anon_1.author_rates_amount AS anon_1_author_rates_amount, anon_1.author_rates_work_type_id AS anon_1_author_rates_work_type_id, anon_1.author_rates_author_id AS anon_1_author_rates_author_id, work_types_1.id AS work_types_1_id, work_types_1.name AS work_types_1_name, users_1.id AS users_1_id, users_1.username AS users_1_username, magazines_1.id AS magazines_1_id, magazines_1.name AS magazines_1_name, magazines_1.author_id AS magazines_1_author_id, magazines_1.genre_id AS magazines_1_genre_id 
FROM (
    SELECT author_rates.id AS author_rates_id, author_rates.amount AS author_rates_amount, author_rates.work_type_id AS author_rates_work_type_id, author_rates.author_id AS author_rates_author_id 
    FROM author_rates 
    LIMIT 10 OFFSET 0) AS anon_1 
LEFT OUTER JOIN work_types AS work_types_1 ON work_types_1.id = anon_1.author_rates_work_type_id 
LEFT OUTER JOIN users AS users_1 ON users_1.id = anon_1.author_rates_author_id 
LEFT OUTER JOIN magazines AS magazines_1 ON users_1.id = magazines_1.author_id 
ORDER BY author_rates.id, author_rates.id, magazines_1.id;

错误:     ProgrammingError:(psycopg2.ProgrammingError)缺少表&#34; author_rates&#34;的FROM子句条目     第4行:... _ 1 ON users_1.id = magazines_1.author_id ORDER BY author_rat ...

热订单应该是:

 ORDER BY anon_1.author_rates_id, magazines_1.id;

问题:有解决方法吗?

环境: ubuntu 14.04,python 2.7,SQLAlchemy 1.0.8,Flask-SQLAlchemy 2.0,Flask 0.10.1 Stack trace

P.S。模型可能看起来有点奇怪,因为问题的根源在闭源应用程序中,我没有足够的想象力来编写好的概念证明

0 个答案:

没有答案