2016-12-14 20 views
0

私はDjango Rest Frameworkを使用しています。存在しない場合はレコードを作成し、存在する場合は更新します。Django Rest Framework - update_or_createの使用方法

class MyModelList(generics.ListCreateAPIView): 
    queryset = MyModel.objects.all() 
    serializer_class = MyModeSerializer 
    permission_classes = (permissions.IsAuthenticated,) 

    def perform_create(self, serializer): 
     my_model, created = MyModel.objects.update_or_create(user_id=self.request.data['user_id'], 
                  defaults={ 
                   'reg_id': self.request.data['reg_id'] 
                  }) 

レコードが作成または更新された:私は何

。しかし、私はエラーが発生しています'OrderedDict' object has no attribute 'pk'

答えて

2

まず、これは悪い考えです.REST API標準を破っているからです。これは、POST経由での作成と、PUTとPATCHによる更新を想定しているからです。

しかし、これが正当な理由があるとすれば、perform_createは、作成後に呼び出され、モデルインスタンスを追加するときに行う必要がある他のものを追加するためのものです。より関連性の高いことは、createメソッドをオーバーライドして、必要に応じてオブジェクトを更新することです。

私はこのようにします。

class MyModelList(generics.ListCreateAPIView): 
    queryset = MyModel.objects.all() 
    serializer_class = MyModeSerializer 
    permission_classes = (permissions.IsAuthenticated,) 

    def create(self, request, *args, **kwargs): 
     mymodel=None 
     id=request.data.get("id") 
     if id: 
      mymodel=self.get_object(id) 

     if mymodel: 
      return self.update(request, *args, **kwargs) 
     else: 
      return self.create(request, *args, **kwargs) 
+0

これは、 'self.create'の中の' self.create'を参照しています... – YPCrumble

0

ありがとう@Bitonator。これは私の最終的な解決策である:

class MyModelList(generics.ListCreateAPIView): 
    queryset = MyModel.objects.all() 
    serializer_class = MyModeSerializer 
    permission_classes = (permissions.IsAuthenticated,) 

    def create(self, request, *args, **kwargs): 
     myMode, created = MyModel.objects.update_or_create(user_id=request.data['user_id'], 
                  defaults={ 
                  'reg_id': request.data['reg_id'] 
                  }) 

     # require context={'request': request} because i'm using HyperlinkModelSerializer 
     serializer = MyModelSerializer(myModel, data=request.data, context={'request': request}) 
     if serializer.is_valid(): 
      serializer.save() 

     if created: 
      return Response(serializer.data, status.HTTP_201_CREATED) 
     else: 
      return Response(serializer.data, status.HTTP_200_OK) 
+0

も動作します。私があなたのコードに見られる唯一の問題は、オブジェクトレベルの権限を尊重しないことです。詳細はhttp://www.django-rest-framework.org/api-guide/permissions/#object-level-permissionsを参照してください。 – Bitonator

0

私は、関連する議論のthis結論に同意し、PUT-として-アップサート実装します。ことを意味

def put(…):が同じようself.upsert(…)を呼ぶだろうがdef post(…):self.create(…)hereを呼び出します。

def upsert(…)thisと同様にself.perform_upsert(serializer)となります。

部分的な更新が必要な場合はここをクリックしてください。その場合は、sql-UPDATEchanged fieldsのみを使用することもできます。その他の合併症。

したがって、部分更新を行わない場合は、def perform_upsert(serializer):serializer.upsert()となります。

nested create、つまりリレーションを使用したい場合は別の問題が発生します。

おそらく、キーとして使用するフィールドを指定する必要があります。

たシリアライザは、次のようになります。

class MyModelSerializer(serializers.ModelSerializer): 

    … 

    _key_attrs = ('username',) # the effective primary key, such as auth_user's username. 

    def upsert(self): 
     assert not self.errors 
     validated_data = self.validated_data 
     effective_key = {key: validated_data.get(key) for key in self._key_attrs} 
     instance, _ = model.objects.update_or_create(defaults=validated_data, **effective_key) 
     return instance 

、あなたはもっと複雑なものが必要な場合は、あなたは正しく(そのfor updateロック付き)、トランザクションを管理するために、不要な避けるためにthe code of update_or_createを見てする必要がありますデータベースクエリ。

関連する問題