【问题标题】:Flask sqlalchemy record all changes in the table is not workingFlask sqlalchemy 记录表中的所有更改不起作用
【发布时间】:2015-02-17 22:46:37
【问题描述】:

我在下面给出了代码...我想记录在User 表中完成的所有更改(提交前+提交后),并将它们以 JSON 格式存储在User2 表中。将它们存储在 JSON 中工作正常;

flask-sqlalchemybefore_models_committed 不起作用。我想我会在before_change函数更改之前和after_change函数更改之后记录;

我在after_commit 函数中得到obj.as_dict(),但在before_commit 中没有

在文档https://pythonhosted.org/Flask-SQLAlchemy/signals.html 中他们说before_models_committedmodels_committed 完全相同


有没有更好的方法来做到这一点???? 或者如何解决以下问题????

from sqlalchemy.types import TypeDecorator, VARCHAR
from sqlalchemy.ext.mutable import Mutable

import json
from bson import json_util

class JSONEncodedDict(TypeDecorator):
    impl = VARCHAR

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = json.dumps(value, default=json_util.default)
        return value

    def process_result_value(self, value, dialect):
        if value is not None:
            value = json.loads(value, object_hook=json_util.object_hook)
        return value


class MutableDict(Mutable, dict):
    @classmethod
    def coerce(cls, key, value):
        if not isinstance(value, MutableDict):
            if isinstance(value, dict):
                return MutableDict(value)

            return Mutable.coerce(key, value)
        else:
            return value

    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        self.changed()

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self.changed()

JsonType = MutableDict.as_mutable(JSONEncodedDict)

from flask import Flask, request, Response, jsonify, g
from flask_sqlalchemy import SQLAlchemy, models_committed, connection_stack, before_models_committed
from flask_login import current_user
from datetime import datetime

from time import sleep
import csv, json

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flask_test.sqlite'
# app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'

db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)
    pub_date = db.Column(db.DateTime)

    def __init__(self, username, email):
        self.username = username
        self.email = email
        self.pub_date = datetime.utcnow()

    def __repr__(self):
        return '<User %r>' % self.username

    def as_dict(self):
       return {c.name: getattr(self, c.name) for c in self.__table__.columns}

class User2(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80))
    olddata = db.Column(JsonType)
    newdata = db.Column(JsonType)
    updatedtime = db.Column(db.DateTime)
    event = db.Column(db.String(30))

    def __init__(self, username, olddata, newdata, event):
        self.username = username
        self.olddata = olddata
        self.newdata = newdata
        self.event = event
        self.updatedtime = datetime.utcnow()

    def __repr__(self):
        return '<User %r has commited some change>' % self.username

    def as_dict(self):
       return {c.name: getattr(self, c.name) for c in self.__table__.columns}

@app.route("/change")
def change_test():
    username, email = request.args.get("username"), request.args.get("email")
    admin1 = User.query.filter_by(username=username).first()
    if username and email:
        if admin1:
            admin1.email = email
            db.session.commit()
            return Response(json.dumps({"username": username,
                                        "email": email,
                                        "update": True}), mimetype='application/json')
        else:
            admin = User(username, email)
            db.session.add(admin)
            db.session.commit()
            return Response(json.dumps({"username": username,
                                        "email": email,
                                        "insert": True}), mimetype='application/json')
    else:
        return Response(json.dumps({"error": "please enter username and email"}), mimetype='application/json')

@before_models_committed.connect_via(app)
def before_change(sender, changes):
    print "Before Change:::"
    print "Sender", sender
    print "changes: "
    for obj, change in changes:
        print "\t", obj, change
        print "Details: "
        print "\t", obj.as_dict()

from sqlalchemy.orm.attributes import get_history

@models_committed.connect_via(app)
def after_change(sender, changes):
    print "After Change:::"
    print "Sender", sender
    print "changes: "
    # s2 = db.create_scoped_session({'scopefunc': connection_stack.__ident_func__})

    for obj, change in changes:
        # for x in obj.__table__.columns:
        #     history=get_history(changes, x)
        print "\t", obj, change
        print "Details: "
        print "\t", obj.as_dict()
        # admin1 = User.query.filter_by(username='admin').first()
        # print "Before change2::", admin1.as_dict()




db.create_all()

if __name__ == "__main__":
    app.run(debug=True, threaded=True)

并且只记录“after_commit”的变化;我写了下面的代码,但在这里我必须创建另一个会话;这里也是;我没有得到before_commit 值的地方!!!

@models_committed.connect_via(app)
def on_models_committed(sender, changes):
    s2 = db.create_scoped_session({'scopefunc': connection_stack.__ident_func__})
    for obj, change in changes:
        if change == "update" or change == "delete":
            curr_user = current_user
            if not curr_user:
                curr_user = "anonymous"

            user2 = User2(curr_user, obj.as_dict(), change)
            s2.add(user2)
            s2.commit()
    s2.close()

终端日志是:

After Change:::
Sender <Flask 'app'>
changes: 
    <User u'testname'> insert
Details: 
    {'username': u'testname', 'pub_date': datetime.datetime(2014, 11, 13, 11, 24, 32, 592000), 'id': 2, 'email': u'testname@gmail.com'}
127.0.0.1 - - [13/Nov/2014 16:54:32] "GET /change?username=testname&email=testname@gmail.com HTTP/1.1" 200 -

更新 1:

这里是更详细的终端日志

 * Running on http://127.0.0.1:5000/
 * Restarting with reloader
After Change:::
Sender <Flask 'app'>
changes: 
    <User u'testname'> insert
Details: 
    {'username': u'testname', 'pub_date': datetime.datetime(2015, 1, 9, 5, 8, 2, 433000), 'id': 1, 'email': u'testname1@gmail.com'}
127.0.0.1 - - [09/Jan/2015 10:38:02] "GET /change?username=testname&email=testname1@gmail.com HTTP/1.1" 200 -
127.0.0.1 - - [09/Jan/2015 10:38:02] "GET /favicon.ico HTTP/1.1" 404 -
After Change:::
Sender <Flask 'app'>
changes: 
    <User u'testname1'> insert
Details: 
    {'username': u'testname1', 'pub_date': datetime.datetime(2015, 1, 9, 5, 8, 19, 9000), 'id': 2, 'email': u'testname11@gmail.com'}
127.0.0.1 - - [09/Jan/2015 10:38:19] "GET /change?username=testname1&email=testname11@gmail.com HTTP/1.1" 200 -
After Change:::
Sender <Flask 'app'>
changes: 
    <User u'testname'> update
Details: 
    {'username': u'testname', 'pub_date': datetime.datetime(2015, 1, 9, 5, 8, 2, 433000), 'id': 1, 'email': u'testname2@gmail.com'}
127.0.0.1 - - [09/Jan/2015 10:38:31] "GET /change?username=testname&email=testname2@gmail.com HTTP/1.1" 200 -

pip freeze 的输出如下:

alembic==0.6.7
backports.ssl-match-hostname==3.4.0.2
blinker==1.3
certifi==14.05.14
cffi==0.8.6
click==3.3
colorama==0.3.2
cryptography==0.6.1
decorator==3.4.0
diesel==3.0.5
dulwich==0.9.9
email==4.0.2
Flask==0.10.1
Flask-Bcrypt==0.6.0
Flask-Bootstrap==3.2.0.2
Flask-Bootstrap3==3.1.1.3
flask-cache==0.13
Flask-Login==0.2.11
Flask-Migrate==1.2.0
flask-mongoengine==0.7.1
Flask-Script==2.0.5
Flask-Session==0.1.1
Flask-SQLAlchemy==2.0
Flask-SQLAlchemySession==0.0.1
Flask-Storage==0.1.0
Flask-Uploads==0.1.3
Flask-WTF==0.10.2
freeze==0.8.0
GitPython==0.1.7
greenlet==0.4.5
ipython==2.3.1
itsdangerous==0.24
jdcal==1.0
Jinja2==2.7.3
jsonpickle==0.8.0
Mako==1.0.0
MarkupSafe==0.23
matplotlib==1.4.2
mongoengine==0.8.7
mysql-connector-python==1.0.12
networkx==1.9.1
nltk==3.0.0
numpy==1.8.1
openpyxl==1.8.6
pbr==0.10.0
psutil==2.1.3
PuLP==1.5.6
py==1.4.25
pycosat==0.6.0
pycparser==2.10
pymongo==2.7.2
PyMySQL==0.6.2
pyOpenSSL==0.14
pyparsing==1.5.7
pyreadline==2.0
pysoundcard==0.5.0
pytest==2.6.3
python-dateutil==2.3
pytz==2014.10
pywin32==219
PyYAML==3.11
pyzmq==14.4.1
requests==2.4.3
schedule==0.3.1
scikit-learn==0.15.2
scipy==0.13.3
simplejson==3.6.5
six==1.8.0
SQLAlchemy==0.9.8
sqlalchemy-migrate==0.9.2
sqlparse==0.1.13
Tempita==0.5.2
tornado==4.0.2
trie==0.1.1
Twiggy==0.4.5
Twisted==14.0.2
uuid==1.30
validator==2.0.6
validator.py==1.2.0
validators==0.7
virtualenv==1.9.1
webapp2==2.5.2
Werkzeug==0.9.6
wheel==0.24.0
Whoosh==2.6.0
wrapt==1.9.0
WTForms==2.0.1
xlrd==0.9.3
xmldict==0.4.1
zope.interface==4.1.1

【问题讨论】:

  • 请使用pip freeze 的输出编辑您的答案,以便我们查看您正在运行的所有内容的版本。
  • @opyate:我已经用pip freeze 的输出更新了帖子,还添加了运行应用程序的更详细的终端日志。

标签: python sqlalchemy flask-sqlalchemy


【解决方案1】:

由于 Flask-SQLAlchemy 中的错误,这些信号目前似乎根本不起作用。带有修复的pull-request 已经合并,可能会在 Flask-SQLAlchemy 的 2.1 版中发布。

【讨论】:

  • @namit:我想你误会了。由于错误,这不起作用。没有工作示例。
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
  • 2017-12-15
  • 2020-06-05
  • 1970-01-01
相关资源
最近更新 更多