これは、Django、htmx、および Stripe を使用して 1 つの製品の電子商取引 Web サイトを作成する 2 部構成のシリーズの最初の部分です。このパートでは、Django プロジェクトを開始し、htmx と統合します。
後半では、Stripe で注文を処理します。
さあ、いきましょう!
次の理由から、Django、htmx、および Stripe を使用して Web サイトを作成します。
最終製品がどのように機能するかは次のとおりです:
次に、Django プロジェクトを構成し、初期ビューを作成し、htmx を使用して購入フォームを構築しましょう。
プロジェクトを設定するには、仮想環境を作成し、アクティブ化し、必要なパッケージをインストールする必要があります。その後、Django プロジェクトと Django アプリを作成できます。
依存関係を分離できるように、仮想環境を作成することから始めましょう:
python -m venv .venv
Linux/Mac でアクティブ化する方法は次のとおりです:
source .venv/bin/activate
Windows の場合:
.venv\Scripts\activate
アクティブ化された仮想環境内で、これを機能させるにはいくつかのパッケージが必要です。
pip install django stripe django-htmx python-dotenv
ここでは以下をインストールしました:
仮想環境と同じディレクトリに、ecommerce_site という Django プロジェクトを作成しましょう:
django-admin startproject ecommerce_site .
Django では、コードを 1 つ以上の「アプリ」ごとに編成することをお勧めします。各アプリは、特定のことを行うパッケージです。プロジェクトには複数のアプリを含めることができますが、この単純なショップの場合は、ほとんどのコード (電子商取引プラットフォームのビュー、フォーム、モデル) を含むアプリを 1 つだけ含めることができます。それを作成して、ecommerce と名付けましょう:
python manage.py startapp ecommerce
そして、このアプリを ecommerce_site/settings.py の INSTALLED_APPS に追加します:
# ecommerce_site/settings.py INSTALLED_APPS = [ # ... the default django apps "ecommerce", # ⬅️ new ]
このセットアップで問題が発生した場合は、最終製品を確認してください。この段階で、ファイル構造は次のようになります:
ecommerce_site/ ├── .venv/ # ⬅️ the virtual environment ├── ecommerce_site/ # ⬅️ the django project configuration │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── ecommerce/ # ⬅️ our app setup │ ├── templates/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ └── views.py └── manage.py
プロジェクトの構成が完了したので、いくつかの基本レイアウトを作成する必要があります。テンプレート ディレクトリに、base.html ファイルを追加します。これは、他のすべてのテンプレートが継承するテンプレートです。ユーザー操作用の htmx、基本的なスタイル設定用の mvp.css、および Django で生成されたメッセージをテンプレートに追加します。
<!-- ecommerce/templates/base.html --> <!DOCTYPE html> <html lang="en"> <head> <title>One-Product E-commerce Site</title> <!-- include htmx ⬇️ --> <script src="https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous" ></script> <!-- include mvp.css ⬇️ --> <link rel="stylesheet" href="https://unpkg.com/mvp.css" /> </head> <body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' hx-boost="true"> <header> <h1>One-Product E-commerce Site</h1> </header> <main> <section> {% if messages %} {% for message in messages %} <p><mark>{{ message }}</mark></p> {% endfor %} {% endif %} </section> {% block content %} {% endblock %} </main> </body> </html>
ホーム ビュー用に、同じ templates ディレクトリに home.html テンプレートを作成します。これは、base.html を拡張し、そのコンテンツ セクションを設定するだけです。
<!-- ecommerce/templates/home.html --> {% extends "base.html" %} {% block content %} <section>{% include "product.html" %}</section> {% endblock %}
このテンプレートには、product.html テンプレートが含まれています。 product.html は、製品に関する詳細とプレースホルダー画像を表示します。同じ templates ディレクトリに作成しましょう:
<!-- ecommerce/templates/product.html --> <form> <img src="https://picsum.photos/id/30/400/250" alt="mug" /> <h3>mug<sup>on sale!</sup></h3> <p>mugs are great - you can drink coffee on them!</p> <p><strong>5€</strong></p> <button type="submit" id="submit-btn">Buy</button> </form>
ecommerce/views.py で、ホーム テンプレートをレンダリングするビューを作成します。
# ecommerce/views.py from django.shortcuts import render def home(request): return render(request, 'home.html')
そして、それを ecommerce_site/urls.py の urlpatterns に追加します:
# ecommerce_site/urls.py from django.contrib import admin from django.urls import path from ecommerce import views # ⬅️ new urlpatterns = [ path("admin/", admin.site.urls), path("", views.home, name="home"), # ⬅️ new ]
これで、次のコマンドを使用してサーバーを実行できるようになります。
python manage.py runserver
ブラウザで http://127.0.0.1:8000 にジャンプすると、次のような内容が表示されるはずです。
It might feel like overkill to add a dedicated product.html template instead of just the product details in the home.html template, but product.html will be useful for the htmx integration.
Great! We now have a view that looks good. However, it doesn’t do much yet. We'll add a form and set up the logic to process our product purchase. Here’s what we want to do:
Let's go step by step.
Let’s first create and add a simple order form to our view allowing a user to select the number of mugs they want. In ecommerce/forms.py, add the following code:
# ecommerce/forms.py from django import forms class OrderForm(forms.Form): quantity = forms.IntegerField(min_value=1, max_value=10, initial=1)
In ecommerce/views.py, we can initialize the form in the home view:
# ecommerce/views.py from ecommerce.forms import OrderForm # ⬅️ new def home(request): form = OrderForm() # ⬅️ new - initialize the form return render(request, "home.html", {"form": form}) # ⬅️ new - pass the form to the template
And render it in the template:
<!-- ecommerce/templates/product.html --> <form method="post"> <!-- Same product details as before, hidden for simplicity --> <!-- render the form fields ⬇️ --> {{ form }} <!-- the same submit button as before ⬇️ --> <button type="submit" id="submit-btn">Buy</button> </form>
When the user clicks "Buy", we want to process the corresponding POST request in a dedicated view to separate the different logic of our application. We will use htmx to make this request. In the same ecommerce/templates/product.html template, let's extend the form attributes:
<!-- ecommerce/templates/product.html --> <!-- add the hx-post html attribute ⬇️ --> <form method="post" hx-post="{% url 'purchase' %}"> <!-- Same product details as before, hidden for simplicity --> {{ form }} <button type="submit" id="submit-btn">Buy</button> </form>
With this attribute, htmx will make a POST request to the purchase endpoint and stop the page from reloading completely. Now we just need to add the endpoint.
The purchase view can be relatively simple for now:
# ecommerce/views.py import time # ⬅️ new # new purchase POST request view ⬇️ @require_POST def purchase(request): form = OrderForm(request.POST) if form.is_valid(): quantity = form.cleaned_data["quantity"] # TODO - add stripe integration to process the order # for now, just wait for 2 seconds to simulate the processing time.sleep(2) return render(request, "product.html", {"form": form})
In this view, we validate the form, extract the quantity from the cleaned data, and simulate Stripe order processing. In the end, we return the same template (product.html). We also need to add the view to the urlpatterns:
# ecommerce_site/urls.py # ... same imports as before urlpatterns = [ path("admin/", admin.site.urls), path("", views.home, name="home"), path("purchase", views.purchase, name="purchase"), # ⬅️ new ]
We now need to tell htmx what to do with this response.
Htmx has a hx-swap attribute which replaces targeted content on the current page with a request's response.
In our case, since the purchase view returns the same template, we want to swap its main element — the