js n個の要素を持つ配列を作成する

jsで、1〜nの連番を持つ要素を作るときに スマートな書き方を教えてもらったのでメモ。

// Array.from()の連番の生成で素直に書いていたやつ
const range = Array.from(new Array(100)).map((v, i) => i + 1);
// こっちの方がちょっとだけ短く書ける
const better = [...Array(100)].map((v, i) => i + 1)

js 配列の中の特定のオブジェクトを上書き

[{ },{///},{ }]

   ↑条件に当てはまるこのオブジェクトだけ上書きしたい、という時

 const oldDataArray = [{id:"1", ☆},{id:"2",☆},{id:"3",☆}];
 const editedData = {id:"2",★};

  const newDataArray = Array.from(oldDataArray, data => {
    if (data.id === editedData.id) {
      return editedData;
    } else {
      return data;
    }
  });

console.log(newDataArray);

datatables ページを跨いでチェックボックスを操作する

  • datatablesで、ページを跨いでチェックボックスを操作する処理。
  • サーバー側ではなく画面側でページングしている場合。
var table=null;

    table = $("#result-table").DataTable({
  // 色々設定
  〜〜
        // 描画後にイベントを付与
        drawCallback: addCheckEvent
    });


var addCheckEvent = function () {

    // チェックボックス全体操作
        var checkboxs = table.$('.check_line') // $('.check_line')のみで指定すると1ページ分しか取得できない
        $(document).on('change', '#check_all', function(){
            for (var i = 0; i < checkboxs.length; i++) {
                table.$('.check_line').prop('checked', $('#check_all).prop('checked'));
            }
        });

    // 一つでもチェックが外れていたら全選択チェックを外す
    for (var checkbox of checkboxs) {
        checkbox.onclick = function () {
            for (var i = 0; i < checkboxs.length; i++) {
                if (checkboxs[i].checked == false) {
                    $('#check_all'').prop('checked', false);
                } else {
                    if (table.$('.check_line').filter(':checked').length == checkboxs.length) {
                        $('#check_all'').prop('checked', true);
                    }
                }
            }
        };
    };
}

datatables 再描画処理

困っていたこと

jQueryのdatatablesで、

  1. ajaxによるデータ取得とテーブル描画($("#table").find('tbody').append(tr_contents)で描画)とdatatablesへの変換を分離
  2. 「検索」ボタンでデータ再取得・テーブル再描画

ていう処理をしたいときに、datatablesの初期化がすんなりいかなかったのでメモ。

こうすると

var table = null;

  if (table) {
        // 二回目以降の描画の場合、初期化が必要
        $("#result-table tbody > tr").remove();
        table.state.clear();
    }

 // table描画処理

table = $("#result-table").DataTable({ 〜〜

テーブル自体の初期化は上手くいき、新たなデータでテーブルが作成されるが 「○件中X~X件を表示」の部分が初回の情報のまま更新されない。

var table = null;

  if (table) {
        // 二回目以降の描画の場合、初期化が必要
        $("#result-table tbody > tr").remove();
        table.state.clear();
        table.destroy();
    }

 // table描画処理
table = $("#result-table").DataTable({ 〜〜

table.destroy()を追加すると、件数情報は更新されるのだが テーブルが初期化されず、初回に描画したテーブルに新たな行がどんどん追加されてしまう。

解決

var table = null;

  if (table) {
        // 二回目以降の描画の場合、初期化が必要
        table.state.clear();
        table.destroy();
        $("#result-table tbody > tr").remove();  // $("#result-table tbody").empty();で良い
    }

 // table描画処理
table = $("#result-table").DataTable({ 〜〜

tbodyを空にする処理のタイミングを変えたら実現できた。 蓋を開けてみたらブログに書くほどのことでもないレベル!! でも下書きしてたので載せる。

Djangoをbeanstalk上にデプロイした時に認証が通らない

事象

リクエストのヘッダーにAuthorization情報を付けて、各APIに認証チェックを入れたい。 curlにすると以下のイメージ

curl -H "Authorization: JWT XXXXXXX" -G http://localhost:8000/api/piyo/getList?login_id=test@test.jp

ローカルではちゃんと認証が通ってレスポンスが返却されるが、
AWSにデプロイしたAPIに同じリクエストを送っても認証エラーになってしまう。

{"status":false,"errors":[{"error_id":"認証エラー"}]}

解決方法

python - Authentication credentials were not provided. when deployed to AWS - Stack Overflow

.ebextensions/django.configに対して、「container_commands:〜」以下のコマンドを追加する

option_settings:
  aws:elasticbeanstalk:container:python:
    WSGIPath: XXX_api/wsgi.py
  aws:elasticbeanstalk:application:environment:
    DJANGO_SETTINGS_MODULE:XXX_api.settings

container_commands: 
  01wsgipass:
    command: 'echo "WSGIPassAuthorization On" >> ../wsgi.conf'

認証が通るようになった!

"Usual issue with aws beanstalk"だそうで。AWSと仲良くなりたい・・・・

Django rest frameworkで認証エラー時のレスポンスをカスタマイズ

認証モデルのカスタマイズ方法はこちらを参考にさせて頂きました。
django-rest-framework-jwtの認証をカスタマイズする方法 - らっちゃいブログ

sampleView.py

class SampleView(APIView):
    
  permission_classes = (permissions.IsAuthenticated,) # 認証チェック
    
  def post(self, request, format=None):
   ~~

こんな感じでViewを定義するだけで

{"detail":"Incorrect authentication credentials."}

こういうレスポンスを返してくれる。優しい

でもこのレスポンスをこちらの仕様に合わせてカスタマイズしたい。
→ 認証エラー時のハンドルはAPIViewで行なっていたので、該当箇所をオーバーライドしてみた。

sampleAuth.py

from rest_framework_jwt.settings import api_settings
from rest_framework.views import APIView
from rest_framework.response import Response


class APIViewWithTokenCheck(APIView):
    ''' APIViewに対してエラーレスポンス返却処理をオーバーライド '''
    def handle_exception(self, exc):
        """
        Handle any exception that occurs, by returning an appropriate response,
        or re-raising the error.
        """
        if isinstance(exc, (exceptions.NotAuthenticated,
                            exceptions.AuthenticationFailed)):
            return Response(  #返却値をカスタマイズ
                data={
                'status': False,
                'error_code':'999_auth_error',
                },
                status=status.HTTP_401_UNAUTHORIZED)

        exception_handler = self.get_exception_handler()

        context = self.get_exception_handler_context()
        response = exception_handler(exc, context)

        if response is None:
            self.raise_uncaught_exception(exc)

        response.exception = True
        return response

これでレスポンスがカスタマイズされる。 {"status":false,"error_code":"999_auth_error"}

ベストなやり方かは不明…

DRF serializerで値の上書き

  • Django REST Frameworkで、serializerのis_valid()とsave()を使用してDBへの登録を実装する
  • table Aへの新規登録後に発行されるIDを使ってtable Bにインサートしたい
  • 先に全てのserializerに対してチェックを行ってから登録を実行したい
A_serializer = ASerializer(data=request_data)
if A_serializer.is_valid():
            return Response(
                        data={
                        'status': False,
                        'errors':A_serializer.errors,
                        },
                        status=status.HTTP_400_BAD_REQUEST)

request_data["id_for_b"] = None # request_dataからは空文字が渡される。設定先の変数はint型なのでエラーになるためNoneで上書き
B_serializer = BSerialiser(data=request_data)
if not B_serializer.is_valid():
             return Response(
                        data={
                        'status': False,
                        'errors':B_serializer.errors,
                        },
                        status=status.HTTP_400_BAD_REQUEST)

A_serializer.save()
# 発行されたIDで測定情報を登録 
B_serializer.validated_data["id_for_b"] = A_serializer.data["id"]
B_serializer.save()

validated_data["id_for_b"]で上書きできるというのがわからなかった・・・。