2014-01-23 84 views
1

我正在使用從文檔中實際複製的最基本的應用程序,並且正在接收非常令人討厭的錯誤。我已經能夠找到它,但不知道如何解決它。我知道在執行flask-security時會出現問題,但是這個錯誤來自sqlalchemy。有什麼建議?修改SqlAlchemy模型時出現不可更改的類型錯誤

from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy 
import logging 
app = Flask(__name__) 

app.config['DEBUG'] = True 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:' # 

db = SQLAlchemy(app) 

roles_users = db.Table('roles_users', 
     db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), 
     db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) 

class Role(db.Model): 
    id = db.Column(db.Integer(), primary_key=True) 
    name = db.Column(db.String(80), unique=True) 
    description = db.Column(db.String(255)) 

    def __init__(self, name, desc): 
     self.name = name 
     self.description = desc 

    def __repr__(self): 
     return '<Role: {}>'.format(str(self.name)) 

class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    username = db.Column(db.String(255), unique=True) 
    password = db.Column(db.String(255)) 
    roles = db.relationship('Role', secondary=roles_users, 
          backref=db.backref('users', lazy='dynamic')) 

    def __init__(self, username, password): 
     self.username = username 
     self.password = password 

    def __repr__(self): 
     return '<User: {}>'.format(str(self.username)) 

def main(): 
    db.create_all() 
    adminRole = Role('Admin', 'Unrestricted') 
    adminUser = User('admin', 'adminpassword') 
    adminUser.roles = [adminRole] 
    db.session.add(adminUser) 
    db.session.commit() 
    app.run(debug=True) 

if __name__ == '__main__': 
    LOG_FILENAME = 'test.log' 
    logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,) 
    logging.debug('This message should go to the log file') 
    try: 
     main() 
    except: 
     logging.exception('Got exception on main handler') 
     raise 

上面的代碼工作得很好。用瓶-Security和子類RoleMixin(它增加了EQNE功能模型時,問題就來一旦類變成這樣:

class Role(db.Model): 
    id = db.Column(db.Integer(), primary_key=True) 
    name = db.Column(db.String(80), unique=True) 
    description = db.Column(db.String(255)) 

    def __init__(self, name, desc): 
     self.name = name 
     self.description = desc 

    def __repr__(self): 
     return '<Role: {}>'.format(str(self.name)) 


    def __eq__(self, other): 
     return (self.name == other or 
       self.name == getattr(other, 'name', None)) 

    def __ne__(self, other): 
     return not self.__eq__(other) 

我收到以下錯誤:

ERROR:root:Got exception on main handler 
Traceback (most recent call last): 
    File "test.py", line 66, in <module> 
    main() 
    File "test.py", line 53, in main 
    adminUser.roles = [adminRole] 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\attributes.py", line 220, in __set__ 
    instance_dict(instance), value, None) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\attributes.py", line 975, in set 
    lambda adapter, i: adapter.adapt_like_to_iterable(i)) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\attributes.py", line 1010, in _set_iterable 
    collections.bulk_replace(new_values, old_collection, new_collection) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\collections.py", line 782, in bulk_replace 
    constants = existing_idset.intersection(values or()) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\util\_collections.py", line 592, in intersection 
    result._members.update(self._working_set(members).intersection(other)) 
TypeError: unhashable type: 'Role' 
DEBUG:root:This message should go to the log file 
ERROR:root:Got exception on main handler 
Traceback (most recent call last): 
    File "test.py", line 66, in <module> 
    main() 
    File "test.py", line 53, in main 
    adminUser.roles = [adminRole] 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\attributes.py", line 220, in __set__ 
    instance_dict(instance), value, None) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\attributes.py", line 975, in set 
    lambda adapter, i: adapter.adapt_like_to_iterable(i)) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\attributes.py", line 1010, in _set_iterable 
    collections.bulk_replace(new_values, old_collection, new_collection) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\orm\collections.py", line 782, in bulk_replace 
    constants = existing_idset.intersection(values or()) 
    File "C:\Users\ramabodhi\Envs\test\lib\site-packages\sqlalchemy\util\_collections.py", line 592, in intersection 
    result._members.update(self._working_set(members).intersection(other)) 
TypeError: unhashable type: 'Role' 

我對蟒蛇3.3 Windows 7和我所有的包都是最新的。

+0

你說你是繼承RoleMixin,但你的角色是db.Model類 –

+0

我的解釋不一致,對不起。所有RoleMixin所做的就是將__eq__和__ne__函數添加到模型中,所以我爲了簡單起見而將其編碼爲正確。 – ramabodhi

回答

4

我有一個「解決方案」,但我想,以確保它是一個可行的解決方案,而不是一個不穩定黑客攻擊。

我知道添加NE當量功能對類需要以所添加的散列函數爲模型是哈希的。所以這是現在的工作:

class Role(db.Model): 
    id = db.Column(db.Integer(), primary_key=True) 
    name = db.Column(db.String(80), unique=True) 
    description = db.Column(db.String(255)) 

    def __init__(self, name, desc): 
     self.name = name 
     self.description = desc 

    def __repr__(self): 
     return '<Role: {}>'.format(str(self.name)) 


    def __eq__(self, other): 
     return (self.name == other or 
       self.name == getattr(other, 'name', None)) 

    def __ne__(self, other): 
     return not self.__eq__(other) 

    def __hash__(self): 
     return hash(self.name) 

讓我知道,如果我已經做到了這一點,謝謝!

+0

我通常將'__hash__'實現爲'return id(self)'。 – dirn

+1

@dim:你應該打破這個習慣; python中的哈希約束是'a == b'意味着'hash(a)== hash(b)',但是如果你已經像ramabodhi一樣覆蓋了'__eq__',該約束將不再成立,並且會導致面向散列的集合被破壞。 – SingleNegationElimination

+0

即使我的__eq__和__ne__函數沒有包含覆蓋,我在類似的Role類中也有同樣的錯誤。我也發現,爲#ramabodhi添加__hash__函數,解決了這個問題。 –