自動化無しに生活無し

WEB開発関係を中心に備忘録をまとめています

  • Django-channelsのAsyncWebsocketConsumerのscopeの内容【JWT認証+Sec-Websocket-Protocol】

    AsyncWebsocketConsumer の scope の内容は以下の通り。 ただし、JWT認証をしており、Sec-Websocket-Protocol を使用している。 { 'type': 'websocket', 'path': '/ws/chat/1/', 'raw_path': b'/ws/chat/1/', 'root_path': '', 'headers': [ (b'host', b'localhost:8000'), (b'user-agent', b'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0'), (b'accept', b'*/*'), (b'accept-language', b'ja,en-US;q=0.7,en;q=0.3'), (b'accept-encoding', b'gzip, deflate, br, zstd'), (b'sec-websocket-version', b'13'), (b'origin', b'http://localhost:3000'), (b'sec-websocket-protocol', b'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzM3MTg4NDg5LCJpYXQiOjE3MzcxODgzNDUsImp0aSI6IjI0OWRlMTUzMjY0YTQ4ZDE5YWVkZDJiODlhNTgwY2M5IiwidXNlcl9pZCI6MX0.hzS0uwx4LhPlM6wFJiIUpEkjVjkGpV87psw5MD1leyk'), (b'sec-websocket-extensions', b'permessage-deflate'), (b'sec-websocket-key', b'Q257WDS+ETm8KNLmj6cQiQ=='), (b'dnt', b'1'), (b'sec-gpc', b'1'), (b'connection', b'keep-alive, Upgrade'), (b'cookie', b'csrftoken=8ShA2y6HDOr794MF0TdrSnbEv76KCY0Y; _ga_HDX0LW64ZT=GS1.1.1737184513.53.1.1737184805.0.0.0;'), (b'sec-fetch-dest', b'empty'), (b'sec-fetch-mode', b'websocket'), (b'sec-fetch-site', b'same-site'), (b'pragma', b'no-cache'), (b'cache-control', b'no-cache'), (b'upgrade', b'websocket') ], 'query_string': b'', 'client': ['127.0.0.1', 35492], 'server': ['127.0.0.1', 8000], 'subprotocols': ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzM3MTg4NDg5LCJpYXQiOjE3MzcxODgzNDUsImp0aSI6IjI0OWRlMTUzMjY0YTQ4ZDE5YWVkZDJiODlhNTgwY2M5IiwidXNlcl9pZCI6MX0.hzS0uwx4LhPlM6wFJiIUpEkjVjkGpV87psw5MD1leyk'], 'asgi': {'version': '3.0'}, 'user': <User: asahina>, 'path_remaining': '', 'url_route': {'args': (), 'kwargs': {'room_name': '1'}} } ユーザーエージェントやCookieのデータも含まれる。 今回、ミドルウェアなどで操作しているため、状況によっ ...
  • DRF+ReactのCRUD簡易掲示板SPAでJWT認証を実装する

    DRF+ReactのSPAでCRUD簡易掲示板をつくる このDRF+ReactのCRUD簡易掲示板SPAに、JWT認証を実装する。 なぜなら、JWT認証を実装しない場合、通常のDjangoのセッションベースの認証を実装する場合では、CSRF検証が必要になるから。 開発要件 JWT認証を実装する( CSRF検証の廃止 ) ログイン、ログアウト、トークンの更新、アカウント新規作成の機能 ユーザー名とパスワードを使用し ...
  • DRF+ReactのSPAでWebsocketのチャットサイトをつくる

    タイトル通り、Django REST FrameworkとReactのSPAで、WebSocketを使ったチャットサイトを作った。 以前のWebSocket搭載チャットサイト(下記)はReactを使っていないため、SPAではない。今回はReactを搭載したSPAとしている。 DjangoでWebSocketを使って、チャットサイトを作る ただし、今回はJWT認証の実装は見送った。理由は後述。 開発要件 WebSock ...
  • DRFでModelViewSetの動的ルーティング(URL内引数)を作る

    例えば、ModelViewSetが以下のような場合 from rest_framework import viewsets from .models import Category,Topic,Reply from .serializers import CategorySerializer,TopicSerializer,ReplySerializer class CategoryView(viewsets.ModelViewSet): serializer_class = CategorySerializer queryset = Category.objects.all() class TopicView(viewsets.ModelViewSet): serializer_class = TopicSerializer queryset = Topic.objects.all() class ReplyView(viewsets.ModelViewSet): serializer_class = ReplySerializer queryset = Reply.objects.all() ルーティングは、このように DefaultRouter を使うと良い。 from django.contrib import admin from django.urls import path,include from rest_framework import routers from bbs import views router = routers.DefaultRouter() router.register(r"topics", views.TopicView, "topic") router.register(r"categories", views.CategoryView, "category") router.register(r"replies", views.ReplyView, "reply") urlpatterns = [ path('admin/', admin.site.urls), path('api/', include(router.urls)), ] だが、これではTopicに紐付いていないReplyまで取得できてしまう。 そこで、 HTTP GET /api/replies/ でReplyを取得するのではなく、 HTTP GET /api/topics/1/replies/ このように動的ルーティング(URL引数 ...
  • DRF+ReactのSPAでCRUD簡易掲示板をつくる

    開発要件 DRF+ReactでSPA react-router-domでページURLの構築 簡易掲示板のCRUD機能 カテゴリ指定・追加機能 リプライ投稿機能 CSRF検証の挙動を確認するため、あえてJWT認証はオミット CRAではなくViteを使用 以前のものは、1対多には対応しておらず、CRAを利用していた。またページもない。 更に、axiosがコールバック地獄になっているので、そちらも修正した。 使用ライブラリ ...
  • DRFはいつCSRF検証をするのか?

    開発中、おかしなことが起こった。 これまでCSRFトークン無しで、PUTやDELETEメソッドが送信できていた。 だが、突然、同様の状況で403エラー(CSRF token missing)が起きた。 CSRFトークン無しでリクエストできていたものが、急に403エラーになりCSRF検証を行うようになった。 何故か? DRFのビューでは、CSRF検証が免除されている https://github.com/encode/django-rest-framework/blob/master/rest_framework/viewsets.py#L146 DRFのビューは、このように .as_view()の戻り ...
  • DateTimeFieldで、フォーマットを指定したserializers.pyを作る

    DateTimeFieldを含むモデルで、シリアライザをこう作ると from rest_framework import serializers from .models import Category,Todo class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ("id", "created_at", "name", "color") class TodoSerializer(serializers.ModelSerializer): category = CategorySerializer() class Meta: model = Todo fields = ("id", "category", "created_at", "content", "deadline", "is_done") このようにタイムゾーン表記になってしまう。 作成日: 2024-12-25T12:00:00+09:00 締切: 2024-12-25T12:00:00+09:00 年月日表記に修正をするには、serializers.pyでフォーマットを指定する。 from rest_framework import serializers from .models import Category,Todo class CategorySerializer(serializers.ModelSerializer): created_at = serializers.DateTimeField(format="%Y年%m月 ...
  • 1対多のモデル構造で、ネストしたserializers.pyを作る

    通常、 class Category(models.Model): name = models.CharField(max_length=100) class Todo(models.Model): title = models.CharField(max_length=200) category = models.ForeignKey(Category, on_delete=models.CASCADE) このモデル構造の場合、シリアライザはこうなる。 from rest_framework import serializers from .models import Todo, Category class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ['id', 'name'] class TodoSerializer(serializers.ModelSerializer): class Meta: model = Todo fields = ['id', 'title', 'category'] ただこれだと、フロントサイドで得られる、JSONは、 [ { "id": 1, "title": "Todo 1", "category": 1 }, { "id": 2, "title": "Todo 2", "category": 2 } ] このように、categoryのidのみであり、カテゴリ名を表示することはできない。 ネストしたSerializerを指定する。 そこで、このように、TodoSerial ...
  • Reactでaxiosを使ってリクエストをすると、2回送られる問題【React.StrictMode問題】

    index.js の root.render( <React.StrictMode> <App /> </React.StrictMode> ); を root.render( <App /> ); に直す。 補足 これは StrictMode が開発段階で動作チェックをするためにやっていること。 本番環境に移行した場合、2度実行されることはない。 そのため、放置していても問題はない。 参考元 https://stackoverflow.com/questions/73002902/api-getting-called-twice-in-react ...