メニュー

Expand
Rate this page:

Thanks for rating this page!

We are always striving to improve our documentation quality, and your feedback is valuable to us. How could this documentation serve you better?

PythonおよびDjangoを使用した予約リマインダー

Ready to implement SMS appointment reminders in your Django web application? We'll use the Twilio Python Helper Library and Twilio SMS API to push out reminders to our customers when appointments are near. Here's how it works at a high level:

  1. 管理者(ユーザー)は、将来の日時に対するアポイントメントを作成し、そのアポイントメント用に顧客の電話番号をデータベースに保存します。
  2. そのアポイントメントを保存すると、アポイントメントが開始する前にその顧客にリマインダーを送信するようにバックグラウンドタスクがスケジュールされます。
  3. アポイントメントより前の設定済み時間に、アポイントメントを思い出させるためにバックグラウンドタスクが SMS リマインダーを顧客に送信します。

Yelpが飲食店に対してレストランの予約確認に、いかにしてSMSを使用しているのか見てみましょう。

Appointment Reminder Building Blocks

使用するテクノロジーは以下のとおりです。

  • Django:データベースドリブンのウェブアプリケーションを作成します。
  • Messages Resource:Twilio の REST API からテキストメッセージを送信します。
  • Dramatiq to help us schedule and execute background tasks on a recurring basis

このチュートリアルの読み方

アポイントメントリマインダーを実装するために、アポイントメントリマインダーをウェブアプリケーションに完全に実装する方法を示した一連のユーザーストーリーに取り組みます。

各ストーリーをかなえるために必要なコードを一通り確認し、各ステップで何を追加する必要があるのかを説明します。

これはTwilioの助けを借りれば30分以内で完了できます。

はじめましょう!

Meet our Django Appointment Reminder Stack

We're building this app for Django 2.1 on Python 3.6. We're big fans of Two Scoops of Django and we will use many best practices outlined there.

In addition to Dramatiq, we will use a few other Python libraries to make our task easier:

  • twilio-python Python ヘルパーライブラリ
  • django-timezone-field:タイムゾーンを保存するためのモデルフィールドを提供します。
  • django-bootstrap3 および django-forms-bootstrap:フォームテンプレートをより単純で優れたものにします。
  • 非常に優れた arrow ライブラリ:日時計算を完全に信頼できるものにします。

We will also use PostgreSQL for our database and Redis as our Dramatiq message broker.

        
        
        
        
        requirements.txt

        Project dependencies

        requirements.txt

        Now that we have all our depenencies defined, we can get started with our first user story: creating a new appointment.

        アポイントメントの作成

        アポイントメントの作成

        ユーザーとして、名前、ゲスト電話番号、および将来の時間を使ってアポイントメントを作成します。

        自動アポイントメントリマインダーアプリケーションを構築するには、ほとんどの場合アポイントメントから始めます。このストーリーでは、システムで新しい Appointment を作成および保存するために、モデルオブジェクトと多少のユーザーインターフェイスを作成する必要があります。

        追加する必要があるのは、おおまかに以下のとおりです。

        • リマインダーを送信する場合に必要な情報を保存するための Appointment モデル
        • フォームをレンダリングしてそのフォームからの POST データを受け入れるためのビュー
        • アポイントメントに関する詳細を入力するための HTML フォーム

        Alright, so we know what we need to create a new appoinment. Now let's start by looking at the model, where we decide what information we want to store with the appointment.

        予約モデルを確認する

        アポイントメントモデル

        リマインダーを送信するために保存する必要がある各アポイントメントのデータは以下の 4 つのみです。

        • 顧客の名前
        • 顧客の電話番号
        • アポイントメントの日時
        • アポイントメントのタイムゾーン

        また、2 つの追加フィールド(task_idcreated)も含めました。task_id フィールドは、このアポイントメントに対応するリマインダータスクを追跡するのに役立ちます。created フィールドは、アポイントメントの作成時に入力されるタイムスタンプにすぎません。

        最後に、モデルのインスタンスをテキストとして表す方法を Django に伝えるように __str__ メソッドを定義しました。このメソッドは、プリマリーキーと顧客の名前を使用して、判読可能な表現のアポイントメントを作成します。

              
              
              
              
              reminders/models.py

              Appointment model fields

              reminders/models.py

              Our appointment model is now setup, the next step is writting a view for it.

              Check out the new Appointment view

              新規アポイントメントビュー

              Django により、開発者は関数またはクラスとしてビューを記述することができます。

              クラスベースのビューは、CRUD のような単純な機能をビューでサポートする必要がある場合に適しています(このアポイントメントプロジェクトに最適です)。

              新しい Appointment オブジェクトの作成用のビューを作るために、Django の汎用 CreateView クラスを使用します。

              指定する必要があるのは、ビューで使用するモデルとビューに含めるフィールドのみです。フォームを宣言する必要はありません。Django は、密かに ModelForm を使用します。

              成功メッセージ

              ビューは最初の 3 行のコードのみで機能する準備ができていますが、SuccessMessageMixin の追加によってそれを少し改善します。

              この mixin は、作成成功後にクラスの success_message プロパティを Django メッセージフレームワークに渡すようにビューに伝えます。それらのメッセージは、テンプレートでユーザーに表示します。

                    
                    
                    
                    
                    reminders/views.py

                    Create new Appointment

                    reminders/views.py

                    新しいアポイントメントを作成するためのビューができたので、新しい URL を URL ディスパッチャーに追加して、ユーザーがその URL に到達できるようにする必要があります。

                    Wiring up the URL with the view we just created

                    URL の接続

                    アポイントメント作成のユーザーストーリーをかなえるために、新しい URL を /new で作成し、それを AppointmentCreateView に向けます。

                    クラスベースのビューを使用しているため、単にビューの名前を使用するのではなく .as_view() メソッドを使ってビューを URL に渡します。

                          
                          
                          
                          
                          reminders/urls.py

                          With a view and a model in place, the last big piece we need to let our users create new appointments is the HTML form.

                          新規の予約フォームを確認する

                          新規アポイントメントフォーム

                          フォームテンプレートは、ベーステンプレートから継承されます。ベーステンプレートについては、templates/base.html を参照してください。

                          アプリケーションのフロントエンドに Bootstrap を使用しており、|as_bootstrap_horizontal テンプレートフィルターでフォームをレンダリングするために django-forms-bootstrap ライブラリを使用します。

                          このファイルに appointment_form.html という名前を付けると、AppointmentCreateView は応答のレンダリング時に自動的にこのテンプレートを使用します。テンプレートに別の名前を付ける場合は、ビュークラス上で template_name プロパティを追加することにより、その名前を指定できます。

                                
                                
                                
                                
                                templates/reminders/appointment_form.html

                                新規アポイントメントフォーム

                                templates/reminders/appointment_form.html

                                We are not leaving this form yet. Instead, let's take a closer look at one of its widgets: the datepicker.

                                Take a look at the datepicker widget

                                アポイントメントフォームの日付ピッカー

                                ユーザーがアポイントメントの日時を簡単に入力できるようにするために、JavaScript 日付ピッカーウィジェットを使用します。

                                このケースでは、bootstrap-datetimepicker が適合します。コンテンツ配信ネットワークから必要な CSS および JS ファイルを取り込み、小さなカスタム JavaScript を追加して、時間フィールドのフォーム入力上でウィジェットを初期化します。

                                      
                                      
                                      
                                      
                                      templates/reminders/appointment_form.html

                                      Datepicker widget

                                      templates/reminders/appointment_form.html

                                      Now let's go back to our Appointment model to see what happens after we successfully post this form.

                                      get_absolute_url メソッドの追加

                                      Add a get_absolute_url() Method

                                      新しいアポイントメントフォームでユーザーが「Submit」をクリックすると、入力は AppointmentCreateView によって受信されてから、Appointment モデルで指定したフィールドと突き合わせて検証されます。

                                      何も問題がない場合、Django は新しいアポイントメントをデータベースに保存します。次にユーザーをどこに送るのかを AppointmentCreateView に伝える必要があります。

                                      AppointmentCreateViewsuccess_url プロパティを指定できますが、デフォルトでは、Django の CreateView クラスは新規に作成されたオブジェクトの get_absolute_url メソッドを使用して、次にどこに行くのかを判断します。

                                      そのため、get_absolute_url メソッドを Appointment モデル上で定義します。このメソッドは、Django の reverse ユーティリティー関数を使用して、このアポイントメントの詳細ページに対する URL を作成します。そのテンプレートは、templates/reminders/appointment_detail.html で確認できます。

                                      これで、ユーザーはすべて新しいアポイントメントを作成するように設定されました。

                                            
                                            
                                            
                                            
                                            reminders/models.py

                                            get_absolute_url method

                                            reminders/models.py

                                            We are now able to create new appointments. Nex, let's quickly implement a few other basic features: listing, updating, and deleting appointments.

                                            See what we need to interact with appointments

                                            アポイントメントとのインタラクション

                                            ユーザーとして、今後のすべてのアポイントメントのリストを表示するとともに、 これらのアポイントメントを編集および削除できるようにします。

                                            大量のアポイントメントを扱う組織の場合は、おそらくそれらのアポイントメントを単一のインターフェイスで表示および管理できるようにしたいと考えるでしょう。このユーザーストーリーでは、それに取り組みます。以下の操作を行う UI を作成します。

                                            • すべてのアポイントメントを表示する
                                            • 個々のアポイントメントを編集する
                                            • Delete individual appointments

                                            これらは CRUD のような基本操作であるため、引き続き Django の汎用クラスベースのビューを使用して多くの労力を節約することにします。

                                                  
                                                  
                                                  
                                                  
                                                  reminders/views.py

                                                  We have the high level view of the task, so let's start with listing all the upcoming appointments.

                                                  Check out the view to list appointments

                                                  アポイントメントのリストの表示

                                                  Django の ListView クラスは、この目的のために作成されました。

                                                  All we need to do it's to point it at our Appointment model and it will handle building a QuerySet of all appointments for us.

                                                  また、このビューを reminders/urls.py モジュールで接続するのは、AppointmentCreateView と同様に簡単です。

                                                  from .views import AppointmentListView
                                                  
                                                  re_path(r'^$', AppointmentListView.as_view(), name='list_appointments'),
                                                  
                                                        
                                                        
                                                        
                                                        
                                                        reminders/views.py

                                                        List appointments

                                                        reminders/views.py

                                                        Our view is ready, now let's check out the template to display this list of appointments.

                                                        See the Appointment list template

                                                        アポイントメントリストテンプレート

                                                        AppointmentListView は、アポイントメントオブジェクトのリストを object_list 変数でテンプレートに渡します。

                                                        その変数が空の場合は、次回のアポイントメントがないことを示す <p> タグを含めます。

                                                        それ以外の場合は、リスト内のアポイントメントごとにテーブルに行を入力します。便利な get_absolute_url メソッドを再度使用して、各アポイントメントの詳細ページへのリンクを含めることができます。

                                                        また、{% url %} テンプレートタグを使用して、編集および削除ビューへのリンクを含めます。

                                                              
                                                              
                                                              
                                                              
                                                              templates/reminders/appointment_list.html

                                                              Render Appointment list

                                                              templates/reminders/appointment_list.html

                                                              And now that our appointment listing requirement is complete, let's see how we can use the new Appointment form to update exisiting appointments.

                                                              See how the new Appointment form can be used to update appointments

                                                              フォームテンプレートの微調整

                                                              Django の UpdateView は、アポイントメント更新用のビューの追加を容易にします。ただし、既存のアポイントメントから自動入力されたデータを処理するには、フォームテンプレートを少し微調整する必要があります。

                                                              Django は日時を秒単位まで正確に保存しますが、アポイントメントが始まる正確な秒の選択を強制することでユーザーに面倒をかけたくはありません。

                                                              この問題を修正するために、bootstrap-datetimepicker の extraFormats 設定オプションを使用します。

                                                              秒の入力をユーザーに求めない format 値と秒を含む日時を受け入れない extraFormat 値を使って日時ピッカーを設定することにより、Django が完全な日時をテンプレートに提供する際にフォームは適切に入力されます。

                                                                    
                                                                    
                                                                    
                                                                    
                                                                    templates/reminders/appointment_form.html

                                                                    Tweaking new Appointment form

                                                                    templates/reminders/appointment_form.html

                                                                    We now have everything to List, Create and Update an Appointment. All that is left is handle the Delete.

                                                                    DeleteView to the rescue

                                                                    削除ビュー

                                                                    DeleteView は、非常に便利なビュークラスであり、指定されたオブジェクトを削除する前に確認ページをユーザーに表示します。

                                                                    UpdateView と同様に、DeleteView は reminders/urls.py で宣言された pk パラメーターを URL で使用して、削除するオブジェクトを検索します。

                                                                    from .views import AppointmentDeleteView
                                                                    
                                                                    re_path(r'^/(?P[0-9]+)/delete$', AppointmentDeleteView.as_view(), name='delete_appointment'),
                                                                    

                                                                    ビュークラスでは success_url プロパティも指定する必要があります。このプロパティは、削除成功後にユーザーをどこに送るのかを Django に伝えます。このケースでは、URL にあるアポイントメントのリスト(list_appointments)にユーザーを戻します。

                                                                    Django プロジェクトは、実行を開始すると URLの前にビューを評価します。そのため、reverse_lazy ユーティリティー関数を使用して、reverse の代わりにアポイントメントリスト URL を取得する必要があります。

                                                                    デフォルトでは、AppointmentDeleteViewappointment_confirm_delete.html という名前のテンプレートを探します。このテンプレートは、templates/reminders ディレクトリで確認できます。

                                                                    また、それにより、このユーザーストーリーが完了します。

                                                                          
                                                                          
                                                                          
                                                                          
                                                                          reminders/views.py

                                                                          Import generic views

                                                                          reminders/views.py

                                                                          これで、ユーザーはアポイントメントの管理に必要なものをすべて手に入れました。他に実装する必要があるのは、リマインダーの送信のみです。

                                                                          Check out the requirements to send a reminder

                                                                          リマインダーの送信

                                                                          アポイントメントシステムとして、今後のアポイントメントの前に、任意の間隔で SMS を介して顧客に通知します。

                                                                          このユーザーストーリーをかなえるためには、個々のユーザーインタラクションとは無関係に単独でアプリケーションを非同期的に動作させる必要があります。

                                                                          One of the most popular Python library for asynchronous tasks is Dramatiq. To integrate Dramatiq with our application, we need to make a few changes:

                                                                          • Appointment オブジェクトからの情報を使用して SMS メッセージを送信する新しい関数を作成します。
                                                                          • Register that function as a task with Dramatiq so it can be executed asynchronously
                                                                          • Run a separate Dramatiq worker process alongside our Django application to call our SMS reminder function at the right time for each appointment

                                                                          If you're brand new to Dramatiq, you might want to skim its Introduction to Dramatiq page before proceeding.

                                                                                
                                                                                
                                                                                
                                                                                
                                                                                reminders/tasks.py

                                                                                Send SMS reminder task

                                                                                reminders/tasks.py

                                                                                Next we will configure Dramatiq to work with our project.

                                                                                Setting up Dramatiq

                                                                                Setting up Dramatiq

                                                                                Dramatiq and Django are both big Python projects, but they can work together easily.

                                                                                By following the instructions in the Dramatiq docs, we can include our Dramatiq settings in our Django settings modules. We can also write our Dramatiq tasks in tasks.py modules that live inside our Django apps, which keeps our project layout consistent and simple.

                                                                                To use Dramatiq, you also need a separate service to be your message broker. We used Redis for this project.

                                                                                The Dramatiq-specific settings in our common.py settings module is DRAMATIQ_BROKER.

                                                                                If you want to see all the steps to get Django, Dramatiq, Redis, and Postgres working on your machine check out the README for this project on GitHub.

                                                                                      
                                                                                      
                                                                                      
                                                                                      
                                                                                      appointments/settings/common.py

                                                                                      Dramatiq settings

                                                                                      appointments/settings/common.py

                                                                                      Now that Dramatiq is working with our project, it's time to write a new task for sending a customer an SMS message about their appointment.

                                                                                      Check how to create a new Dramatiq task

                                                                                      Creating a Dramatiq task

                                                                                      タスクは、アポイントメントの ID (プライマリキー)を唯一の引数として取ります。Appointment オブジェクト自体を引数として渡すことができますが、このベストプラクティスでは、SMS が最新バージョンのアポイントメントデータを使用することが保証されます。

                                                                                      タスクは、リマインダーの送信前にアポイントメントが削除されたかどうかをチェックする機会も提供します。リマインダーの送信は、関数の一番上で行います。この方法では、存在しなくなったアポイントメントに対する SMS リマインダーを送信しません。

                                                                                            
                                                                                            
                                                                                            
                                                                                            
                                                                                            reminders/tasks.py

                                                                                            Let's stay in our task a bit longer, because the next step is to compose the text of our SMS message.

                                                                                            See how to send an SMS with Twilio Python client

                                                                                            SMS メッセージの送信

                                                                                            便利な arrow ライブラリを使用してアポイントメントの時間をフォーマットします。その後、twilio-python ライブラリを使用してメッセージを送信します。

                                                                                            モジュールの一番上で Twilio REST クライアントをインスタンス化します。このクライアントは、TWILIO_ACCOUNT_SID および TWILIO_AUTH_TOKEN 環境変数を検索して自身を認証します。適正な値は、アカウントダッシュボードで見つけることができます。

                                                                                            Sending the SMS message itself is as easy as calling client.messages.create(), passing arguments for the body of the SMS message, the recipient's phone number, and the Twilio phone number you want to send this message from. Twilio will deliver the SMS message immediately.

                                                                                                  
                                                                                                  
                                                                                                  
                                                                                                  
                                                                                                  reminders/tasks.py

                                                                                                  Send SMS on Dramatiq task

                                                                                                  reminders/tasks.py

                                                                                                  send_sms_reminder タスクが完了したので、アポイントメントの作成時または更新時にそのタスクを呼び出す方法を見てみましょう。

                                                                                                  How do we call this task?

                                                                                                  リマインダータスクの呼び出し

                                                                                                  個々のアポイントメントに対するリマインダーをスケジュールできるようにするために、新しいメソッドを Appointment モデルに追加しました。

                                                                                                  このメソッドは、まず arrow を再度使用して、アポイントメントの time および time_zone で新しい日時を作成します。

                                                                                                  時間の逆行は、通常の Python では注意を要する場合がありますが、arrow の .replace() メソッドを使用すると、容易に appointment_time から分を減算することができます。REMINDER_TIME 設定のデフォルト値は 30 分です。

                                                                                                  We finish by invoking our Dramatiq task, using the delay parameter to tell Dramatiq when this task should execute.

                                                                                                  tasks.py モジュールは Appointment モデルをインポートするため、models.py モジュールの一番上で send_sms_reminder タスクをインポートすることはできません。schedule_reminder メソッドにインポートすると、循環依存の関係が回避されます。

                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        
                                                                                                        reminders/models.py

                                                                                                        Schedule a new Dramatiq task

                                                                                                        reminders/models.py

                                                                                                        最後に、Appointment オブジェクトが作成または更新されるたびに Django が schedule_reminder メソッドを呼び出すことを確認する必要があります。

                                                                                                        アポイントメントの save メソッドの無効化

                                                                                                        アポイントメントの save メソッドの無効化

                                                                                                        これを行うための最良の方法は、モデルの save メソッドを無効にすることです。これには、オブジェクトのプライマリキーが割り当てられた後の schedule_reminder の追加の呼び出しも含まれます。

                                                                                                        重複するリマインダーやタイミングを間違えたリマインダーの回避

                                                                                                        Scheduling a Dramatiq task every time an appointment is saved has an unfortunate side effect - our customers will receive duplicate reminders if an appointment was saved more than once. And those reminders could be sent at the wrong time if an appointment's time field was changed after its creation.

                                                                                                        To fix this, we keep track of each appointment's reminder task through the task_id field, which stores Dramatiq's unique identifier for each task.

                                                                                                        We then look for a previously scheduled task at the top of our custom save method and cancel it if present.

                                                                                                        これにより、正確に 1 つのリマインダーだけがデータベース内のアポイントメントごとに送信され、また、そのアポイントメントに指定された最新の time に送信されるようになります。

                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              
                                                                                                              reminders/models.py

                                                                                                              楽しいチュートリアルだったしょう? ここから先はどうしましょうか?

                                                                                                              関連トピック

                                                                                                              Finishing the Django Appointment Reminder Implementation

                                                                                                              単純な CRUD 操作を Appointment モデル上でサポートする機能を素早く構築できるようにするために、Django のクラスベースのビューを使用しました。

                                                                                                              We then integrated Dramatiq into our project and used the twilio-python helper library to send SMS reminders about our appointments asynchronously.

                                                                                                              You'll find instructions to run this project locally in its GitHub README.

                                                                                                                    
                                                                                                                    
                                                                                                                    
                                                                                                                    
                                                                                                                    reminders/models.py

                                                                                                                    アポイントメントモデル

                                                                                                                    reminders/models.py

                                                                                                                    次はどこでしょうか?

                                                                                                                    多少のコードとわずかな設定で、自動アポイントメントリマインダーをアプリケーションで起動できます。お疲れ様でした。

                                                                                                                    If you are a Python developer working with Twilio, you might want to check out other tutorials in Python:

                                                                                                                    Browser Call

                                                                                                                    ウェブページのボタンを押して、電話を介して訪問者をライブサポートまたはセールス担当者に接続します。

                                                                                                                    二要素認証

                                                                                                                    Improve the security of your Python app's login functionality by adding two-factor authentication via text message.

                                                                                                                    これは役に立ちましたか?

                                                                                                                    Thanks for checking out this tutorial! If you have any feedback to share with us, please reach out on Twitter... we'd love to hear your thoughts, and know what you're building!

                                                                                                                    Andrew Baker Agustin Camino David Prothero Kat King Hector Ortega Samuel Mendes Paul Kamp
                                                                                                                    Rate this page:

                                                                                                                    ヘルプが必要ですか?

                                                                                                                    誰しもが一度は考える「コーディングって難しい」。そんな時は、お問い合わせフォームから質問してください。 または、Stack Overflow でTwilioタグのついた情報から欲しいものを探してみましょう。