概要
Django REST Framework(以下DRF)環境をVSCodeのDev Containerを使って構築しました。
コードを書く際に、デバッガーを起動させてブレークポイントで処理を止めてステップ実行できたほうが嬉しいのでそのあたりもまとめました。
前提
作業環境は以下になります。
- macOS Ventura バージョン13.2.1
VSCodeの拡張機能で以下を使用しています。
- Dev Containers
https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
手順
Dev ContainerでPythonコンテナを立ち上げる
今回はVSCodeの拡張機能のDev Containerを使ってコンテナを構築しました。
まず作業用のディレクトリをVSCodeで開き、画面左下の緑のボタンをクリックします。
エディタ上部に表示されるメニューからCreate Dev Containerをクリック
Pythonが動作することを確認するため、demo.py
ファイルを作成し適当なコードを書いてみます。
touch demo.py
example = 1
print(example)
ブレークポイントを設定してF5ボタンを押下し、デバッガーが起動することを確認します。
Pythonが動くことは確認できたので不要なファイルを削除します。
rm demo.py
コンテナにDRFをインストールする
PythonコンテナにDjangoとDRFをインストールします。
pip install django
pip install djangorestframework
もしくは以下のようなrequirements.txtを書いて、pip install -r requirements.txt
でも可能です。
Django~=3.1.7
djangorestframework~=3.11.1
ローカルサーバーを起動する
以下の手順は公式ドキュメントの「Tutorial 1: Serialization」内容を参考に行います。
https://www.django-rest-framework.org/tutorial/1-serialization/
django-adminコマンドで新規プロジェクトを作成します。
django-admin startproject tutorial
treeコマンドで以下のようなディレクトリとファイルが作成されていることが確認できます。
vscode ➜ /workspaces/python $ tree
.
└── tutorial
├── manage.py
└── tutorial
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
2 directories, 6 files
ローカルサーバーを起動する
以下のコマンドを実行します。
cd tutorial
python manage.py migrate
python manage.py runserver
以下、公式ドキュメントの内容に沿って新規appを作成しmodel、serializer、viewを作成します。
snippetsという名前で新規appを作成します。
python manage.py startapp snippets
tutorial/settings.py
のINSTALLED_APPS
に以下を追加。
INSTALLED_APPS = [
...
'rest_framework',
'snippets',
]
modelの定義で使うpygmentsをインストールしておきます。
pip install pygments
snippets/models.py
を以下の内容に編集します。
from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted([(item, item) for item in get_all_styles()])
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
class Meta:
ordering = ['created']
migrateを行います。
python manage.py makemigrations snippets
python manage.py migrate snippets
snippets/serializers.py
を作成し、以下の内容にします。
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ['id', 'title', 'code', 'linenos', 'language', 'style']
snippets/views.py
を以下の内容にします。
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
@csrf_exempt
def snippet_list(request):
"""
List all code snippets, or create a new snippet.
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return JsonResponse(serializer.data, safe=False)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors, status=400)
@csrf_exempt
def snippet_detail(request, pk):
"""
Retrieve, update or delete a code snippet.
"""
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return JsonResponse(serializer.data)
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = SnippetSerializer(snippet, data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data)
return JsonResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
snippet.delete()
return HttpResponse(status=204)
snippets/urls.py
を作成し、以下の内容にします。
from django.urls import path
from snippets import views
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>/', views.snippet_detail),
]
tutorial/urls.py
を以下の内容に編集します。
from django.urls import path, include
urlpatterns = [
path('', include('snippets.urls')),
]
Pythonのshellからデータを保存します。
python manage.py shell
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
snippet = Snippet(code='foo = "bar"\n')
snippet.save()
ローカルサーバーが起動している状態でcurlコマンドでhttpリクエストを送信して、レスポンスが返ってくることを確認します。
curl localhost:8000/snippets/
[{"id": 1, "title": "", "code": "foo = \"bar\"\n", "linenos": false, "language": "python", "style": "friendly"}]
ここまでで基本的な処理が動作することが確認できました。
デバッガーが起動するようにlaunch.jsonを作成
デバッガーメニューからcreate a launch.json fileをクリックします。
manage.pyへのパスを入力します。(今回で言うと${workspaceFolder}の次にturorialディレクトリがある)
Enterを押すと以下のlaunch.jsonが作成されます。
argsプロパティでDRFサーバーを起動するコマンドのrunserverが設定されています。
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Django",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/tutorial/manage.py",
"args": [
"runserver"
],
"django": true,
"justMyCode": true
}
]
}
curlコマンドでリクエストを投げます。
curl localhost:8000/snippets/
以上です。