2014-11-13 2 views
1

나는 아래 주어진 코드를 작성했습니다 ... 나는 (변경 전 커밋 + 커밋 후) User 테이블에서 수행 된 모든 변경 내용을 기록하고이를 User2 테이블에 JSON 형식으로 저장하려고합니다. . JSON에 저장하면 잘 작동합니다.

이지만 flask-sqlalchemybefore_models_committed이 작동하지 않습니다. 나는 변화 전의 before_change 기능과 변경 후 기록 할 것이라고 생각했다 after_change 기능;

내가 after_commit 기능에 obj.as_dict()를 얻을 수 있지만, 문서 https://pythonhosted.org/Flask-SQLAlchemy/signals.html에서 before_commit

에 그들은 before_models_committed 작품 정확히 같은 더 좋은 방법 models_committed


으로이 작업을 수행 할 수 있다는 말을하지 ???? 또는 아래 문제를 해결하는 방법 ????플라스크 sqlalchemy 레코드 테이블의 모든 변경 내용이 작동하지 않습니다

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'[email protected]'} 
127.0.0.1 - - [13/Nov/2014 16:54:32] "GET /change?username=testname&[email protected] 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'[email protected]'} 
127.0.0.1 - - [09/Jan/2015 10:38:02] "GET /change?username=testname&[email protected] 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'[email protected]'} 
127.0.0.1 - - [09/Jan/2015 10:38:19] "GET /change?username=testname1&[email protected] 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'[email protected]'} 
127.0.0.1 - - [09/Jan/2015 10:38:31] "GET /change?username=testname&[email protected] 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 
+0

'''pip freeze'''의 출력으로 답을 편집하여 실행중인 모든 버전을 볼 수 있습니다. – opyate

+0

@opyate : 나는'pip freeze'의 출력으로 게시물을 업데이트했고, 실행중인 앱의 자세한 터미널 로그를 추가했습니다. – namit

답변

0

Flask-SQLAlchemy의 버그로 인해 이러한 신호가 전혀 작동하지 않는 것 같습니다. 수정본이있는 pull-request은 이미 병합되었으며 아마도 Flask-SQLAlchemy 버전 2.1에서 릴리스 될 것입니다.

+0

@zwirbltier : 작업 예제를 게시 할 수 있습니까 ?? – namit

+0

@namit : 오해 하셨다고 생각합니다. 이것은 버그로 인해 작동하지 않습니다. 작동 예제가 없습니다. – zwirbeltier

관련 문제