2017-06-13 13 views
1

質問は実際にSQLAlchemy宣言型モデルを更新してバリデーターを実行する方法です。私の場合、User.name = nameのようなセッターを使用することは、実際にはオプションではありません。以下はバリデータを実行中に辞書データを使用して宣言型SQLAlchemyモデルを更新する方法

は、あなただけのインスタンスの属性を設定するsetattr()を使用してではなく、単純な更新方法を提供し、あなたのモデルへのミックスインを追加することができ、私は

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 

from sqlalchemy import Column, String, Integer 
from sqlalchemy.orm import validates 
from sqlalchemy.ext.declarative import declarative_base 

some_engine = create_engine('sqlite://') 
Session = sessionmaker(bind=some_engine) 
session = Session() 


Base = declarative_base() 


class User(Base): 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False) 

    @validates('name') 
    def validate_name(self, key, value): 
     if value != 'asd': 
      raise ValueError('not asd') 
     return value 

Base.metadata.create_all(bind=some_engine) 

user = User(id=1, name='qwe') 
# >>> ValueError: not asd 
user = User(id=1, name='asd') 

session.add(user) 
session.commit() 

session.query(User).filter(User.id=1).update({'name': 'qwe'}) 
session.query(User).filter(User.id==1)[0].name 
# >>> 'qwe' 
+0

上のループを使用しますvalidates decoratorは[AttributeEvents](http://docs.sqlalchemy.org/)の上にある便利な機能ですja/latest/orm/events.html#sqlalchemy.orm.events.AttributeEvents)。そのため、一括更新では機能しません。更新前などのMapperイベントは一括更新でも起動しません。 "Query.update()メソッドは"一括操作 "であり、ORM作業単位自動化をバイパスしてパフォーマンスを向上させました。**すべての警告をお読みくださいそして以下の警告。あなたは "not asd"を強制するためにDBレベルでCHECK制約を追加することができます。 –

+0

SQLAlchemyでのCHECK制約の定義:http://docs.sqlalchemy.org/en/latest/core/constraints.html#check-constraint –

+0

「作業単位自動化をバイパスする」という免責事項は何も教えてくれません残念ながら、SQLAlchemyのドキュメントは本当に面倒で厄介です:( – user541905

答えて

1

何を意味するかの実行可能な例です。

class UpdateMixin: 
    """ 
    Add a simple update() method to instances that accepts 
    a dictionary of updates. 
    """ 
    def update(self, values): 
     for k, v in values.items(): 
      setattr(self, k, v) 

Userクラスは、その後

class User(UpdateMixin, Base): 
    ... 

として定義されるだろうそして、あなたは、例えば

session.query(User).get(1).update({ 'name': 'qwe' }) 
# or since you have the user instance from before 
user.update({ 'name': 'qwe' }) 

Query.get()の使用を実行する可能性が与えられた辞書から単一インスタンスを更新します。指定されたIDを持つユーザーがいない場合、Noneを返し、メソッド更新を呼び出そうとします。もう1つの注意点は、例外が発生した場合にロールバックしないと、ディクショナリに順序がないために更新があった場合(セッションに追加されたもの)を予測できないということです。だから、いつもどんなエラーでもロールバックしてください。

と混同しないように、実際にupdateSelfなどの名前を付けることをおすすめします。

1

簡単な答えは、モデルレベルの制約が必要なときにquery.updateを使用することではありません。このようなモデルレベルの制約を強制するよりも、パフォーマンスが重要な時代です。その他の答えは解決策の詳細を示していますが、根本的な答えは、Query.updateはPythonレベルの制約を強制することではないということです。ソリューションの 一般的なカテゴリは次のとおりです。

  • は、いくつかのセッション・レベルの方法とQuery.getまたはQuery.filter.all

  • チェック制約

  • トリガやストアドプロシージャ

関連する問題