Djangoで簡単なECサイトを作り、基本機能を確認する

Django
DjangoPython
0

この記事ではDjango Oscarを使って簡単なECサイトを作る方法を紹介する。
また、作ったECサイトについて、1つずつ機能を見ていき、どんな機能が実装されているのか、逆に何を追加で実装しないといけないのかを明らかにする。

スポンサーリンク

はじめに

目的

そもそもECサイトを作りたいと思った時に、作成方法の選択肢として

  • Amazonや楽天などのプラットフォームを利用する
  • Shopifyなどの有料のASPを利用する
  • DjangoなどのECサイトフレームワークを利用する
  • フルスクラッチで構築する

が挙げられる。
DjangoなどのECサイトフレームワークを利用する手法は比較的手間はかかるものの、手数料などのコストはかからない。
そこで、Djangoを使ってECサイトを構築し、どんな機能がモジュールとして提供されているのか確認する。

なお、本記事は大学院の授業で行われた課題の一部であり、学習の一環であるため商用レベルのECサイトは作らない。
商用レベルまで到達したい方は別記事(例えばこれ)を参照されたい。

環境

  • CentOS Linux release 8.1.1911
  • Python 3.6.8
  • pip 20.2.1
  • virtualenv 15.1.0
  • django 3.0.9
  • django-oscar 2.1
  • SQLite 3.26.0
  • MySQL 8.0.21

そもそもDjangoとはPythonで実装されたWebアプリケーションフレームワークである。
Instagramでも使われるなど、実用性が高い。(参考

その中でDjango OscarはECサイトを作るためのフレームワークであり、必要な機能を全てサポートしている。
Djangoには他にもECサイトを作るためのフレームワークが用意されているが、Django Oscarが最もメジャーであるようだ。(参考

データベースはSQLiteがデフォルトで対応している。
MySQLにも対応しているが、バグが生じたので使うのをやめた。(詳しくは後述)

スポンサーリンク

Django Oscarをインストールする

Pythonの仮想環境であるvirtualenv環境で必要なパッケージをインストールしていく。(Django公式に強く推奨されている)
まずはvirtualenvをインストールしておく。

$ dnf -y install python3-virtualenv

次にDjangoとDjango Oscarをインストール。

# venvという環境を作る。名前は何でも良い。
$ virtualenv venv
$ cd ~/venv

# venv環境を有効にする。
$ source bin/activate

# Django Oscarのインストール。Djangoも同時にインストールされる。
(venv)$ pip install django-oscar
...
# 一部抜けているパッケージがあったのでインストールする。
(venv)$ pip install sorl-thumbnail
...
(venv)$ pip freeze
...
django==3.0.8
django-oscar=2.1

# venv環境から抜ける。
(venv)$ deactivate

次にDjangoでサイトを作る。

$ cd ~/venv
$ source bin/activate

# mysiteという名前のサイトを作る。(名前は自由で後からでも変更可能)
(venv)$ django-admin startproject mysite
(venv)$ cd mysite

# データベース設定(デフォルトはSQLite)
(venv)$ python manage.py migrate

上の3つ目のコマンドで次のようなフォルダが出来ている。
最上位のmysite/はプロジェクトのフォルダであり、任意の名前に変更可能である。

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

次に、サイトにアクセスするために、mysite/settings.pyの以下の部分を編集する。

# 任意のホストからアクセス可能にする。指定する場合はカンマで区切る。
ALLOWED_HOSTS = ['*'] 

# ついでに以下の部分も変更する
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

サイトを立ち上げてみる。

(venv)$ python manage.py runserver 
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
August 06, 2020 - 15:26:07
Django version 3.0.8, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

内部ネットワークからアクセスする場合はhttp://127.0.0.1:8000/にアクセスすれば良い。
また、次のコマンドで外部からアクセスできる(はず)。(外部からアクセスしたい場合はポートのfirewall設定をする必要がある。)

(venv)$ which python
[pythonのパス]
(venv)$ sudo [pythonのパス] manage.py runserver 0.0.0.0:80
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
August 06, 2020 - 15:30:31
Django version 3.0.8, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:80/
Quit the server with CONTROL-C.

これで外部からhttp://[IPアドレス]にアクセスでき、次のように表示される。(こちらを参照)

データベースをMySQLに変更する

DjangoのデフォルトのデータベースはSQLite(MySQLより小規模で簡単)であり、前章では何も変更せず立ち上げた。
なんとなくMySQLに変更したかったので、その手順を記す。(下の補足にあるようにMySQL特有の問題が生じたため、結局使わなかった。)
MySQLのインストールの手順を説明するのは割愛。(こちらが参考になる。)

インストールと設定ができたら、データベースを作成する。

$ mysql -uroot -p[password]

mysql> create database db1;
Query OK, 1 row affected (0.06 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| db1                |
| sys                |
+--------------------+

mysql> exit

そのままでは使えないのでドライバを入れる。
Django推奨のドライバはmysqlclientであるため、これをインストールする。(参考
単純にpipでインストールしても謎のエラーが出るので、mysql-develをインストールしておく。(参考

(venv)$ sudo dnf install mysql-devel
...
(venv)$ pip install mysqlclient

次にmysite/settings.pyのDATABASESの記述を変更する。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db1', # 作成したデータベース名
        'USER': 'root', # ログインユーザー名
        'PASSWORD': 'password', # 自分で設定したパスワード
        'HOST': '',
        'PORT': '',
        'ATOMIC_REQUESTS': True, # トランザクションをリクエストに関連付けるために必要。Django Oscar推奨。
    }
}

最後にテーブルを作成し、完了。(あとでまた変更する)

(venv)$ python mysite/manage.py migrate
.....

補足

http://[IPアドレス]/dashboard/から商品カテゴリを追加しようとすると、OperationalError at /dashboard/catalogue/categories/create/ 1093 .. というエラーが表示される。

調べてみるとこれはDjangoではなくMySQLの問題であり、DjangoライブラリのSQL文を書き換える必要性を感じたので諦めた。

SQLiteやPostgreSQLを使うとこの問題は生じない。

最低限のECサイトを立ち上げる

Django Oscarを使ってECサイトを立ち上げるにはこちらのサイトが非常に参考になる。(以下はほとんどこのサイトの和訳である。)
バージョンによって少々異なるようなので、インストールしたバージョンとドキュメントのバージョンが一致することを確認しておきたい

まず、すでにあるmysite/settings.py追加で以下の部分を記述する

# このモジュールを追加でインポート
from oscar.defaults import *

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                # 次の4行を追加
                'oscar.apps.search.context_processors.search_form',
                'oscar.apps.checkout.context_processors.checkout',    
                'oscar.apps.communication.notifications.context_processors.notifications',     
                'oscar.core.context_processors.metadata',
            ],
        },
    },
]

INSTALLED_APPS = [
    ...
    # 以下の部分を追加
    'oscar.config.Shop',
    'oscar.apps.analytics.apps.AnalyticsConfig',
    'oscar.apps.checkout.apps.CheckoutConfig',
    'oscar.apps.address.apps.AddressConfig',
    'oscar.apps.shipping.apps.ShippingConfig',
    'oscar.apps.catalogue.apps.CatalogueConfig',
    'oscar.apps.catalogue.reviews.apps.CatalogueReviewsConfig',
    'oscar.apps.communication.apps.CommunicationConfig',
    'oscar.apps.partner.apps.PartnerConfig',
    'oscar.apps.basket.apps.BasketConfig',
    'oscar.apps.payment.apps.PaymentConfig',
    'oscar.apps.offer.apps.OfferConfig',
    'oscar.apps.order.apps.OrderConfig',
    'oscar.apps.customer.apps.CustomerConfig',
    'oscar.apps.search.apps.SearchConfig',
    'oscar.apps.voucher.apps.VoucherConfig',
    'oscar.apps.wishlists.apps.WishlistsConfig',
    'oscar.apps.dashboard.apps.DashboardConfig',
    'oscar.apps.dashboard.reports.apps.ReportsDashboardConfig',
    'oscar.apps.dashboard.users.apps.UsersDashboardConfig',
    'oscar.apps.dashboard.orders.apps.OrdersDashboardConfig',
    'oscar.apps.dashboard.catalogue.apps.CatalogueDashboardConfig',
    'oscar.apps.dashboard.offers.apps.OffersDashboardConfig',
    'oscar.apps.dashboard.partners.apps.PartnersDashboardConfig',
    'oscar.apps.dashboard.pages.apps.PagesDashboardConfig',
    'oscar.apps.dashboard.ranges.apps.RangesDashboardConfig',
    'oscar.apps.dashboard.reviews.apps.ReviewsDashboardConfig',
    'oscar.apps.dashboard.vouchers.apps.VouchersDashboardConfig',
    'oscar.apps.dashboard.communications.apps.CommunicationsDashboardConfig',
    'oscar.apps.dashboard.shipping.apps.ShippingDashboardConfig',

    # 3rd-party apps that oscar depends on
    'widget_tweaks',
    'haystack',
    'treebeard',
    'sorl.thumbnail',
    'django_tables2',
]

# 追加
SITE_ID = 1

MIDDLEWARE = (
    ...
    # 以下の部分を追加
    'oscar.apps.basket.middleware.BasketMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)

# 追加。メールアドレス認証に対応。
AUTHENTICATION_BACKENDS = (
    'oscar.apps.customer.auth_backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',
)

# 追加。検索エンジン。
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
    },
}

# 追加。日本円に対応。
OSCAR_DEFAULT_CURRENCY = 'JPY'
OSCAR_CURRENCY_FORMAT = '¤#,##0'

次に、mysite/urls.pyを以下のように変更する。

from django.apps import apps
from django.urls import include, path
from django.contrib import admin

urlpatterns = [
    path('i18n/', include('django.conf.urls.i18n')),

    # The Django admin is not officially supported; expect breakage.
    # Nonetheless, it's often useful for debugging.

    path('admin/', admin.site.urls),

    path('', include(apps.get_app_config('oscar').urls[0])),
]

次にsuperuserを作成する。管理者ページにログインする際に必要である。

# 管理者を作成(管理画面にログインするために必要)
(venv)$ python manage.py createsuperuser
Username (leave blank to use 'user1'): admin
Email address: [email protected] # メールアドレスを入力
Password: # パスワードを入力
Password (again): 
# This password is too common. パスワードが簡単過ぎると再入力を求められる
Superuser created successfully.

最後にデータベースを作成し、サイトを立ち上げる。

(venv)$ python manage.py migrate
(venv)$ python manage.py runserver

これで下のように商品がないショップが閲覧できるようになっている。

これで管理者として商品の出品や在庫の管理ができ、購入者として商品の閲覧や購入ができるようになっている。
他にもさまざまな機能がすでに実装されているので、次のセクションで見ていく。

機能を1つずつ見ていく

最低限のECサイトを作ることができたので、http://[IPアドレス]を開いた状態で、実装されている機能を1つずつ見ていき、必要があれば修正していく。

新規アカウント登録

以下の情報で新規アカウント登録を試してみる。

  • メールアドレス:[email protected]
  • パスワード:password2020
    • 数字だけの場合や簡単すぎる場合などは拒否される。
    • 確認で異なるパスワードを書いた場合もちゃんとチェックされる。

残念ながら、ConnectionRefusedError at /accounts/login/という表示がでる。
ちなみにmysite/settings.pyDEBUG = Trueとするとこのようなエラーメッセージが表示される。(デフォルトでTrueになっているはず。)

メールを送ろうとしていることに原因があるようである。
mysite/settings.pyに以下を追加する。

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

こうすることでエラーは発生せず、「ご登録ありがとうございます!」と表示される。
実際のメールアドレスにはメールは送られない。(本記事では実装しない。)

アカウント管理 ・ログイン

登録後のプロフィールのページにも次のような機能があることが分かる。

  • プロフィール
  • 注文履歴
  • アドレス帳(住所一覧)
    • ここで住所の追加が行える。
  • Eメール履歴
    • ログイン時のメールが残っていることが分かる。
  • 商品入荷通知
  • 通知
  • ほしい物リスト

パスワードの変更やプロフィールの編集・削除も可能である。

また、登録したアカウントを一旦ログアウトしても再度ログインできることが分かる。
複数のアカウントが登録されていても正しくログインできることが確認できる。

パスワードリセットはメール送信を実装していないためできない。
また、何度もログイン試行ができる仕様になっている。(つまり5分間停止とかは未実装。)

住所(国)の設定

プロフィールにある住所欄を見ると国の指定が必須であるのに選択肢がない。
そこで、国を設定できるようにする。
Oscarではpycountryパッケージのデータを解析できるコマンドがあるため、それを利用する。

(venv)$ pip install pycountry
...
(venv)$ python manage.py oscar_populate_countries 

これで249ヶ国の国を入力できるようになっている。
国内だけにしたい場合は、DBを立ち上げ次のようにする。

(venv)$ python manage.py dbshell
...
mysql> UPDATE address_country SET is_shipping_country = 0 WHERE printable_name != 'Japan';

こうすると、配送住所選択の時に日本がデフォルトになり、国名選択が出てこなくなる。
しかし、アカウントページの住所登録では国名選択が表示されたままである。

商品の管理

次は管理者側の機能を確認する。
http://[IPアドレス]/dashboard/にアクセスすると、ログイン画面が出ると思うので、作成したsuperuserのメールアドレスとパスワードでログインする。
これも何度もログイン試行ができる使用になっている。

superuserはスタッフ権限があるので、管理者ページにログインできるが、ユーザーアカウントではログインできないことも分かる。

ログインに成功するとダッシュボードを見ることができる。
ここで様々な商品や売上を管理することができる。
http://[IPアドレス]/admin/でも商品管理ができるが、ダッシュボードのほうがECサイトに特化した使いやすい管理ページとなっている。

商品の追加

まだ商品がない状態なので追加してみる。
ダッシュボードの上部にある「商品管理 -> 商品」をクリック。

新商品追加の欄があるが、商品タイプがないので「+選択」を押せない。
そこで「商品管理 -> 商品タイプ」をクリックし、商品タイプを新規追加する。
適当に「本」などの名称で追加しておく。

再度、新商品追加の欄に戻ると、「本」を選択できるようになっている。
「+選択」をクリックすると、新商品に関する様々な情報を入力できるようになっている。

  • 商品詳細
    • 商品名など
  • カテゴリ
  • 商品画像
  • 在庫と価格
  • バリエーション一覧
  • アップセリング

「カテゴリ」と「取引業者」を設定しないと保存できないようなので、まず「商品管理 -> カテゴリ」に移動する。
「フィクション」「学術書」などのカテゴリを作っておく。
次に「販売管理 -> 取引業者」に移動し、新規取引業者作成から新しく作っておく。

以上で、他に必要事項を入力すれば商品の新規追加ができることが確認でき、商品ページに追加されていることも確認できる。

しかし、画像を入れても保存されず、表示されない。
また、「在庫記録」が1になっていることも気になる。

商品の検索

http://[IPアドレス]/catalogue/に移動すると商品の検索ができるようになっている。
商品名と商品の説明から検索ワードにかかるものが表示されるようである。

関連度や値段によって並び替えもできることが確認できる。

カート

商品を購入するとき、カート機能がある。
つまりは購入を一旦保留し、あとでまとめて会計できるようにする機能である。

いくつか商品をカートに入れ中身を見ると、商品一覧と合計金額を見ることができる。
また、再度商品を見たり、削除、今は買わないを選択することができ、クーポンやセールの割引も反映させることができるようになっている。

クーポン

カートを見るとクーポンコードを入力できることが分かる。
まだクーポンが発行されていないので、適当な文字列を入力しても有効ではないと返ってくる。

管理者ページに戻るとクーポンを発行できることが分かる。
しかし、値引き対象にしている商品があるにも関わらず、クーポン発行の画面では値引き対象の製品の選択肢がないことに気付く。

これは商品グループを作成することで解決できた。
「商品管理 -> 商品グループ」から新規商品グループ作成をし、セール対象カテゴリに適当なカテゴリを追加する。

再びクーポン発行のページに戻ると、値引き対象の選択肢があることが確認できる。
これでクーポンを発行することができる。

値引きの仕方はパーセントだったり、定額だったりと様々なものを選択できる。

ユーザー側の購入画面に戻りクーポンを入力すると、正しく反映されることが確認できる。
また、条件と異なるクーポンを入力すると、「割引対象外」と表示される。

購入

カートの画面で注文確認画面に遷移すると、まず配送先住所を指定する画面が出てくる。
ログインしたアカウントで予め住所を登録していると、その住所が表示される。

次に配送方法の指定になっているが、飛ばされてしまう。
その次に決済になっているが、追加で実装する必要がある。(本記事ではしない)
「次へ」をクリックすると注文内容の確認が出てくるので、確認し注文完了となる。

アカウントのEメール履歴を見ると、注文の確認のメールが来ていることが分かる。

注文管理

購入が完了した後、http://[IPアドレス]/dashboard/を見ると、諸々の指標がちゃんと更新されていることが分かる。

しかし、購入された商品の「在庫記録」を見ると全て1になっている。
ユーザー側から商品を見るとちゃんと在庫が減っていて、在庫がないものは「在庫なし」と表示されている。

ほしい物リスト

ユーザー側から商品のページを見ると、ほしい物リストに追加できることが分かる。
ほしい物リストに名前を付け、その中に追加すると保存される。
保存したものは自分のアカウントページから閲覧できるようになっている。

ほしい物リストは個人で複数持つことができ、それぞれのリストに商品を保存することができる。

商品のレビュー

ユーザー側から商品のページを見ると、レビューを記入できることが分かる。
全て匿名での投稿になっている。

他のユーザーでログインすると、そのレビューを見ることができる。

セール

クーポンと似ているが、セールを行うことができる。
条件や割引率、期間などを設定することができる。

注文フロー

実際にはデフォルトで定義されていないが、注文フローを簡単に定義することができる。
mysite/settings.pyに以下を追加する。

OSCAR_INITIAL_ORDER_STATUS = 'Pending'
OSCAR_INITIAL_LINE_STATUS = 'Pending'
OSCAR_ORDER_STATUS_PIPELINE = {
    'Pending': ('Being processed', 'Cancelled',),
    'Being processed': ('Processed', 'Cancelled',),
    'Cancelled': (),
}

こうすることで管理者ページのダッシュボードから注文フローを確認することができる。
「キャンセルされた」という状態を設定することはできるが、ユーザー側から注文をキャンセルする機能は実装されていない。

実装されていないもの

以上で実装されている基本的な機能を記述してきた。
全ての機能を紹介することはできず、他にも細かい機能があることに注意されたい。

逆に実装されていない機能をまとめておく。
これらは追加で考える必要がある。

  • メール送信
    • これが原因でパスワードを忘れた場合の対処もできない。
  • セキュリティ
    • ログイン時など
  • 商品画像の保存・表示
  • 決済
  • 税金の計算
  • 管理者側からの在庫管理
  • 非匿名でのレビュー
  • 注文のキャンセル

終わりに

本記事では簡単なECサイトをDjango Oscarを使って構築する手順を紹介し、実装されている機能を1つずつ確認した。
多くの機能がモジュールとして用意されているため、最低限のECサイトは深く考えなければ非常に簡単に作成することができる。

しかし、実用的には必要だが実装されていない機能もあるので、それらを考えることには時間がかかりそうである。

スポンサーリンク
H-MEMO

コメント