Django Tutorial Part 8 -- データがない時に 404 のページを出すようにする
Tags: django
Published: 2022-04-17 14:24:01


## 何をするか

https://docs.djangoproject.com/en/4.0/intro/tutorial03/#raising-a-404-error

polls/views.py/detail で URL から渡された id のデータがない時に 404 のページを返すようにする。

## 現状存在しない id で　detail を見るとどうなるか

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eyh4bd84l6y6r84ow076.png)

```py
def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)
```

現状は、request として URL から渡された question_id をそのまま ページで表示することになっている

よって、存在しない id でもエラーが出ない。

---

## question id に基づく question と detail.html を読み込むようにする。

```py
def detail(request, question_id):
    question = Question.objects.get(pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})
```

ここから question_id に基づいてテーブルのレコードを取ってきて 
polls/template/polls/detail.html を読み込み、context として question を渡すようにする

```html
<h1>Question Detail</h1>
<h2>Question Text</h2>
{{ question }}
```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y2togz0oupuekd9bityw.png)

そしてファイルを作成すると、detail で id に基づいた question_text が読める。

---

## try except raise 無しで存在しない question_id にアクセスする


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h68kdic2r74b5h83dm4b.png)

これでは try except を書いていないので、データがない question_id 
にアクセスすると `DoesNotExist at /polls/5/` のエラーページが出てしまう

---

## Http404 を使って Question.DoesNotExist で 404 とエラーの詳細を表示する

```py
from django.http import HttpResponse, Http404

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})
```

Http404 のライブラリをインポートして
try に先ほどの処理を書いて
except で Question.DoesNotExist の条件で
Http404 と raise で
その Question のレコードがないと言うメッセージを返す。

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwex64anyb5yus1j5av4.png)

これでレコードがない question_id にアクセスすると
404 と表示して、詳細なエラーの原因を表示できるようになる。

ここに 404 Page として HTML も設定できるのだろうか？要検証


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/biqhabpjeyojwtdf7ha0.png)
  

GitHub の 404 は可愛い。

---

## get_object_or_404 を使って try except を省略して処理を書く。

https://docs.djangoproject.com/en/4.0/intro/tutorial03/#a-shortcut-get-object-or-404

```py
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
```

この正常と例外に分かれているコードを

```py
    question = get_object_or_404(Question, pk=question_id)
```

この一行で同じようにかける。

Question.DoesNotExist の条件や、Question does not exist のメッセージは詳しく指定できないが

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mhq5uqeaecfxcojogxuk.png)

> No Question matches the given query.

(question_id = 5 と言う) クエリにマッチした Question が見つからなかったと言うメッセージで返してくれる。

try と except で書いた方が丁寧で正確だと思うが、
手早く書くならこれでもありだと思った。

---

## まとめ

```py
def detail(request, question_id):
    question = Question.objects.get(pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})
```

TableName.objects.get でレコードを取ってくるときは、
中身がないと DoesNotExist のエラーがそのまま出る

try-except raise で 

```py
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
```

Http404 を使えば
条件に応じた例外処理とエラーメッセージで
404 のページが出せる。

```
    question = get_object_or_404(Question, pk=question_id)
```

get_object_or_404 を使うとレコードがなかったときに、
query にマッチしなかったと言うメッセージで 404 のページが出せる。