Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

CSSとかのコツ

CSSって、ちゃんと勉強してないので、いまいち理解できてない。他の人が作ったhtmlファイルとか、cssファイルは読解が難しい気がする。

  • CSSの場合、classが重要なので、classをまず確認する。
  • そのclassが、どういう仕様になっているのか、コードの記載があるcssファイル(main.css)とかで確認する。
  • djangoに限って言えば、以下のようにstyleで囲んで新しいcss classを作成する。そのclassを追記すれば無理やり上書きできる。
<style>
{% block style %}
.btn-large {
    background-color: #00aeda;
}

.btn-blue {
    color: white;
    background-color:#00aeda;
}

.appIconBig{
 display: block;
 margin-left: auto;
 margin-right: auto;
 height: 75px;
 width: 75px;
}

.appIconS{
 padding: 0px;
 margin: 0px;
 height: 30px;
 width: 30px;
 vertical-align: middle;
}

.navbar-brand-small{
    padding:0px;
    margin:0px;
    vertical-align: middle;
}

@import 'https://fonts.googleapis.com/css?family=Dosis|PT+Sans';
.backimage-text{
    font-family:'PT Sans','Dosis', Avenir, "Open Sans", "游ゴシック", "Yu Gothic", Helvetica, sans-serif;
    /*font-weight: bolder;*/
}
{% endblock %}
</style>
  • cssを上書きするときに、ハイフォンでつないで、別のclassを追加するのはわかりやすいかもしれない。navbar-brandの場合は、navbar-brand-small とかいうふうに。

  • padding とmarginは大事。

  • padding 5 5 とかで、縦、横の設定が一気にできるので、楽。

  • padding-top, padding-bottom, padding-left, padding-right とかでも設定できる。

AngularJS1 + Django REST Frameworkに再挑戦 その12 Comment Reply Directive

概要

AngularJS1 + Django REST Frameworkに再挑戦 その12 Comment Reply Directive

参考動画

Django + AngularJS | Coding For Entrepreneurs

Reply to Comments part1

  • js/app/comment/comment.directive.js を作成する。
'use strict';

angular.module('core.comment').
    // Commentも読み込む
    directive('commentThread', function(Comment){
        return {
            restrict: "E",
            scope: {

            },
            template: "<ul><li>Reply</li></ul>",
            link: function(scope, element, attr){

            }
        }
    })
  • home.htmlに、<script src='{% static "js/app/core/comment/comment.directive.js" %}' ></script>に読み込ませる。

  • ここで1点ポイントは、comment.directive.jsの後に読み込ませる。なぜなら、comment.directive.js内の、Commentモジュールを継承したいため。

  • blog-detail.htmlに、<comment-thread></commentThread>を追記することで、commentThreadを利用できる。

  • 最終的に以下のようにcomment.directive.jsを修正する。

angular.module('core.comment').
    directive('commentReplyThread', function(Comment){
        return {
            restrict: "E",
            scope: {
                comment: '=comment',

            },
            template: "<ul ng-show='replies'><li ng-repeat='reply in replies'>{{ reply.content }}</li></ul>" + "<div class='text-center' ng-show='!replies'><img style='margin: 0 auto;' ng-src='/static/img/ring.gif' class='img-responsive'/><div>",
            // ng-src='/static/img/ring.gif'ここで、アニメーションがちょっと使える!
            // loading.ioという所のgifアニメを使うといいぽいな。
            link: function(scope, element, attr){
                if (scope.comment){
                    var commentId = scope.comment.id
                    if (commentId){
                        Comment.get({id: commentId}, function(data){
                            scope.replies = data.replies
                    })
                    }
                }
            }
        }
    })

Reply to Comments part2

  • blog-detailの一部を、comment.directive.jsのtemplateに埋め込む
'use strict';

angular.module('core.comment').
    directive('commentReplyThread', function(Comment){
        return {
            restrict: "E",
            scope: {
                comment: '=comment',

            },
            template: "<ul ng-show='replies'><li ng-repeat='reply in replies'>{{ reply.content }}</li></ul>" + "<div class='text-center' ng-show='!replies'><img style='margin: 0 auto;' ng-src='/static/img/ring.gif' class='img-responsive'/>" +
            "</div>" +
            "<p style='color:red;' ng-if='reply.content'>Preview: {{ reply.content }}</p>" +
            "<form ng-submit='addCommentReply(reply, comment)'>" +
            "<textarea class='form-control'  ng-model='reply.content'></textarea>" +
            "<input class='btn btn-default btn-sm' type='submit' value='Reply'/>" +
            "</form>",
            // ng-src='/static/img/ring.gif'ここで、アニメーションがちょっと使える!
            // loading.ioという所のgifアニメを使うといいぽいな。
            link: function(scope, element, attr){
                if (scope.comment){
                    var commentId = scope.comment.id
                    if (commentId){
                        Comment.get({id: commentId}, function(data){
                            scope.replies = data.replies
                    })
                    }
                }
            }
        }
    })
  • 一旦indexpageなどに直接コードをかく->angularのtemplateに一部埋め込む->angularのtemplateのhtmlを作成する という流れが一番わかりやすくてミスが少ないかもしれない。

AngularJS1 + Django REST Frameworkに再挑戦 その11 Reply to Comments

概要

AngularJS1 + Django REST Frameworkに再挑戦 その11 Reply to Comments

参考動画

Django + AngularJS | Coding For Entrepreneurs

Reply to Comments

  • コメントのreplyとかを表示したい。まずはcommentのcontextの内容を確認する。
<ul ng-show='comments.length > 0'>
    <li ng-repeat='comment in comments | filter: query'>
            {{ comment.content }} | Replies: {{ comment.reply_count }} | <a href='#' class='btn btn-sm btn-default' confirm-click='Do you want to delete this?' confirmed-click='deleteComment(comment)'>X</a>
    </li>
</ul>
  • さらにcommentの送信ボックスなどを作る。
<ul ng-show='comments.length > 0'>
    <li ng-repeat='comment in comments | filter: query'>
            {{ comment.content }}<br/>| <small>Replies: {{ comment.reply_count }} |<a href='#' class='' confirm-click='Do you want to delete this?' confirmed-click='deleteComment(comment)'>Remove</a></small>
            <br/>
            <div class='row'>
                <div class='col-sm-6'>
                    <p style='color:red;' ng-if='reply.content'>Preview: {{ reply.content }}</p>
                    <form ng-submit='addReply()'>
                        <textarea class='form-control'  ng-model='reply.content'></textarea>
                        <input class='btn btn-default btn-sm' type='submit' value='Reply'/>
                    </form>
                </div>
            </div>
        <div class='clearfix'></div>
        <br/>
        <br/>
    </li>
</ul>
  • commentのreplyのformに、parent_idが自動で入力されるようにする。
<form ng-submit='addReply()'>
    <input type='hidden' ng-model='reply.parent_id' value='{{ comment.id }}'>
    <textarea class='form-control'  ng-model='reply.content'></textarea>
    <input class='btn btn-default btn-sm' type='submit' value='Reply'/>
</form>
  • blog-detail.component.jsのaddReplyに追記してみる。
$scope.addReply = function() {
          console.log($scope.reply)
  • このままではうまく行かないので、addCommentReplyというfunctionをblog-detail.component.jsに追記する。
$scope.addCommentReply = function(reply, parentComment){
          console.log(reply)
          console.log(parentComment.id)
      }
      //これはとりあえず、replyの内容と、parentComment.idの内容をconsolelogに表示するだけ。
  • blog-detail.htmlに追記する。addCom
<form ng-submit='addCommentReply(reply, comment)'>
    <textarea class='form-control'  ng-model='reply.content'></textarea>
    <input class='btn btn-default btn-sm' type='submit' value='Reply'/>
</form>
  • blog-detail.htmlに追記する。addNewCommentというfunctionに変更する。
<div class='row'>
        <div class='col-sm-6'>
            <p style='color:red;' ng-if='newComment.content'>Preview: {{ newComment.content }}</p>
            <form ng-submit='addNewComment()'>
                <textarea class='form-control'  ng-model='newComment.content'></textarea>
                <input class='btn btn-default' type='submit'/>
            </form>
        </div>
    </div>
  • blog-detail.component.jsにaddNewCommentを作成する。
$scope.addNewComment = function() {
          // console.log($scope.reply)
          Comment.create({
              content: $scope.newComment.content,
              slug: slug,
              type: "post"
              },
              function(data){
                  //console.log(data)
                  $scope.comments.push(data)
                  resetReply()
              }, function(e_data){
                  // error
                  console.log(e_data)
              })
      }

AngularJS1 + Django REST Frameworkに再挑戦 その10 ngResource Create & Delete

概要

AngularJS1 + Django REST Frameworkに再挑戦 その10 ngResource Create & Delete

参考動画

Django + AngularJS | Coding For Entrepreneurs

ngResource Create & Delete

  • ngResource を使って、commentをsave, deleteする機能を実装する。

  • blog-detail.component.jsを編集する。Commentのsave機能をつける。

...
Comment.save({
  //saveに必要な項目を代入する。
                    content: $scope.reply.content,
                    slug: slug,
                    type: "post"
                    },
  //ここからは、dataと、e_dataがある場合は、error_dataを表示するようなfunctionをセットしてある。
                    function(data){
                        // success
                        console.log(data)
                    }, function(e_data){
                        // error
                        console.log(e_data)
                    })
  • これで、commentをsaveする機能がついた。あとは、今までのcomment createのコードをコメントアウトする。
...
$scope.addReply = function() {
          console.log($scope.reply)
          var token = $cookies.get("token")
          if (token){
              Comment.save({
                          content: $scope.reply.content,
                          slug: slug,
                          type: "post"
                          },
                          function(data){
                              // success
                              console.log(data)
                          }, function(e_data){
                              // error
                              console.log(e_data)
                          })

              // var req = {
              //     method: "POST",
              //     url: 'http://127.0.0.1:8000/api/comments/create/',
              //     data:{
              //         content: $scope.reply.content,
              //         slug: slug,
              //         type: "post",
              //     },
              //     headers:{
              //         authorization: "JWT " + token
              //     }
              // }
              //
              // var requestAction = $http(req)
              //
              // requestAction.success(function(r_data, r_status, r_headers, r_config){
              //     $scope.comments.push($scope.reply)
              //     resetReply()
              // })
              // requestAction.error(function(e_data,e_status, e_headers, e_config){
              //     console.log(e_data)
              // })
              //
              // $scope.comments.push($scope.reply)
              // // $scope.post.comments.push("abc")
          } else {
...
  • Failed to load resource: the server responded with a status of 405 (Method Not Allowed)このままだとこのerrorが出てしまうので、ちょっと修正が必要。GETではなく、POSTでデータを送付する必要あり。

  • 全体を修正する。comment.service.jsに、commentCreateメソッドを追加する。

'use strict';

angular.
    module('core.comment').
        factory('Comment', function($resource){
            // こちらのurlは、commentのurlにセットする。
            var url = '/api/comments/:id/'
            var commentQuery = {
                url: url,
                method: "GET",
                params: {},
                isArray: true,
                cache: false,
                transformResponse: function(data, headerGetter, status){
                    // console.log(data)
                    var finalData = angular.fromJson(data)
                    return finalData.results
                }

            }

            var commentGet = {
                method: "GET",
                params: {"id": "@id"},
                isArray: false,
                cache: false,
            }

            var commentCreate = {
                //こちらのurlは、djangoで設定したcommentsをcreateするurlを指定する。
                url: '/api/comments/create/',
                method: "POST",
                // params: {"id": "@id"},
                // isArray: false,
                // cache: false,
            }

            return $resource(url, {}, {
                query: commentQuery,
                get: commentGet,
                create: commentCreate,
            })

        });
  • headerのstatusText:"Unauthorized"というerrorが出て保存ができない!comment.service.js`で、コメントアウトしたところに、headerにauthorizationを入れるコードがあったと思うので、それを利用して、認証をする。
...
factory('Comment', function($cookies, $resource){
...
// cookiesからtokenをgetする。
var token = $cookies.get("token")
      if(token){
// headersにJWT tokenを代入する。
          commentCreate["headers"] = {"Authorization": "JWT " + token}
      }
  • これで一応は、登録ができるようになったけど、一度更新しないと、comment一覧に反映されないのがいまいち!なので、blog-detailページの処理を担当している、blog-detail.compose.jsを修正する。
if (token){
            Comment.create({
                        content: $scope.reply.content,
                        slug: slug,
                        type: "post"
                        },
                        function(data){
                            // success
                            //console.log(data)
                            //ここを追加する
                            $scope.comments.push(data)
                        }, function(e_data){
                            // error
                            console.log(e_data)
                        })
  • これでリアルタイムに反映されるようになった!

  • 次はdelete機能をつけていく。試しにblog-detail.component.jsに、シンプルなdelete機能を追記してみる。

$scope.deleteComment = function(comment) {
          comment.$delete()
          // $scope.$apply(
          //     $scope.comments.splice(comment, 1)
          // )
          // someResource.$delete()
      }
  • これで、deleteを試すと、405 (Method Not Allowed)が表示されてしまう。なので、createの時と同じように、comment.compose.jsに、commentDeleteメソッドを作成する。
...
var commentDelete = {
          // urlは、commentsのidを選択する。
          url: '/api/comments/:id/',
          // methodにDELETEを指定する。
          method: "DELETE",
          // params: {"id": "@id"},
          // isArray: false,
          // cache: false,
      }
...
    var token = $cookies.get("token")
        if(token){
          commentCreate["headers"] = {"Authorization": "JWT " + token}
          //ここを追記する。
          commentDelete["headers"] = {"Authorization": "JWT " + token}
        }

      return $resource(url, {}, {
          query: commentQuery,
          get: commentGet,
          create: commentCreate,
          delete: commentDelete
      })
  • これで試してみると、errorが表示されてしまう。どうも、comment_idが不明らしいということなので、deleteの際に、idを追記する。blog-detail.component.jsを修正する。
...
$scope.deleteComment = function(comment) {
          comment.$delete({"id": comment.id})
          // $scope.$apply(
          //     $scope.comments.splice(comment, 1)
          // )
          // someResource.$delete()
      }
...
  • これで一旦削除はできるようになった!次は、リアルタイムで画面から削除するコードを追記する。javascriptの、spliceメソッドを使う。多分これは、リストから指定した数の要素を削除するとかそういう意味だと思う。
$scope.deleteComment = function(comment) {
          comment.$delete({"id": comment.id},
          function(data){
              // success
              $scope.comments.splice(comment,1)
          }, function(e_data){
              // error
              console.log(e_data)
          })
  • 同じようにupdateReplyもaddReplyと似たような形で、実装できる。まずは、blog-detail.component.jsを修正する。
$scope.updateReply = function(comment) {
          Comment.update({
              "id": comment.id,
              content: $scope.reply.content,
              slug: slug,
              type: "post"
              },
              function(data){
                  //console.log(data)
                  //$scope.comments.push(data)
                  // resetReply()
              }, function(e_data){
                  // error
                  console.log(e_data)
              })
      }
  • 次に、comment.service.jsを修正する。
...
// まず、commentUpdateを作成する。
var commentUpdate = {
          url: '/api/comments/:id/',
          method: "PUT",
          // params: {"id": "@id"},
          // isArray: false,
          // cache: false,
      }
...
// 次に認証を作成する。
var token = $cookies.get("token")
      if(token){
          commentCreate["headers"] = {"Authorization": "JWT " + token}
          commentDelete["headers"] = {"Authorization": "JWT " + token}
          commentUpdate["headers"] = {"Authorization": "JWT " + token}
      }
...
// 最後にプロパティとして、登録する。
return $resource(url, {}, {
          query: commentQuery,
          get: commentGet,
          create: commentCreate,
          delete: commentDelete,
          update: commentUpdate,
      })
...
  • 結構ややこしいな。重要なのは、viewを修正することと、モデル(データ)を修正することは別々の機能として考えた方がわかりやすいということだね。

AngularJS1 + Django REST Frameworkに再挑戦 その9 Comment ngResource

概要

AngularJS1 + Django REST Frameworkに再挑戦 その9 Comment ngResource

参考動画

Django + AngularJS | Coding For Entrepreneurs

Comment ngResource

  • ngResource は、$httpを含んでおり、サーバとHTTP通信でデータのやりとりをするものなのかな。

  • core/post/post.module.jsのモジュール名を、post->core.post に名前を変更する(よりロバストにするため。)

  • core/comment フォルダを作成。

  • core/comment/comment.module.jsと、comment.service.jsを作成する。

  • comment.module.jsにコードを追記する。

'use strict';

angular.module('core.comment', []);
  • comment.service.jsを作成する。
'use strict';

angular.
    module('core.comment').
        factory('Comment', function($resource){
            var url = '/api/comments/'
            return $resource(url, {}, {
                query: {
                    method: "GET",
                    params: {},
                    isArray: true,
                    cache: false,
                    transformResponse: function(data, headerGetter, status){
                        // console.log(data)
                        var finalData = angular.fromJson(data)
                        return finalData.results
                    }
                    // interceptor
                },
                get: {
                    method: "GET",
                    params: {"slug": "@slug"},
                    isArray: false,
                    cache: false,
                }
            })

        });
  • まず、var url = '/api/comments/'に変更する。

  • commentのjsonデータをゲットするために、var commentQueryをセットする。

var commentQuery = {
          url: url,
          method: "GET",
          params: {},
          isArray: true,
          cache: false,
          transformResponse: function(data, headerGetter, status){
              // console.log(data)
              var finalData = angular.fromJson(data)
              return finalData.results
          }
  • 同様にvar commentGetをセットする。ここで注意すべきなのは、url + ":id/"としているところ。
var commentGet = {
          url: url + ":id/"
          method: "GET",
          params: {"id": "@id"},
          isArray: false,
          cache: false,
      }
  • 全体のデータのゲットは、commentQueryで、個別コメントのゲットは、commentGetでJSONデータを取得するのか。ということはcommentGetの方でもtransformResponseが必要になりそうだけど、どうなんだろうな。

  • 現在はcomment.service.jsは、以下のようなコードになっている。

'use strict';

angular.
    module('core.comment').
        factory('Comment', function($resource){
            var url = '/api/comments/'
            var commentQuery = {
                url: url,
                method: "GET",
                params: {},
                isArray: true,
                cache: false,
                transformResponse: function(data, headerGetter, status){
                    // console.log(data)
                    var finalData = angular.fromJson(data)
                    return finalData.results
                }

            }

            var commentGet = {
                url: url + ":id/"
                method: "GET",
                params: {"id": "@id"},
                isArray: false,
                cache: false,
            }

            return $resource(url, {}, {
                query: commentQuery,
                get: commentGet,
            })

        });
  • core.commentをblog-detail.component.jsに組み込んでみる。
...
angular.module('blogDetail').
    component('blogDetail', {
        templateUrl: '/api/templates/blog-detail.html',
        controller: function(Comment, Post, $cookies, $http, $location, $routeParams, $scope){
            var slug = $routeParams.slug
            Post.get({"slug": slug}, function(data){
                $scope.post = data
                // $scope.comments = data.comments
                // Commentをslugと、type(contenttype)で絞り込んでおく。
                Comment.query({"slug": slug, "type":"post"}, function(data){
                    $scope.comments = data
                })
            })
...

AngularJS1 + Django REST Frameworkに再挑戦 その8 Comment ListAPI View

概要

AngularJS1 + Django REST Frameworkに再挑戦 その8 Comment ListAPI View

参考動画

Django + AngularJS | Coding For Entrepreneurs

Comment ListAPI View

  • blog-detai.component.jsのaddReplyを少し修正する。
$scope.addReply = function() {
          console.log($scope.reply)
          var token = $cookies.get("token")
          if (token){
              var req = {
                  method: "POST",
                  url: 'http://127.0.0.1:8000/api/comments/create/',
                  data:{
                      content: $scope.reply.content,
                      slug: slug,
                      type: "post",
                  },
                  headers:{
                      authorization: "JWT " + token
                  }
              }
  • ただし、settings.pyのrest_framework.authentication.SessionAuthenticationコメントアウトしておかないと、なぜかcommentができない。
"DEFAULT_AUTHENTICATION_CLASSES": (
       # 'rest_framework.authentication.SessionAuthentication',
       'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
      #'rest_framework.authentication.BasicAuthentication'

  ),
  • CommentListAPIを修正する。
from django.contrib.contenttypes.models import ContentType
...
class CommentListAPIView(ListAPIView):
    serializer_class = CommentListSerializer
    permission_classes = [AllowAny]
    filter_backends= [SearchFilter, OrderingFilter]
    search_fields = ['content', 'user__first_name']
    pagination_class = PostPageNumberPagination #PageNumberPagination

    def get_queryset(self, *args, **kwargs):
        #queryset_list = super(PostListAPIView, self).get_queryset(*args, **kwargs)
        queryset_list = Comment.objects.filter(id__gte=0) #filter(user=self.request.user)
        query = self.request.GET.get("q")
        slug = self.request.GET.get("slug") # content we commented on
        type = self.request.GET.get("type", "post") # content type
        if slug:
            model_type          = type
            model_qs            = ContentType.objects.filter(model=model_type)
            if model_qs.exists():
                SomeModel           = model_qs.first().model_class()
                obj_qs              = SomeModel.objects.filter(slug=slug)
                if obj_qs.exists():
                    content_obj     = obj_qs.first()
                    queryset_list   = Comment.objects.filter_by_instance(content_obj)
        if query:
            queryset_list = queryset_list.filter(
                    Q(content__icontains=query)|
                    Q(user__first_name__icontains=query) |
                    Q(user__last_name__icontains=query)
                    ).distinct()
        return queryset_list
...
  • 何がしたいかというと、

    • postのdetailpageに表示されるslugを取得->postのinstanceを絞り込む->そのinstanceで、commentを絞り込む
    • content-typeが、postのqueryset(要は、slugでpostを絞り込む)
    • さらにその中から、postのinstanceで、コメントを絞り込む。このinstanceで絞り込むところが多分ポイント。
    • slugでそのまま絞り込んでも良さそうなきがするけど、ダメなのかな。
  • さらに修正する。queryset_list = []をセットすることと、slugがないときにelseで、空のリストを返すように設定してある。

class CommentListAPIView(ListAPIView):
...

    def get_queryset(self, *args, **kwargs):
        #queryset_list = super(PostListAPIView, self).get_queryset(*args, **kwargs)
        queryset_list = []
        query = self.request.GET.get("q")
        slug = self.request.GET.get("slug") # content we commented on
        type = self.request.GET.get("type", "post") # content type
        if slug:
            model_type          = type
            model_qs            = ContentType.objects.filter(model=model_type)
            if model_qs.exists():
                SomeModel           = model_qs.first().model_class()
                obj_qs              = SomeModel.objects.filter(slug=slug)
                if obj_qs.exists():
                    content_obj     = obj_qs.first()
                    queryset_list   = Comment.objects.filter_by_instance(content_obj)
        else:
            queryset_list = Comment.objects.filter(id__gte=0) #filter(user=self.request.user)

        if query:
            queryset_list = queryset_list.filter(
                    Q(content__icontains=query)|
                    Q(user__first_name__icontains=query) |
                    Q(user__last_name__icontains=query)
                    ).distinct()
        return queryset_list

AngularJS1 + Django REST Frameworkに再挑戦 その7 Comment Create API Endpoint & Serializer Context

概要

AngularJS1 + Django REST Frameworkに再挑戦 その7 Comment Create API Endpoint & Serializer Context

参考動画

Django + AngularJS | Coding For Entrepreneurs

Comment Create API Endpoint & Serializer Context

  • http://127.0.0.1:8000/api/comments/create/にアクセスして、apiを作成しようとしても、valid errorが表示されて、作成できない。なので、serializerを変更する。

  • comments/api/serializers.pyの、class CommentCreateSerializer(ModelSerializer):をコピペして独立させる。

  • 以下のように追記する。

from rest_framework import serializers
...
class CommentCreateSerializer(ModelSerializer):
    type = serializers.CharField(write_only=True) #Post
    slug = serializers.SlugField(write_only=True) #new-title
    parent_id = serializers.IntergerField(required=False) # comment自体が親になる可能性もあるため
...
  • def __init__の初期化メソッドの箇所は丸々削除する。

  • class Metaのfieldsを追記する。後、validate以下は一旦コメントアウトする。

fields = [
        'id',
        'content',
        'type',
        'slug',
        'parent_id',
        'timestamp',
    ]
  • まあ普通のserializerに戻したという感じで、ここから新たにserializerの機能を追加していく。

  • def validateを以下のように修正する。

def validate(self, data):
      model_type = data.get("type", "post")
      model_qs = ContentType.objects.filter(model=model_type)
      if not model_qs.exists() or model_qs.count() != 1:
          raise ValidationError("This is not a valid content type")
      SomeModel = model_qs.first().model_class()
      slug = data.get("slug")
      obj_qs = SomeModel.objects.filter(slug=slug)
      if not obj_qs.exists() or obj_qs.count() != 1:
          raise ValidationError("This is not a slug for this content type")
      parent_id = data.get("parent_id")
      if parent_id:
          parent_qs = Comment.objects.filter(id=parent_id)
          if not parent_qs.exists() or parent_qs.count() != 1:
              raise ValidationError("This is not a valid parent for this content")
      return data
  • def createも同じように、validated_dataを利用して、書き換える。
def create(self, validated_data):
      content = validated_data.get("content")
      if user:
          main_user = user
      else:
          main_user = User.objects.all().first()
      model_type      = validated_data.get("type", "post")
      slug            = validated_data.get("slug")
      parent_id       = validated_data.get("parent_id")
      parent_obj      = None
      if parent_id:
          parent_obj = Comment.objects.filter(id=parent_id).first()

      comment = Comment.objects.create_by_model_type(
              model_type, slug, content, main_user,
              parent_obj=parent_obj,
              )
      return comment
  • comments/api/views.pyのCommentCreateAPIViewを修正する。一旦シンプルな形に戻す。
class CommentCreateAPIView(CreateAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentCreateSerializer
  • CommentCreateAPIViewに、contextを追記する。(get_serializer_contextを上書きする)
class CommentCreateAPIView(CreateAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentCreateSerializer

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['user'] = self.request.user
        return context
  • なぜ、userをわざわざcontextで渡すかというと、CommentCreateSerializerの方で、使いたいらしい。
def create(self, validated_data):
      content         = validated_data.get("content")
      model_type      = validated_data.get("type", "post")
      slug            = validated_data.get("slug")
      parent_id       = validated_data.get("parent_id")
      parent_obj      = None
      if parent_id:
          parent_obj = Comment.objects.filter(id=parent_id).first()
      user            = self.context['user']
      comment = Comment.objects.create_by_model_type(
              model_type, slug, content, user,
              parent_obj=parent_obj,
              )
      return comment
  • ここまでセットしたら、http://127.0.0.1:8000/api/comments/create/でコメントを作成してみる。。。。無事表示された〜!