• 商品一覧
  • お問合せ
  • ブログ記事
お仕事の依頼
好かれるマーケティング研究室のデフォルトサムネイル画像

Djangoで問い合わせフォームを作る

2021-04-02
前回は、Djangoで単純な1ページだけを表示するアプリケーションを作成しました。
今回は、単純な静的なページではないページを作成して、もうちょっとDjangoを有効活用していきます。
問い合わせフォームを作成していきましょう。
もう少し具体的には、問い合わせページにアクセスしたら、そのページ内にあるフォームに情報を入力して送信すると、問い合わせのメールがあなた宛に届くようにしていきます。
Djangoでどうやって問い合わせ対応をするかみていきましょう!( ´▽`)♪

問い合わせ用のアプリケーションを作成する

まずは、問い合わせ用のアプリケーションを作成していきましょう。
Djangoのプロジェクトがあるディレクトリに移動し、以下のコマンドを入力することでアプリケーションを作成します。
python manage.py startapp inquiries
そして、まずはDjangoにこのアプリケーションを使うと伝えるために、settings.pyのINSTALLED_APPSにこのアプリを追加しましょう。
# skilla/settings.py
INSTALLED_APPS = [
  ...省略...
  'inquiries.apps.InquiriesConfig',
]
そして、静的ページを作った時のようにルーティングを設定しましょう。
# skilla/urls.pyに以下を追加

urlpatterns = [
  ...省略...
  path('inquiry/', include('inquiries.urls')),
]
# inquiriesアプリケーションのurls.pyに以下を追加

from django.urls import path
from . import views

app_name = 'inquiries'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
]
例えば、[www.skilla.com]というアドレスがあったとして、[www.skilla.com/inquiry/]というアドレスでこのinquiriesアプリケーションにアクセスできるようになりました。
しかし、まだ Viewを作成していないので、それも忘れずに設定しましょう。inquiriesアプリケーションのviews.pyに以下を追加します。
# inquiries/views.py
 
from django.views import generic

class IndexView(generic.TemplateView):
   template_name = "inquiries/index.html"
そして、静的ページと同じようにinquiriesアプリケーション内に、templatesフォルダ、inquiriesフォルダを作り、その中にindex.htmlを作っておきます。
# inquiries/templates/inquiries/index.html
 
This is inquiry page
ここまで作成したら、一度開発用サーバーを実行して、上の文章が表示されているか確認してみましょう。開発用サーバーを起動するには、以下のコマンドでしたね。
python manage.py runserver
エラーが発生しなかったら、ブラウザから以下のアドレスにアクセスしてみましょう。以下のように表示されれば成功です。
http://localhost:8000/inquiry/ Django 最初の問い合わせページ

問い合わせページを作成する

さて、ここからが新しく覚えていくところです。まずはViewを問い合わせに対応できるように変えていきます。
views.pyでは、以下のように書いていましたね。
# inquiries/views.py

from django.views import generic
 
class IndexView(generic.TemplateView):
  template_name = "inquiries/index.html"
これをフォームを使うように変更していきます。今回は、特殊なことをしないので、genericのFormViewをそのまま使うことができます。このクラスを継承することで、フォームのViewを簡単に書くことができます。
views.pyを以下のように変更しましょう。
# inquiries/views.py

from django.views import generic
from . import forms

class IndexView(generic.FormView):
  template_name = "inquiries/index.html"
  form_class = forms.InquiryForm
[InquiryForm]というクラスをform_classに設定することで、このViewで使用するフォームのフォーマットを設定できます。[InquiryForm]クラスはまだ実装していないので、このクラスを定義する必要があります。
inquiriesアプリケーション内に、forms.pyというファイルを追加します。そしてその中にフォームに必要な情報を追加していきます。
# inquiries/forms.py

from django import forms

class InquiryForm(forms.Form):
  name = forms.CharField(label='名前', max_length=30)
  email = forms.EmailField(label='メール')
  inquiry = forms.CharField(label='問い合わせ内容',widget=forms.Textarea)
   
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
とりあえず最低限必要な情報として、名前とメールアドレスと問い合わせ内容を記入できるようにしました。ここでforms.xxxFieldと設定している変数が、後で作成するテンプレートに表示されるフォームの項目になります。
今回はCharFieldとEmailFieldを使っていますが、他にも様々なFieldがあります。詳細は以下のドキュメントを確認してください。
次にこれらの情報を入力することができるフォームを、先ほどのindex.htmlに追加していきます。
# inquiries/index.html

<!DOCTYPE html>
<html>
 <header>
   <title>問い合わせページ</title>
 </header>
 <body>
   <form method="post">
     {% csrf_token %}
     {{ form.non_field_errors }}
     
     {% for field in form %}
       <div>
         <label for="{{ field.id_for_label }}">
           {{ field.label_tag }}
         </label>
         <div>
           {{ field }}
           {{ field.errors }}
         </div>
       </div>
     {% endfor %}
     <button type="submit">送信</button> 
   </form>
 <body>
</html>
HTMLのフォームを使うので、少しだけちゃんとしたhtml形式で作成しました。HTMLの詳細は省きますので、興味があれば調べてみてください。
ただし、普通のHTMLと違うところがあります。それが<body>内にある{}で囲まれている部分です。
このindex.htmlはhtmlファイルではありますが、同時にDjangoのテンプレートでもあります。テンプレートは前にも説明したように、ただの静的ファイルではなく、情報をつけたり変更したりできます。それを行っているのが{}で囲まれている部分なんですね。
何をしているか1つずつ説明していきます。
{% csrf_token %}
これは脆弱性対策の1つです。csrfはクロスサイトリクエストフォージェリ(cross site request forgery)という攻撃の略です。詳細については、ここでは触れませんが、Djangoではフォームの送信などでpostするときに、このトークンをつけていないとエラーが発生します。
とりあえず、フォームを使う時はこれを書いておけば、Djangoで勝手にセキュリティ対策をしてくれているということだけ覚えておいてください。
{{ form.non_field_errors }}]
{{ field.errors }}
​この2つの行はエラーを表示するコードです。フォームで入力をする時、入力ないように問題があると正常に送信することができません。
例えば、フォームでメールアドレスの欄を必須にするなど、なにか制約がある場合にエラーが発生します。エラー情報を表示できるようにしておくと、ユーザーがなにかミスをしてしまった時に、何を直したらいいかがすぐにわかるようになります。
field.errorsはField単位のエラーで、form.non_field_errorsはformのclean関数で検出できるエラーで、複数のFieldに関係するエラーを表示できます。
詳細は以下のページで確認できます。
{% for field in form %}
{% endfor %}
このコードは先ほど作成した[InquiryForm]の中にあるFieldの項目をforループで1つずつ取り出しています。InquiryFormには、name, email, inquiryの3つのFieldがありましたので、そのそれぞれに対して、この2行の間に書かれた内容が処理されます。
htmlで直接フォームを書いてもいいのですが、このようにしておくと変更が少し楽になります。InquiryFormでフォームの項目を変更したくなったら、InquiryFormを編集するだけで、index.htmlで表示する内容にも反映されます。変更箇所を少なくするとミスが少なくなるので素敵ですね。
{{ field }}
{{ field.label_tag }}
最後にfield自体の情報を処理するコードです。[field]はフォームのそのfieldを入力するテキストボックスを追加してくれます。[field.label_tag]は、InquiryFormで設定したlabelを表示してくれます。
ところで{{ }}と{% %}の違いはなんなのでしょうか?{{ }}は変数にアクセスする時に使います。そのまま何か情報を表示したいなら、こちらを使いましょう。ifやforなどなんらかの処理をする必要がある時は、{% %}を使いましょう。
これでフォームは完成です。以下のアドレスにアクセスしてフォームが正しく表示されるか確認してください。
後は、このフォームで"送信"ボタンを押した時にどんな処理をするか、Djangoに伝えるだけです。

メール送信処理を作成する

さて、現状この送信ボタンを押してもなにも起こりません。それでは面白くないので、ちゃんと動くようにしてあげましょう。
そのためには、まずviews.pyを変更します。
# inquiries/views.py

from django.views import generic
from . import form
from django.urls import reverse_lazy

class IndexView(generic.FormView):
  template_name = "inquiries/index.html"
  form_class = form.InquiryForm
  success_url = reverse_lazy('inquiries:index')

  def form_valid(self,form):
    form.send_email()
    return super().form_valid(form)    
[form_valid]関数はユーザーがフォームに入力して、その全ての入力値に問題がなかった場合に呼ばれる関数です。これは親クラスであるgeneric.FormViewで定義されている関数です。その関数をoverrideして、親クラスの[form_valid]関数の前にEメールを送る処理を追加しています。
[form_valid]関数が呼ばれた後、suceess_urlに設定したアドレスに自動的に遷移するようになっています。ここでは、reverse_lazy関数を使ってアドレスを伝えています。この関数を使うことで、アドレスを直接書かずに、urls.pyで設定した"app_name:name"の形式で指定することができます。
後は、このsend_emailでどのような内容のメールを送るかを設定すれば、フォームが完成します。send_email関数はforms.pyのInquiryFormクラスに追加します。もう少しなので頑張りましょう!
# inquiries/forms.py

from django.core.mail import EmailMessage

class InquiryForm(forms.Form):

  ...省略...
    
  def send_email(self):
    name = self.cleaned_data['name']
    email = self.cleaned_data['email']
    inquiry = self.cleaned_data['inquiry']
    
    message = EmailMessage(subject=name + "からの問い合わせ",
                            body=inquiry,
                            from_email=email,
                            to=["admin@skilla.com"],
                            cc=[email])
    message.send()
[send_email]関数はform.send_email()という形で呼び出しました。つまり、selfにはformが入っています。このformからデータを取り出しています。self.cleaned_data['name']というのがそうですね。
このcleaned_dataには、フォーム入力した際に、エラーが発生しなかった場合の値が入っています。['<field名>']のように指定するとそれぞれの値を取り出すことができます。
そして次に、EmailMessageを作成して、それをmessage.send()で送信しています。
そして次に、EmailMessageを作成して、それをmessage.send()で送信しています。
EmailMessage(...)を呼ぶことでメールを作成できます。subjectはメールの題名、bodyはメールの本文、from_emailはメールの送信元、toはメールの送信先、ccはメールのccです。toとccが配列になっているのは、toやccが複数ある場合があるからです。もし2人以上にメールを送る必要があれば、この配列に必要なメールアドレスを足していけばいいわけです。
最後にメールをいちいち確認するのは面倒なので、開発中は実際には送らないようにしておきましょう。settings.pyでEメールの送り方を設定できるので、Eメールは実際には送らずにコンソールに表示する設定にしておきましょう。skillaプロジェクトのsettings.pyを開いて、以下を書き込んでください。
# skilla/settings.py
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
書く場所はどこでも構いません。あなたのわかりやすい場所に書いておけば大丈夫です。
これで完成です。おめでとうございます!
それでは、Djangoの開発用サーバーを起動させて、このフォームに情報を入力して、メールがコンソールに表示されるか確認してみてください。問題なく動いていれば、開発用サーバーを起動させたコンソールに送られるEmailの情報が表示されます。
python manage.py runserver
http://localhost:8000/inquiry/ 入力内容(メールアドレスは適当です) Django 問い合わせ入力
結果(メールのSubjectが文字化けしているように見えますが、実際に送るときはちゃんと表示されます)
Django メール送信後のコンソール
これで問い合わせフォームの作成は完了です。おつかれさまでした!

サンプルサイト

repl.itにここまでに作成した内容を残しておきます。下のリンクにアクセスして、左側にあるCodeを選択すると、ファイル構成やファイルの内容を確認できます。

練習問題

  1. フォームにチェックボックスを追加してみましょう。
  2. 問い合わせページ(index.html)のテンプレートに{{ form }}と書くとどうなるでしょうか?
  3. あなたに仕事を依頼するためのフォームを新しく作成してみてください。

無料メルマガ

今すぐもっと好かれる!

プロフィール

西松 大輝:マーケティング・サイエンティスト

数字から愛へ
・「何を変えるか?」を行動経済学・TOCLSSで分析する。
・「何を伝えるか?」を戦略・マーケティングで明確にする。
・「何を測定するか?」を機械学習・ITで支援する。

"全部"やらなくっちゃあならないってのが 「マーケティング・サイエンティスト」のつらいところだな。
覚悟はいいか?僕はできてる
  • お仕事の依頼
  • お問合せ
  • プライパシーポリシー
  • 特定商取引法に基づく表記
2019-2022, 好かれるマーケティング研究室©