DjangoはPythonでWebアプリを作成する際によく使われるフレームワークです。パッと見返せるよう公式チュートリアルの大まかな流れをまとめました。
公式チュートリアル:
https://docs.djangoproject.com/ja/5.2/intro/tutorial01/
プロジェクトの作成
django-admin startproject mysite
サーバの起動
python manage.py runserver
アプリの作成
python manage.py startapp polls
アプリのURL
mysite/urls.py と mysite/polls/urls.py でURLを分割管理
from django.urls import path, include
urlpatterns = [
# ex: http://127.0.0.1:8000/polls/
path('polls/', include('polls.urls')),
, ...
]
from django.urls import path
from . import views
urlpatterns=[
# ex: /polls/
path("",views.index, name="index"),
]
アプリのView
上記、path()は以下の views.py の index() につないでいる。これにより、レスポンスが返ってくる。
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
アプリの追加
INSTALLED_APPS = [
'polls.apps.PollsConfig',
...,
]
管理者ユーザーの作成
python manage.py createsuperuser
データベースモデル
データベースモデルの作成。models.ForeignKeyにより他のデータベースと連携
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
データベースモデルの変更を反映
python manage.py makemigrations polls
データベースモデルの確認
sqlite3 db.splite3
sqlite3> .schema
データベースの更新
python manage.py migrate
データベースの確認
sqlite3> .tables
データベース API
python manage.py shell
from polls.models import Question, Choice
q=Question(question_text="Hello", pub_date=timezone.now())
q.save()
c=q.choice_set.create(choice_text='hoge', votes=0)
Question.objects.all()
q.choice_set.all()
Admin Page
python manage.py createsuperuser
admin.site.register(Question)
その後、http://127.0.0.1:8000/admin にブラウザでアクセス。ブラウザで Question を変更できる。
template
from django.shortcuts import render
from .models import Question
def index(request):
question_list=Question.objects.order_by("-pub_date")[:5]
context={
"latest_question_list":question_list,
}
return render(request, "polls/index.html", context)
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Raise 404 error
from django.http import Http404
from django.shortcuts import render
def detail(request, question_id):
try:
question=Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist!")
return render(request, "polls/detail.html", {"question": question})
省略形
from django.shortcuts import get_object_or_404
from django.shortcuts import render
def detail(request, question_id):
question=get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question": question})
Remove Hardcode URL
polls/urls.py で path() に name 引数を指定することで、テンプレート中からURLを逆引きできる
urlpatterns=[
... ,
# ex: /polls/5/
path("<int:question_id>/", views.detail, name='detail'),
... ,
]
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
URL Namespacing
polls/urls.py に app_name = 'polls'
を追加することで、どのアプリの views 関数か区別できるようになる。
app_name="polls"
urlpatterns=[
...
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
requestから値を受け取る
template のタグで name = "choice"、value = "{{choice.id}}" として、formを作成し、polls:voteに渡す。
<form action={% url 'polls:vote' question.id %} method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ question.question_text }}</h1></legend>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice"{{ forloop.counter }}
value={{choice.id}} >
<label for="chice"{{ forloop.counter }}>
{{choice.choice_text}}
</label>
<br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
method="post" で送信されているので、request.POST から値を取得する。request.POSTは辞書型のように扱うことができる。
def vote(request, question_id):
question=get_object_or_404(Question, pk=question_id)
try:
selected_choice=question.choice_set.get(pk=request.POST["choice"])
except (KeyError, Choice.DoesNotExist):
context={
"question": question,
"error_message": "You didn't select a choice!"
}
return render(request, "polls/detail.html", context)
else:
selected_choice.votes+=1
selected_choice.save()
response_url=reverse("polls:results", args=(question_id,))
return HttpResponseRedirect(response_url)
Generic View
generic.ListView と generic.DetailView を使う場合。
ListView では テンプレートに渡すオブジェクトリストを get_queryset
関数で定義している。また、テンプレート中での名前をcontext_object_name
で指定する。
DetailView は model
で使用するオブジェクトを指定する。context_object_name
は自動でモデルの名前から推定される(Question
→ question
)。
from django.views import generic
class IndexView(generic.ListView):
template_name="polls/index.html"
context_object_name="latest_question_list"
def get_queryset(self):
return Question.objects.order_by("-pub_date")[:5]
class DetailView(generic.DetailView):
model=Question
template_name="polls/detail.html"
class ResultsView(generic.DetailView):
model=Question
template_name="polls/results.html"
generic.DetailView は引数名 pk
(primary key) で引数を受け取るので、urls.py で pk
を指定する。また、クラスViewでは as_view()
を呼び出す。
urlpatterns=[
# ex: /polls/
path("",views.index, name="index"),
# ex: /polls/5/
path("<int:pk>/", views.DetailView.as_view(), name='detail'),
# ex: /polls/5/results/
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
# ex: /polls/5/votes/
path("<int:question_id>/vote/", views.vote, name="vote"),
]