2015-10-09 86 views
4

我正在Flask中開發api,使用棉花糖進行序列化/反序列化/驗證,SQLAlchemy作爲我的ORM。用Marshmallow模式過濾sqlalchemy表更新

在我的更新函數中,我想限制可以更新的字段,例如我不希望用戶目前能夠更改他們的電子郵件。

爲了達到這個目的,我建立了一個模式(UserSchema),它的字段受到一個元組(UserSchemaTypes.UPDATE_FIELDS)的限制。這個元組不包含電子郵件。

我遇到的問題是電子郵件是我的數據庫中用戶行的必填字段。

因此,當我使用架構(users_schema.load(user_json))創建User模型對象時,會將一個非法對象添加到sqlalchemy會話中。

#schema to validate the posted fields against 
users_schema = UserSchema(only=UserSchemaTypes.UPDATE_FIELDS) 
#attempt to deserialize the posted json to a User model object using the schema 
user_data = users_schema.load(user_json) 
if not user_data.errors:#update data passed validation 
    user_update_obj = user_data.data 
    User.update(user_id,vars(user_update_obj)) 

在我更新功能本身我接下來要通過db.session.expunge_all從會話中刪除了這種非法對象(),就好像我不我收到OperationalError。

OperationalError: (raised as a result of Query-invoked autoflush; consider   
using a session.no_autoflush block if this flush is occurring prematurely) 
(_mysql_exceptions.OperationalError) (1048, "Column 'email' cannot be null") [SQL: u'INSERT INTO user (email, password, active, phone, current_login_at, last_login_at, current_login_ip, last_login_ip, login_count) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)'] [parameters: (None, None, 1, '0444', None, None, None, None, None)] 

是否有這樣做的更好/更清潔的方式:當db.session.expunge_all()被刪除

@staticmethod  
def update(p_id,data): 
    db.session.expunge_all()#hack I want to remove 
    user = User.query.get(p_id) 
    for k, v in data.iteritems(): 
     setattr(user, k, v) 
    db.session.commit() 

OperationalError收到?

回答

1

從史蒂芬洛里亞https://github.com/marshmallow-code/marshmallow-sqlalchemy/issues/33#issuecomment-147008000

這裏有幾個不同的方法,你可以採取:

選項1:現場參數

from marshmallow import Schema, fields, pre_load 

class BaseSchema(Schema): 
    @pre_load 
    def check_update_fields(self, data) 
     non_update_fields = set([ 
      fname, fobj for fname, obj in self.fields 
      if fobj.metadata.get('can_update') is False 
     ]) 
     return { 
      key: value for key, value in data.items() 
      if key not in non_update_fields 
     } 

class UserSchema(BaseSchema): 
    name = fields.Str() 
    email = fields.Str(can_update=False) 

選項2:類元選項

from marshmallow import Schema, SchemaOpts, fields, pre_load 
class BaseSchemaOpts(SchemaOpts): 
    def __init__(self, meta): 
     super().__init__(meta) 
     self.update_fields = getattr(meta, 'update_fields', set()) 

class BaseSchema(Schema): 
    OPTIONS_CLASS = BaseSchemaOpts 

    email = fields.Str(can_update=False) 

    @pre_load 
    def check_update_fields(self, data) 
     non_update_fields = set(self.fields) - set(self.opts.update_fields) 
     return { 
      key: value for key, value in data.items() 
      if key not in non_update_fields 
     } 

class UserSchema(BaseSchema): 

    name = fields.Str() 
    email = fields.Str() 

    class Meta: 
     update_fields = ('name',) 
0

您的數據庫與您的型號不符。

您應該同步數據庫是因爲您更改了有關模型的某些內容(電子郵件null爲非空)。刪除表格並重新同步數據庫,或使用遷移工具修改表格以匹配您的模型。