こんにちは、Shinonです。 現在、このポートフォリオサイトはDjangoを使って自作しているのですが、今後の運用(特にGoogle AdSenseの申請)を見据えて、サイト内に「お問い合わせフォーム」を実装しました。
Googleフォームなどを埋め込むのが一番簡単なのですが、せっかくならバックエンドの勉強も兼ねて、Djangoの機能を使ってゼロから構築してみることに。今回はその実装の流れと、デプロイ時に遭遇したエラーの解決策を書き残しておきます。
【1. データベースの設計(Model)】
まずは、送られてきたメッセージを保存するための箱を作ります。 models.pyにInquiryというモデルを定義しました。
class Inquiry(models.Model):
name = models.CharField("お名前", max_length=100)
email = models.EmailField("メールアドレス")
subject = models.CharField("件名", max_length=200)
message = models.TextField("お問い合わせ内容")
created_at = models.DateTimeField("送信日", auto_now_add=True)
これをadmin.pyに登録して、Djangoの管理画面から一覧で確認できるように設定しました。readonly_fieldsを使って、届いた内容を誤って書き換えてしまわないようにしたのがちょっとしたこだわりです。
【2. 入力フォームと処理(Form & View)】
次に、ユーザーが入力するためのフォームと、送信時の処理を書きます。 DjangoのModelFormを使えば、モデルの項目から自動でHTMLのフォームを作ってくれるので非常に便利でした。
views.pyでは、アクセスされた時(GET)は空のフォームを表示し、送信ボタンが押された時(POST)はデータを保存して、同じページにリダイレクト(二重送信防止)させるという、Webシステムの超基本とも言える処理を書いています。
【3. 遭遇したエラー:本番環境での「TemplateDoesNotExist」】
ローカルでの準備を終えて、Renderへデプロイを済ませた後、お問い合わせページにアクセスすると見事に500 Internal Server Errorの洗礼を受けました。
ログを確認すると、原因は TemplateDoesNotExist。 「contact.htmlが見つからない」とDjangoが怒っていました。
原因は、ディレクトリ(フォルダ)の階層指定の漏れでした。 他のページは templates/photos/ の中に綺麗に格納していたのに、今回新しく作った contact.html だけがディレクトリの指定から外れてしまっていたんです。
【解決策】
以下の2箇所に photos/ というパスを正確に書き足すことで無事に解決しました。
views.pyのレンダリング先
return render(request, 'photos/contact.html', {'form': form})contact.htmlのベース読み込み
{% extends 'photos/base.html' %}
ファイルの位置を整え、パスを正確に繋ぎ直して再度デプロイしたところ、無事にお問い合わせフォームが表示されました。送信テストを行い、管理画面にデータが届いた瞬間は、やっぱり嬉しいものですね。
【おわりに】
エラー画面が出た時は少し焦りましたが、ログから自力でフォルダ構成のズレを見抜けたのは、エンジニアとしての経験値が少し上がった気がします。ほとんどAIに任せきりなので、構造や仕組みの理解を努めていきたいです。
※この文章はAI geminiを用いて作成しています。