MawaLog

一日一日、楽しく生きる。技術と音楽が好き。

DRF::ひとつのapi.viewで複数のモデル操作の仕方(特にsave()について)

Django

Django

メリット

DRFは、Django単体と違って、views.py上にmodelを呼んできて、save()としただけではモデルを引っ張ってきて操作を手軽にできません。(delete()はできます)なので、例えばページビュー数をカウントして、別のモデルに記録させるという場合は、今から各やり方ならできるので便利です。Django単体とDRFの相違点は要するに、serializer でデータを全部やりとりするようにかませるとsave()も含めモデル操作ができるということです。実例を見た方が早いので下記記します

実例1(pkが同じモデルAとBを更新)

#api.views.py

# url: a/detail/1(=pk) を想定ください

class ArticleDetailAPIView(RetrieveAPIView):    
    permission_classes = [AllowAny]
    queryset = A.objects.all()
    serializer_class =ADetailSerializer
    lookup_field = 'pk'

    def get_object(self):
        try:
            instance = A.objects.get(id=self.kwargs['pk'])
            #↑とりあえずget_objectでオーバーライドしたものの、
            #返すクエリは同じなので下記のように揃えておく

            obj = B.objects.filter(id=self.kwargs['pk']).first() 
            #↑ここで別のモデルを呼び出す
            #ポイントは更新するにはQuerysetだとエラーがでるので
            #.first()をつけてBオブジェクト単体にしておくこと

            data = {'hoge_field': 'fuga'}
            #↑更新したい箇所だけjsonデータを作っておく

            update_serializer =BDetailSerializer(obj, data=data)
            #↑更新しないデータ=>obj,更新したい箇所のデータ=>dataに格納されている。
            #これをセーブしたいモデルに対応したシリアライザーを呼んできてserializedされた(正確な表現しらない・・・)
            #データを変数化。


            if update_serializer.is_valid(): #serializedされたデータがバリデーションTrueなら、
                update_serializer.save() #更新セーブ

        except:
            raise Http404

        return instance

実例2(モデルArticle内のPVフィールドを再帰的に更新)

#api.views.py
# url: article/detail/1(=pk) を想定ください


class ArticleDetailAPIView(RetrieveAPIView):    
    permission_classes = [AllowAny]
    queryset = Article.objects.all()
    serializer_class = ArticleDetailSerializer
    lookup_field = 'pk'

    def get_object(self):
        try:
            instance = Article.objects.get(id=self.kwargs['pk'])
            #↑とりあえずget_objectでオーバーライドしたものの、
            #返すクエリは同じなので下記のように揃えておく

            obj = Article.objects.filter(id=self.kwargs['pk']).first()
            #↑ここでPV数を反映させたいので、Articleのモデルを呼び出す
            #ポイントは更新するにはQuerysetだとエラーがでるので
            #.first()をつけてBオブジェクト単体にしておくこと

            now_pv_num = obj.pv_num + 1 #pv数を+1する
            data = {'pv_num': now_pv_num}
            #↑更新したい箇所(pv数)だけjsonデータを作っておく

            update_serializer = ArticleDetailSerializer(obj, data=data)
            #↑更新しないデータ=>obj,更新したい箇所のデータ=>dataに格納されている。
            #これをセーブしたいArticleモデルに対応したArticleシリアライザーを呼んできてserializedされた(正確な表現しらない・・・)
            #データを変数化。

            if update_serializer.is_valid():#serializedされたデータがバリデーションTrueなら、
                update_serializer.save()#更新セーブ

        except:
            raise Http404

        return instance

という感じで、DRF独特の書き方に慣れるといいと思われます^^

参考記事

'QuerySet' object has no attribute '_meta'このエラー解決はこれが役立ちました!

stackoverflow.com