Postgres和SqlAlchemy没有正确更新行

时间:2017-02-16 23:19:39

标签: python postgresql amazon-web-services flask-sqlalchemy pgadmin

每当我使用带有session的{​​{1}}执行更新语句,然后调用SqlAlchemy时,它很少会更新数据库。

这是我的环境: 我有两台服务器在运行。一个用于我的数据库,另一个用于我的python服务器。

数据库服务器:

  • commit() - 在亚马逊的RDS上

使用Python的服务器

  • Postgres v9.6 - 在Amazon EC2实例
  • Linux 3.13.0-65-generic x86_64
  • SqlAlchemy v1.1.5
  • Python v3.4.3

另外,我使用Flask 0.11.1来查询我的表格。

重要文件:

pgAdmin 4

server/models/category.py

from sqlalchemy.orm import backref from .. import db from flask import jsonify class Category(db.Model): __tablename__ = "categories" id = db.Column(db.Integer, primary_key=True) cat_name = db.Column(db.String(80)) includes = db.Column(db.ARRAY(db.String), default=[]) excludes = db.Column(db.ARRAY(db.String), default=[]) parent_id = db.Column(db.ForeignKey('categories.id', ondelete='SET NULL'), nullable=True, default=None) subcategories = db.relationship('Category', backref=backref( 'categories', remote_side=[id], single_parent=True, cascade="all, delete-orphan" )) assigned_user = db.Column(db.String(80), nullable=True, default=None) def to_dict(self): return dict( id=self.id, cat_name=self.cat_name, parent_id=self.parent_id, includes=self.includes, excludes=self.excludes, assigned_user=self.assigned_user, ) def json(self): return jsonify(self.to_dict()) def __repr__(self): return "<%s %r>" % (self.__class__, self.to_dict()) class CategoryOperations: ... @staticmethod def update_category(category): return """ UPDATE categories SET cat_name='{0}', parent_id={1}, includes='{2}', excludes='{3}', assigned_user={4} WHERE id={5} RETURNING cat_name, parent_id, includes, excludes, assigned_user """.format( category.cat_name, category.parent_id if category.parent_id is not None else 'null', "{" + ",".join(category.includes) + "}", "{" + ",".join(category.excludes) + "}", "'" + category.assigned_user + "'" if category.assigned_user is not None else 'null', category.id ) @staticmethod def update(category, session): print("Updating category with id: " + str(category.id)) stmt = CategoryOperations.update_category(category) print(stmt) row_updated = session.execute(stmt).fetchone() return Category( id=category.id, cat_name=row_updated[0], parent_id=row_updated[1], includes=row_updated[2], excludes=row_updated[3], assigned_user=row_updated[4] ) ...

server/api/category.py

在这种情况下,还有一个文件可能会有用:

from flask import jsonify, request import json from .api_utils.utils import valid_request as is_valid_request from . import api from ..models.category import Category, CategoryOperations from ..models.users_categories import UsersCategoriesOperations, UsersCategories from ..models.listener_item import ListenerItemOperations, ListenerItem from ..models.user import UserOperations from ..schemas.category import category_schema from .. import get_session ... @api.route('/categories/<int:id>', methods=['PUT']) def update_category(id): category_json = request.json if category_json is None: return "Bad Request: Request not sent as json", 400 valid_json, json_err = is_valid_request(category_json, ['cat_name', 'parent_id', 'includes', 'excludes', 'assigned_user'], "and") if not valid_json: return json_err, 400 category = Category( id=id, cat_name=category_json['cat_name'], parent_id=category_json['parent_id'], includes=category_json['includes'], excludes=category_json['excludes'], assigned_user=category_json['assigned_user'], ) session = get_session() try: updated_category = CategoryOperations.update(category, session) session.commit() print(updated_category.to_dict()) return jsonify(updated_category.to_dict()), 200 except Exception as e: print("ROLLBACK") print(e) session.rollback() return str(e), 500 ...

server/__init__.py

为了解释我给出的环境和文件的更多内容,让我们说我的类别表中有一行如下:

import sqlalchemy as sa
from flask import Flask
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from config import config
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from flask_cors import CORS, cross_origin
from .db_config import CONFIG

db = SQLAlchemy()
ma = Marshmallow()

Engine = sa.create_engine(
    CONFIG.POSTGRES_URL,
    client_encoding='utf8',
    pool_size=20,
    max_overflow=0
)
Session = sessionmaker(bind=Engine)
conn = Engine.connect()


def get_session():
    return Session(bind=conn)


def create_app(config_name):
    app = Flask(__name__, static_url_path="/app", static_folder="static")
    app_config = config[config_name]()
    print(app_config)
    app.config.from_object(app_config)

    from .api import api as api_blueprint
    app.register_blueprint(api_blueprint, url_prefix='/api')

    from .api.routes import routes
    routes(app)

    from .auth import authentication
    authentication(app)

    db.init_app(app)
    ma.init_app(app)
    CORS(app)
    ...
    return app

当我向{ "assigned_user": null, "cat_name": "Category Name Before", "excludes": [ "exclude1", "excludeBefore" ], "id": 2, "includes": [ "include1", "include2" ], "parent_id": null } 发送PUT请求时,身体为:

/api/categories/2

在请求期间,我打印出我的PUT请求创建的SQL语句(用于测试),我得到了这个:

{
  "assigned_user": null,
  "cat_name": "Category Name 1",
  "excludes": [
    "exclude1",
    "exclude2"
  ],
  "id": 2,
  "includes": [
    "include1",
    "include2"
  ],
  "parent_id": null
}

提交UPDATE语句后,它会返回响应。我像这样得到更新后的对象:

UPDATE categories
SET cat_name='Category Name 1',
    parent_id=null,
    includes='{include1,include2}',
    excludes='{exclude1,exclude2}',
    assigned_user=null
WHERE id=2
RETURNING cat_name, parent_id, includes, excludes, assigned_user

当我使用以下网址发出GET请求时:{ "assigned_user": null, "cat_name": "Category Name 1", "excludes": [ "exclude1", "exclude2" ], "id": 2, "includes": [ "include1", "include2" ], "parent_id": null } 我得到了同样的对象:

/api/categories/2

但是,当我在{ "assigned_user": null, "cat_name": "Category Name 1", "excludes": [ "exclude1", "exclude2" ], "id": 2, "includes": [ "include1", "include2" ], "parent_id": null } 中运行下面的SQL命令时,我得到旧版本(它没有更新数据库中的行):

pgAdmin

这是我得到的对象:

SELECT * FROM categories WHERE id=2

这是我在做PUT请求之前的对象。如果我重新启动我的python服务器并执行GET请求,那么我将获得旧对象。感觉就像在会话中一样,它存储数据,但由于某种原因,它不会传播到数据库。

如果我在{ "assigned_user": null, "cat_name": "Category Name Before", "excludes": [ "exclude1", "excludeBefore" ], "id": 2, "includes": [ "include1", "include2" ], "parent_id": null } 中运行更新命令,它可能会很好地更新行。

更新:我还使用这些方法(如所讨论的here)进行更新,但仍然存在同样的问题:

pgAdmin

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

事实证明,每次调用get_session时,我都会创建一个新会话。每次HTTP请求后我都没有关闭会话。

以下是server/api/category.py PUT请求的样子:

@api.route('/categories/<int:id>', methods=['PUT'])
def update_category(id):
    category_json = request.json
    if category_json is None:
        return "Bad Request: Request not sent as json", 400
    valid_json, json_err = is_valid_request(category_json, ['cat_name', 'parent_id', 'includes', 'excludes', 'assigned_user'], "and")
    if not valid_json:
        return json_err, 400

    category = Category(
        id=id,
        cat_name=category_json['cat_name'],
        parent_id=category_json['parent_id'],
        includes=category_json['includes'],
        excludes=category_json['excludes'],
        assigned_user=category_json['assigned_user'],
    )
    session = get_session()
    try:
        updated_category = CategoryOperations.update(category, session)
        session.commit()
        print(updated_category.to_dict())
        return jsonify(updated_category.to_dict()), 200
    except Exception as e:
        print("ROLLBACK")
        print(e)
        session.rollback()
        return str(e), 500
    finally:                              #
        session.close()                   # <== The fix

一旦我关闭了我完成后打开的每个会话,问题就解决了。

希望这有助于某人。