【发布时间】:2015-02-17 22:46:37
【问题描述】:
我在下面给出了代码...我想记录在User 表中完成的所有更改(提交前+提交后),并将它们以 JSON 格式存储在User2 表中。将它们存储在 JSON 中工作正常;
但flask-sqlalchemy 的before_models_committed 不起作用。我想我会在before_change函数更改之前和after_change函数更改之后记录;
我在after_commit 函数中得到obj.as_dict(),但在before_commit 中没有
在文档https://pythonhosted.org/Flask-SQLAlchemy/signals.html 中他们说before_models_committed 与models_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