2016-10-31 4 views
1

Djangoの値を原子的に比較交換保存するにはどうすればModelインスタンスFieldにすることができますか? (PostgreSQLをDBバックエンドとして使用する)。Djangoのモデルフィールドを原子的に比較交換する

このようなコンテンツを持つ複数の投稿(同じフォームの送信など)は、安全でなくてもうまく動作しないクライアント側のJavaScriptまたはフォーム側のUUIDのサーバー側のトラッキングにのみ依存することなく有効ですこれは悪意のある複数の投稿に対して安全ではありません。例えば

:あなたが探しているものを

def compare_exchange_save(model_object, field_name, comp, exch): 
    # How to implement? 
    .... 


from django.views.generic.edit import FormView  
from django.db import transaction 
from my_app.models import LicenseCode 

class LicenseCodeFormView(FormView): 
    def post(self, request, ...): 

     # Get object matching code entered in form 
     license_code = LicenseCode.objects.get(...) 

     # Safely redeem the code exactly once 
     # No change is made in case of error 
     try: 
      with transaction.atomic() 
       if compare_exchange_save(license_code, 'was_redeemed', False, True): 
        # Deposit a license for the user with a 3rd party service. Raises an exception if it fails. 
        ... 
       else: 
        # License code already redeemed, don't deposit another license. 
        pass 
     except: 
      # Handle exception 
      ... 

答えて

1

は、クエリセットオブジェクトのupdate機能です。 1.8に入って来たケース/ - リンクは1.10のためのものであることをconditional updatesNOTE上のドキュメントをチェックアウト -

値に応じて、オブジェクトが場合は、ケースとの比較を行うことができます。

Fフィールドの値の参照に使用されるユーティリティもあります。私は私のモデルのモデルに値を更新する必要が

(Model.objects 
.filter(id=my_id) 
.update(field_to_be_updated=Case(
     When(my_field=True, then=Value(get_new_license_string()), 
     default=Value(''), 
     output_field=models.CharField()))) 

あなたがFオブジェクトを使用する必要がある場合は、ただで等号の右側にそれを参照たとえば

更新式

更新がtransaction.atomic()コンテキストマネージャを使用する必要はありませんが、他のデータベース操作を実行する必要がある場合は、transaction.atomic()

編集でそのコードをラップし続ける必要があります:あなたはまた、したいことがあり

をクエリーセットが実行されたときに行ロックを実装するクエリーセットselect_for_updateメソッドを使用してくださいdocs

+0

これはアトミックであることが保証されていますか?私はドキュメントでそれを見ません。そうでない場合は、私の使用例では、2つの異なる要求が「ライセンスを入金する」セクションに入ることが可能です。 – Danra

+0

これは単一のデータベース呼び出しです。それは可能な限り原子質です。 –

+0

@DanielRosemanは原子であるかどうか?つまり、PostgreSQLのバックエンドを想定して、このメソッドを同時に呼び出す2つの同時リクエストが、両方とも正常に値を更新することは可能ですか?それとも、最大で1つが成功することが保証されていますか? – Danra

関連する問題