32

いくつかのプロパティを一意にする必要があります。どうすればこれを達成できますか?

のようなものはありunique=Trueますか?

Python 用の Google App Engine を使用しています。

4

2 に答える 2

25

Google はそれを行う機能を提供しています。

http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model_get_or_insert

Model.get_or_insert(key_name, **kwds)

指定されたキー名でモデルの種類のエンティティを取得しようとします。存在する場合、get_or_insert() は単純にそれを返します。存在しない場合は、指定された種類、名前、および kwds のパラメーターを持つ新しいエンティティが作成され、保存され、返されます。

get とそれに続く (場合によっては) put は、原子性を確保するためにトランザクションにラップされます。これは、 get_or_insert() が既存のエンティティを上書きすることはなく、指定された種類と名前のエンティティが存在しない場合にのみ、新しいエンティティを挿入することを意味します。

つまり、get_or_insert() は次の Python コードと同等です。

def txn():
  entity = MyModel.get_by_key_name(key_name, parent=kwds.get('parent'))
  if entity is None:
    entity = MyModel(key_name=key_name, **kwds)
    entity.put()
  return entity
return db.run_in_transaction(txn)

引数:

key_name エンティティーのキーの名前 **kwds 指定されたキー名を持つインスタンスが存在しない場合に、モデル クラスのコンストラクターに渡すキーワード引数。目的のエンティティに親がある場合は、parent 引数が必要です。

注: get_or_insert() は RPC オブジェクトを受け入れません。

このメソッドは、要求されたエンティティが存在するか、メソッドによって作成されたかにかかわらず、そのエンティティを表すモデル クラスのインスタンスを返します。すべてのデータストア操作と同様に、トランザクションを完了できなかった場合、このメソッドは TransactionFailedError を発生させる可能性があります。

于 2011-04-29T08:44:07.293 に答える
21

値が一意であることを確認するための組み込みの制約はありません。ただし、これを行うことができます:

query = MyModel.all(keys_only=True).filter('unique_property', value_to_be_used)
entity = query.get()
if entity:
    raise Exception('unique_property must have a unique value!')

keys_only=Trueエンティティのデータをフェッチしないことでパフォーマンスがわずかに向上するため、使用します。

より効率的な方法は、キー名がプロパティ名 + 値で構成されるフィールドのない別のモデルを使用することです。次にget_by_key_name、これらの複合キー名の 1 つ以上を取得するために を使用できます。1 つ以上の not-None値を取得した場合は、重複する値があることがわかります (そうでない値を確認するとNone、一意でない値がわかります)。


onebyoneのコメントで述べたように、これらのアプローチは、最初に取得して後で実行するという性質により、リスクの同時実行性の問題を引き起こします。理論的には、既存の値のチェックの直後にエンティティが作成され、チェック後のコードが引き続き実行され、値が重複する可能性があります。これを防ぐには、トランザクションを使用する必要があります:トランザクション - Google App Engine


トランザクションを持つすべてのエンティティの一意性を確認する場合は、最初の方法を使用してそれらすべてを同じグループに入れる必要がありますが、これは非常に非効率的です。トランザクションの場合、次のように 2 番目の方法を使用します。

class UniqueConstraint(db.Model):
    @classmethod
    def check(cls, model, **values):
        # Create a pseudo-key for use as an entity group.
        parent = db.Key.from_path(model.kind(), 'unique-values')

        # Build a list of key names to test.
        key_names = []
        for key in values:
            key_names.append('%s:%s' % (key, values[key]))

        def txn():
            result = cls.get_by_key_name(key_names, parent)
            for test in result:
                if test: return False
            for key_name in key_names:
                uc = cls(key_name=key_name, parent=parent)
                uc.put()
            return True

        return db.run_in_transaction(txn)

UniqueConstraint.check(...)成功を返すには、すべての単一のキーと値のペアが一意である必要があると想定します。トランザクションは、モデルの種類ごとに 1 つのエンティティ グループを使用します。このように、トランザクションは一度に複数の異なるフィールドに対して信頼できます (1 つのフィールドのみの場合、これはより簡単になります)。また、1 つ以上のモデルに同じ名前のフィールドがある場合でも、それらは競合しません。お互い。

于 2009-07-26T22:13:16.067 に答える