akiyoko blog

akiyoko の IT技術系ブログです

ゼロからはじめる Django で ECサイト構築(その2:Django Oscar の Sandbox サイト構築)

前回の記事「ゼロからはじめる Django で ECサイト構築(その1:ECパッケージの選定)」では、Django ベースの ECパッケージを選定し、「Django Oscar」が圧倒的人気で最有力候補であることが確認できました。


<過去記事>
akiyoko.hatenablog.jp


今回、「ゼロからはじめる Django で ECサイト構築」シリーズの第二回では、実際に、Django Oscar の Sandbox サイトを構築していくことにします。



f:id:akiyoko:20160531080056j:plain




 

Django Oscar について

概要

Django Oscar は、ECサイトを構築・運営するために必要な多くの機能が盛り込まれた、オープンソースで Django 製の ECパッケージです。ライセンスは修正BSDライセンス(New BSD license)で、商用利用も可能です。

github.com


機能の詳細については、次回以降にまとめていく予定です。


Sandbox とは

Sandbox とは、動作確認をするための開発者用のテスト環境のことを指します。
いわゆる「デモ環境」のことですね。

Django Oscar には、いろんな機能が組み込まれたデモサイトを簡単に立ち上げられるような仕組みが備わっていて、これを使うことで、Django Oscar の機能をお試しで検証することができます。




 

ECサイト構築に必要な三要素

さて、ECサイトを構築するためには、

  • 決済代行サービスのマーチャントアカウント
  • ECパッケージ
  • サーバ

の三つが必要最低限の要素として挙げられるでしょう。


まず一つ目の「決済代行サービスのマーチャントアカウント」は、PayPalWebPay などの決済代行サービスのビジネスアカウント(売り手アカウント)を指します。Sandbox 環境においては、Sandbox(ややこしいですが、決済代行サービス側が用意してくれるテスト環境を指します)用のマーチャントアカウントを使用することで、実際に支払いをすることなく決済処理の流れをシミュレートすることができます。


今回の検証では、決済代行サービスとして PayPal を利用するのですが、Sandbox については次のように説明されています。

ペイパルでは、決済サービスの動作確認ができるテスト環境として、Sandboxを公開しています。
テスト用の「Buyer(買い手)」アカウントと、「Seller(売り手)」アカウントを作成し、サービスの導入から、決済の流れまで、詳細にシミュレーションすることができます。


Sandbox | ペイパルビジネスガイド - PayPal


二つ目の ECパッケージについては、前回の選定で最有力候補となった「Django Oscar」を使用します。なお、決済モジュールには「django-oscar-paypal」を使用することとします。


三つ目のサーバについては、今回の Sandbox サイトでは仮想環境(Vagrant 上の Ubuntu 仮想マシン)を利用します。




 

Sandbox サイトの構築手順

ここから実際に、Django Oscar の Sandbox サイトを構築していきます(2016/5/28 バージョン)。


構築する環境は以下となります。

  • サーバ:Ubuntu 14.04TLS(on Vagrant)
  • Python 2.7.6
  • Django 1.9.6(現時点の最新バージョン)
  • ECパッケージ:Django Oscar 1.2+(現時点の最新バージョン)
  • 決済モジュール:django-oscar-paypal 0.9.7(現時点の最新バージョン)

 
以降、次のような手順で進めていきます。

 

1. サーバの初期設定

私は通常、PyCharm Professional Edition の

  • Vagrant 連携機能
  • サーバとのソースコード同期機能
  • リモートデバッグ機能

などの機能を利用するために、PyCharm を使っています。なので、いつもなら

  • PyCharm の設定
    • Pure Python Project を作成(空っぽのプロジェクトを作成)
    • Vagrant連携

という流れで、PyCharm から Ubuntu サーバを立ち上げています。


<過去記事>
akiyoko.hatenablog.jp


手動でやるなら、以下のコマンドを実行します。

$ cd ~/PycharmProjects/oscar_sandbox/
$ vagrant init ubuntu/trusty64

仮想マシンに固定 IPアドレスを付けるために、Vagrantfile を書き換えます。

  config.vm.network "private_network", ip: "192.168.33.105"

仮想マシンを起動します。

$ vagrant up


Vagrant サーバに ssh で乗り込みます。

$ ssh vagrant@192.168.33.105

 

1.1. 最低限のライブラリをインストール
$ sudo apt-get update
$ sudo apt-get -y install python-dev git tree

 

1.2. MySQL をインストール

Ubuntu サーバに MySQL をインストールします。

$ sudo apt-get -y install mysql-server
(root/rootpass)
$ sudo apt-get -y install mysql-client libmysqlclient-dev python-mysqldb

$ mysql --version
mysql  Ver 14.14 Distrib 5.5.49, for debian-linux-gnu (x86_64) using readline 6.3

$ sudo mysql_install_db

### 文字化け対策(セクションの最後に以下の設定を追加)
### http://blog.snowcait.info/2014/06/04/mariadb-utf8/
$ sudo vi /etc/mysql/my.cnf
---
[mysqld]
  ・
  ・
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem

# Character set settings
character-set-server = utf8

[mysqldump]
  ・
  ・
---

$ sudo service mysql restart

$ sudo mysql_secure_installation
Enter current password for root (enter for none):
Change the root password? [Y/n] n
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y


 

1.3. データベースを作成

データベース、データベースユーザを作成します。
なお、データベース名は Djangoプロジェクト名と合わせて myproject とします。

データベース名 myproject
データベースユーザ myprojectuser
データベースユーザパスワード myprojectuserpass
$ mysql -u root -p
mysql> create database myproject character set utf8;
mysql> create user myprojectuser@localhost identified by "myprojectuserpass";
mysql> grant all privileges on myproject.* to myprojectuser@localhost;
mysql> flush privileges;
mysql> exit


 

1.4. pip をインストール

Python 2.7.9 以降であれば pip がバンドルされているのですが、Ubuntu 14.04LTS では Python 2.7.6 が標準なので、手動でインストールします。

「sudo apt-get -y install python-pip」でインストールすると pip のバージョンが古いので、get-pip.py で最新版を入れることにします。

$ wget https://bootstrap.pypa.io/get-pip.py
$ sudo -H python get-pip.py
$ pip --version
pip 8.1.2 from /usr/local/lib/python2.7/dist-packages (python 2.7)


参考


 

1.5. virtualenv, virtualenvwrapper をインストール
### virtualenv, virtualenvwrapper をインストール
$ sudo -H pip install virtualenv virtualenvwrapper

### virtualenvwrapper の設定
$ cat << EOF >> ~/.bash_profile

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi
EOF
$ cat << EOF >> ~/.bashrc

source /usr/local/bin/virtualenvwrapper.sh
export WORKON_HOME=~/.virtualenvs
EOF
$ source ~/.bashrc


 

2. Sandbox サイト(Django Oscar)の作成

2.1. Django Oscar プロジェクトを構築

Setting up the development environment — django-oscar 1.3 documentation
に従って、Oscar プロジェクトのインストールをします。

### Djangoプロジェクトの virtualenv 環境を設定して activate
$ mkvirtualenv myproject

### /opt/webapps 配下にプロジェクトの外箱を作成
$ sudo mkdir -p /opt/webapps/myproject
$ sudo chown -R `whoami`. /opt/webapps

### JPEG Support
### http://django-oscar.readthedocs.org/en/latest/internals/contributing/development-environment.html#jpeg-support
$ sudo apt-get -y install libjpeg-dev libfreetype6-dev zlib1g-dev
### make sandbox をした後であれば ↓ を実行して Pillow を再インストール
### pip install --no-cache-dir -I pillow
### http://qiita.com/tototoshi/items/7b74fe26eb7bf39be7b5

### MySQLライブラリのインストール
###($ pip install MySQL-python でも OK)
$ pip install mysqlclient

### Oscar プロジェクトを作成
$ cd /opt/webapps/myproject/

### 通常であれば、django-admin.py startproject . とするところを、今回は clone -> make sandbox として Sanbox サイトを作成
### http://django-oscar.readthedocs.org/en/latest/internals/getting_started.html
$ git clone https://github.com/django-oscar/django-oscar.git .


ここで、

###$ git checkout 1.2

として、最新の stable バージョン (1.2) に合わせようとしましたが、make sandbox 実行時に、

django.db.utils.OperationalError: (2013, 'Lost connection to MySQL server during query')

というエラーになってしまったので、master のままで試すことにしました(2016/5/28 時点)。


ちなみに、現時点の最新コミットは以下の通りです。

commit 156a4b814d540bb1c6216b757cfa4441b36f8077
Merge: e1a8ea7 de633f8
Author: Michael van Tellingen
Date: Wed Apr 13 09:03:37 2016 +0200

Merge pull request #2030 from crgwbr/fix_broken_py3_migrations

Fix makemigrations in Python 3

 

### MySQL用の設定変更
$ vi sites/sandbox/settings.py
<変更前>
---
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': location('db.sqlite'),
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
        'ATOMIC_REQUESTS': True
    }
}
---
  ↓
<変更後>
---
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'myprojectuserpass',
        'HOST': 'localhost',
        'PORT': '',
        'ATOMIC_REQUESTS': True
    }
}
---

### Sandbox プロジェクトを作成
### プロジェクトのディレクトリ構造は
### myproject/ (as <repository_root>)
### └─ sites/sandbox/ (as <django_project_root> also as <configuration_root>)
$ make sandbox


ちなみに、make sandbox の処理はこのようになっています。

Makefile(抜粋)

install:
    pip install -e . -r requirements.txt

build_sandbox:
    # Remove media
    -rm -rf sites/sandbox/public/media/images
    -rm -rf sites/sandbox/public/media/cache
    -rm -rf sites/sandbox/public/static
    -rm -f sites/sandbox/db.sqlite
    # Create database
    sites/sandbox/manage.py migrate
    # Import some fixtures. Order is important as JSON fixtures include primary keys
    sites/sandbox/manage.py loaddata sites/sandbox/fixtures/child_products.json
    sites/sandbox/manage.py oscar_import_catalogue sites/sandbox/fixtures/*.csv
    sites/sandbox/manage.py oscar_import_catalogue_images sites/sandbox/fixtures/images.tar.gz
    sites/sandbox/manage.py oscar_populate_countries
    sites/sandbox/manage.py loaddata sites/_fixtures/pages.json sites/_fixtures/auth.json sites/_fixtures/ranges.json sites/_fixtures/offers.json
    sites/sandbox/manage.py loaddata sites/sandbox/fixtures/orders.json
    sites/sandbox/manage.py clear_index --noinput
    sites/sandbox/manage.py update_index catalogue

sandbox: install build_sandbox

 
Sandbox の作成が完了したら、作成状況を確認してみます。

$ pip list | grep Django
Django (1.9.6)

$ pip list | grep django-oscar
django-oscar (1.3.dev0, /opt/webapps/myproject/src)

$ pip freeze
alabaster==0.7.8
apipkg==1.4
Babel==2.3.4
beautifulsoup4==4.4.1
coverage==3.7.1
coveralls==0.4.4
decorator==4.0.9
Django==1.9.6
django-debug-toolbar==1.4
django-extensions==1.6.1
django-extra-views==0.6.4
django-haystack==2.4.1
-e git+https://github.com/django-oscar/django-oscar.git@156a4b814d540bb1c6216b757cfa4441b36f8077#egg=django_oscar
django-tables2==1.0.7
django-treebeard==4.0.1
django-webtest==1.7.8
django-widget-tweaks==1.4.1
docopt==0.6.2
docutils==0.12
execnet==1.4.1
factory-boy==2.6.1
fake-factory==0.5.7
flake8==2.5.1
flake8-blind-except==0.1.0
flake8-debugger==1.4.0
funcsigs==1.0.2
ipaddress==1.0.16
ipdb==0.8.1
ipython==4.0.1
ipython-genutils==0.1.0
isort==4.2.2
Jinja2==2.8
MarkupSafe==0.23
mccabe==0.3.1
mock==1.3.0
mysqlclient==1.3.7
nose==1.3.7
pathlib2==2.1.0
pbr==1.10.0
pep8==1.7.0
pexpect==4.1.0
phonenumbers==7.4.1
pickleshare==0.7.2
Pillow==2.7.0
pockets==0.3
ptyprocess==0.5.1
purl==1.3
py==1.4.31
pycountry==1.8
pyflakes==1.0.0
Pygments==2.1.3
pyprof2calltree==1.3.2
pysolr==3.2.0
pytest==2.8.5
pytest-cache==1.0
pytest-cov==2.2.0
pytest-django==2.9.1
pytest-xdist==1.13.1
python-dateutil==2.5.3
pytz==2016.4
PyYAML==3.11
requests==2.7.0
simplegeneric==0.8.1
six==1.10.0
snowballstemmer==1.2.1
sorl-thumbnail==12.4a1
spec==0.11.1
Sphinx==1.3.3
sphinx-rtd-theme==0.1.9
sphinxcontrib-napoleon==0.4.3
sqlparse==0.1.19
tox==1.8.1
traitlets==4.2.1
Unidecode==0.4.19
uWSGI==2.0.12
virtualenv==15.0.1
waitress==0.9.0
WebOb==1.6.1
WebTest==2.0.17
Werkzeug==0.9.6
whitenoise==2.0.6
Whoosh==2.6.0
$ find . -name "*.pyc" -exec rm -rf {} \;
$ tree -a /opt/webapps/myproject/ -I ".git|docs|tests" -L 3
/opt/webapps/myproject/
├── AUTHORS
├── CHANGELOG.rst
├── CONTRIBUTING.rst
├── .coveragerc
├── Dockerfile
├── .dockerignore
├── .gitignore
├── gulpfile.js
│   ├── index.js
│   └── tasks
│       ├── default.js
│       ├── less.js
│       └── watch.js
├── LICENSE
├── lint.sh
├── .mailmap
├── Makefile
├── MANIFEST.in
├── package.json
├── README.rst
├── requirements_migrations.txt
├── requirements.txt
├── runtests.py
├── sandbox.yml
├── setup.cfg
├── setup.py
├── sites
│   ├── _fixtures
│   │   ├── auth.json
│   │   ├── comms.json
│   │   ├── offers.json
│   │   ├── order-events.json
│   │   ├── pages.json
│   │   ├── promotions.json
│   │   ├── range-products.csv
│   │   └── ranges.json
│   ├── README.rst
│   └── sandbox
│       ├── apps
│       ├── deploy
│       ├── fixtures
│       ├── __init__.py
│       ├── logs
│       ├── manage.py
│       ├── public
│       ├── README.rst
│       ├── settings_mysql.py
│       ├── settings_postgres.py
│       ├── settings.py
│       ├── settings_sphinx.py
│       ├── static
│       ├── templates
│       ├── test_migrations.sh
│       ├── update_latest.sh
│       ├── urls.py
│       ├── whoosh_index
│       └── wsgi.py
├── src
│   ├── django_oscar.egg-info
│   │   ├── dependency_links.txt
│   │   ├── PKG-INFO
│   │   ├── requires.txt
│   │   ├── SOURCES.txt
│   │   └── top_level.txt
│   └── oscar
│       ├── app.py
│       ├── apps
│       ├── core
│       ├── defaults.py
│       ├── forms
│       ├── __init__.py
│       ├── locale
│       ├── management
│       ├── models
│       ├── profiling
│       ├── static
│       ├── templates
│       ├── templatetags
│       ├── test
│       └── views
├── tox.ini
├── transifex.sh
├── .travis.yml
└── .tx
    └── config

29 directories, 56 files

ここで一旦、データベースをバックアップしておきます。

### http://weblabo.oscasierra.net/mysql-mysqldump-01/
### ちなみに、リストアするときは mysql -u root -p myproject < ~/myproject_init.dump
$ mysqldump --single-transaction -u root -p myproject > ~/myproject_init.dump


 

2.2. Runserver で起動
$ python sites/sandbox/manage.py runserver 0.0.0.0:8000

でサーバを起動して、
http://192.168.33.105:8000/
にブラウザからアクセスします。

f:id:akiyoko:20160529121316p:plain


ログインユーザ

username: superuser
email: superuser@example.com
password: testing

username: staff
email: staff@example.com
password: testing

f:id:akiyoko:20160529121332p:plain

f:id:akiyoko:20160529121348p:plain


疎通ができたら、Runserver を一旦停止します。


ちなみにここまでの設定では、決済モジュールの設定をしていないので、決済処理を完了することができなくなっています。

f:id:akiyoko:20160529122316p:plain

(住所や電話番号などのダミー情報は、US Address Generator - Fake Address, Random Address Generator で生成したものを入力しました。)
f:id:akiyoko:20160529122334p:plain

f:id:akiyoko:20160529122349p:plain

このように、決済モジュール(payment gateway libraries)を設定してね、って怒られます。



以下、PyCharm を使う場合のメモです。PyCharm を使ってない方はすっ飛ばしてください。

  • PyCharm の設定
    • デプロイ先サーバ設定
    • ソースコードの同期
    • ローカル側でソースコードを Git管理
    • Project Interpreter の設定
    • Run/Debug設定(以下に詳細を記載)


Project ペインの manage.py ファイルで右クリック > [Create "manage"] を選択します。

Name manage
Script sites/sandbox/manage.py
Script parameters runserver 0.0.0.0:8000
Environment variables PYTHONUNBUFFERED=1(デフォルトのまま)
Python interpreter Project Default (Remote Python 2.7.6 Vagrant VM at ~/PycharmProjects/oscar_sandbox (/home/vagrant/.virtualenvs/myproject/bin/python))
Working directory /opt/webapps/myproject
Path mappings - Local path /Users/akiyoko/PycharmProjects/oscar_sandbox
Path mappings - Remote path /opt/webapps/myproject


ここで、「Add content roots to PYTHONPATH」と「Add source roots to PYTHONPATH」のチェックを外します。

f:id:akiyoko:20160529125100p:plain

要するに、Script のパスに気をつけてね、ってことです。



各種設定を確認

Sandbox サイトの settings.py を確認すると、以下のドキュメントに書かれている、既存サイトに追加する場合に追加する必要のある設定が全て追加されています。
http://django-oscar.readthedocs.org/en/latest/internals/getting_started.html


sites/sandbox/settings.py(抜粋)

    ・
    ・
SITE_ID = 1
    ・
    ・
TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.request",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.core.context_processors.static",
    "django.contrib.messages.context_processors.messages",
    # Oscar specific
    'oscar.apps.search.context_processors.search_form',
    'oscar.apps.promotions.context_processors.promotions',
    'oscar.apps.checkout.context_processors.checkout',
    'oscar.core.context_processors.metadata',
    'oscar.apps.customer.notifications.context_processors.notifications',
)

MIDDLEWARE_CLASSES = (
    'debug_toolbar.middleware.DebugToolbarMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
    # Allow languages to be selected
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    # Ensure a valid basket is added to the request instance for every request
    'oscar.apps.basket.middleware.BasketMiddleware',
    # Enable the ProfileMiddleware, then add ?cprofile to any
    # URL path to print out profile details
    #'oscar.profiling.middleware.ProfileMiddleware',
)
    ・
    ・
# Add another path to Oscar's templates.  This allows templates to be
# customised easily.
from oscar import OSCAR_MAIN_TEMPLATE_DIR
TEMPLATE_DIRS = (
    location('templates'),
    OSCAR_MAIN_TEMPLATE_DIR,
)
    ・
    ・
INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.admin',
    'django.contrib.flatpages',
    'django.contrib.staticfiles',
    'django.contrib.sitemaps',
    'django_extensions',
    # Debug toolbar + extensions
    'debug_toolbar',
    'apps.gateway',     # For allowing dashboard access
    'widget_tweaks',
]
from oscar import get_core_apps
INSTALLED_APPS = INSTALLED_APPS + get_core_apps()

# Add Oscar's custom auth backend so users can sign in using their email
# address.
AUTHENTICATION_BACKENDS = (
    'oscar.apps.customer.auth_backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',
)
    ・
    ・


INSTALLLED_APPS に

  • django.contrib.sites
  • django.contrib.flatpages

が追加されていて、MIDDLEWARE_CLASSES に

  • oscar.apps.basket.middleware.BasketMiddleware
  • django.contrib.flatpages.middleware.FlatpageFallbackMiddleware

が追加されていることが確認できます。



ちなみに、「TEMPLATE_CONTEXT_PROCESSORS」と「TEMPLATE_DIRS」を分けて記述している Sandbox の setteings.py の書き方は、Django 1.9 の書き方としては少し古いようですね。

Before Django 1.8 this setting was split between TEMPLATE_CONTEXT_PROCESSORS and TEMPLATE_DIRS.


http://django-oscar.readthedocs.org/en/latest/internals/getting_started.html



 

決済モジュールの導入手順

続けて、Django Oscar の Sandbox サイトに決済モジュールを組み込んでいきます。

決済代行サービスに「PayPal」を利用することを想定して、決済モジュールには「django-oscar-paypal」を選択することにします。


手順は以下の通りです。


参考
http://django-oscar-paypal.readthedocs.org/en/latest/


 

1. PayPal の Test API Credentials を取得

PayPal の決済モジュールを利用するには、「Test API Credentials」という PayPal の決済API を利用するための認証情報が必要となります。

「Test API Credentials」は、以下の 3セットのキー・バリューとなっています。

  • PAYPAL_API_USERNAME
  • PAYPAL_API_PASSWORD
  • PAYPAL_API_SIGNATURE



Test API Credentials を取得する前に、まずは PayPal のアカウントを取得します。本番ではビジネスアカウントが必要ですが、Sandbox では個人アカウントでも大丈夫です。


PayPal アカウントを取得した後に、「PayPal Developer」ページからログインします。
https://developer.paypal.com/
f:id:akiyoko:20160531003041p:plain

Sandbox アカウントではなく、通常の PayPal アカウントでログインします。
f:id:akiyoko:20160531003105p:plain

「DASHBOARD」をクリックします。
f:id:akiyoko:20160531003128p:plain

「Accounts」を選択します。
f:id:akiyoko:20160531003200p:plain

Sandbox 用の「Buyer アカウント(マーチャントアカウント)」と「Seller アカウント(買い手アカウント)」がデフォルトで用意されている(はずな)ので、Type が「BUSINESS」となっている方の Buyer アカウントの「Profile」をクリックします。
f:id:akiyoko:20160531003227p:plain

「API Credentials」タブから Test API Credentials を確認することができます。
f:id:akiyoko:20160531003251p:plain


参考(PayPal 公式)


参考(Test API Credentials)


参考(ビジネスアカウント)


 

2. django-oscar-paypal のインストール

Ubuntu サーバ側で、django-oscar-paypal をインストールします。

$ workon myproject
$ pip install django-oscar-paypal
  • django-localflavor==1.3
  • django-oscar-paypal==0.9.7

が追加されました。


 

3. INSTALLED_APPS に追加

sites/sandbox/settings.py に「paypal」を加えます。

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.admin',
    'django.contrib.flatpages',
    'django.contrib.staticfiles',
    'django.contrib.sitemaps',
    'django_extensions',
    # Debug toolbar + extensions
    'debug_toolbar',
    'paypal',
    'apps.gateway',     # For allowing dashboard access
    'widget_tweaks',
]


 

4. マイグレーション

以下のコマンドを実行して、django-oscar-paypal 系のテーブルを作成します。

$ python sites/sandbox/manage.py migrate --run-syncdb

Operations to perform:
  Synchronize unmigrated apps: reports_dashboard, messages, django_extensions, treebeard, gateway, communications_dashboard, reviews_dashboard, offers_dashboard, pages_dashboard, shipping_dashboard, haystack, promotions_dashboard, checkout, vouchers_dashboard, django_tables2, partners_dashboard, staticfiles, oscar, paypal, sitemaps, catalogue_dashboard, users_dashboard, search, debug_toolbar, widget_tweaks, dashboard, ranges_dashboard, orders_dashboard
  Apply all migrations: customer, promotions, shipping, wishlists, offer, admin, sessions, thumbnail, contenttypes, auth, payment, reviews, analytics, catalogue, flatpages, sites, address, basket, partner, order, voucher
Synchronizing apps without migrations:
  Creating tables...
    Creating table paypal_expresstransaction
    Creating table paypal_payflowtransaction
    Running deferred SQL...
Running migrations:
  No migrations to apply.
  Your models have changes that are not yet reflected in a migration, and so won't be applied.
  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.

Django 1.9 の場合は、「run-syncdb」オプションを付けないとテーブルが作成されないので要注意です。(最後の警告は無視して OK。対応したいのであれば、makemigrations を実行すればよい。)

参考
http://stackoverflow.com/a/34635951


ここで、

  • paypal_expresstransaction
  • paypal_payflowtransaction

というテーブルが追加されました。



ここでもう一度、データベースをバックアップしておきます。

$ mysqldump --single-transaction -u root -p myproject > ~/myproject_migrate_paypal.dump

 

5. settings を修正

ここからは、
http://django-oscar-paypal.readthedocs.org/en/latest/express.html#getting-started
を参考にして進めていきます。


https://github.com/django-oscar/django-oscar-paypal/blob/master/sandbox/settings.py
を参考に、settings.py を修正します。


sites/sandbox/settings.py の最後の方に、以下の設定を追加します。

    ・
    ・
# django-oscar-paypal
# ===================

PAYPAL_SANDBOX_MODE = True
PAYPAL_CALLBACK_HTTPS = False
PAYPAL_API_VERSION = '119'

PAYPAL_API_USERNAME = ''
PAYPAL_API_PASSWORD = ''
PAYPAL_API_SIGNATURE = ''

from django.utils.translation import ugettext_lazy as _
OSCAR_DASHBOARD_NAVIGATION.append(
    {
        'label': _('PayPal'),
        'icon': 'icon-globe',
        'children': [
            {
                'label': _('Express transactions'),
                'url_name': 'paypal-express-list',
            },
        ]
    })

# Try and import local settings which can be used to override any of the above.
try:
    from settings_local import *
except ImportError:
    pass


次に、sites/sandbox/settings_local.py に、「1. PayPal の Test API Credentials を取得」で取得したマーチャントアカウントの APIキーを設定します。

PAYPAL_API_USERNAME = 'xxxxxx-facilitator_api1.xxxxxx.xxx'
PAYPAL_API_PASSWORD = 'xxxxxxxxxxxxxxxx'
PAYPAL_API_SIGNATURE = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

 

6. urls.py を修正

https://github.com/django-oscar/django-oscar-paypal/blob/master/sandbox/urls.py
を参考に、sites/sandbox/urls.py を修正します。

<修正前>

    ・
    ・
from oscar.app import application
from oscar.views import handler500, handler404, handler403
    ・
    ・
# Prefix Oscar URLs with language codes
urlpatterns += i18n_patterns('',
    # Custom functionality to allow dashboard users to be created
    url(r'gateway/', include('apps.gateway.urls')),
    # Oscar's normal URLs
    url(r'', include(application.urls)),
)
    ・
    ・

  ↓
<修正後>

    ・
    ・
from oscar.app import application
from oscar.views import handler500, handler404, handler403
from paypal.express.dashboard.app import application as express_dashboard
    ・
    ・
# Prefix Oscar URLs with language codes
urlpatterns += i18n_patterns('',
    # PayPal Express integration
    url(r'checkout/paypal/', include('paypal.express.urls')),
    # Dashboard views for Express
    url(r'dashboard/paypal/express/', include(express_dashboard.urls)),
    # Custom functionality to allow dashboard users to be created
    url(r'gateway/', include('apps.gateway.urls')),
    # Oscar's normal URLs
    url(r'', include(application.urls)),
)
    ・
    ・


 

7. django-oscar-paypal のテンプレートファイルを修正

Django Oscar の basket(ショッピングカート)機能、および checkout(チェックアウト)機能で使われている各種テンプレートファイルに対して、以下の修正を行います。

  • Django 1.9 対応(django-oscar-paypal が Django 1.9 に対応していないため)
  • 体裁修正(django-oscar-paypal が Django Oscar のスタイルに対応していないため)


ここで、settings.py の設定が以下のようになっており、Sandbox プロジェクトの仕組み上、「sites/sandbox/templates/」 -> 「src/oscar/templates/oscar/」の順にテンプレートファイルをルックアップし、それでも無ければ、INSTALLED_APPS でインストールしたアプリケーションのテンプレートファイルを参照するようになっています。

from oscar import OSCAR_MAIN_TEMPLATE_DIR
TEMPLATE_DIRS = (
    location('templates'),
    OSCAR_MAIN_TEMPLATE_DIR,
)

Sandbox プロジェクトでは、「src/oscar/templates/oscar/」配下に実ファイルを配置しているため、ライブラリが持っているテンプレートファイルによるオーバーライドが出来ないので注意が必要です。


 

1) ショッピングカート画面

django-oscar-paypal の Sandbox用に用意されているファイル
https://github.com/django-oscar/django-oscar-paypal/blob/master/sandbox/templates/basket/partials/basket_content.html
を sites/sandbox/templates/ 配下にコピーします。

$ cd /tmp/
$ git clone https://github.com/django-oscar/django-oscar-paypal.git
$ cd django-oscar-paypal/
$ git checkout 0.9.7
$ mkdir -p /opt/webapps/myproject/sites/sandbox/templates/basket/partials
$ cp -a sandbox/templates/basket/partials/basket_content.html /opt/webapps/myproject/sites/sandbox/templates/basket/partials/basket_content.html

2016/5/28 現時点の django-oscar-paypal のソースコードのままでは、以下のようにエラーが出てしまいます。

f:id:akiyoko:20160529145830p:plain

テンプレート内で、

{% load url from future %}

と書くと、Django 1.9 で動かした場合に、

'url' is not a valid tag or filter in tag library 'future'

というエラーが発生します。これは、Django1.9 以降では、future タグの url がなくなって、ビルトインのものを使うようになったからです。なので、Django1.9 以降では、url を load する必要は無く、

{% url 'checkout:preview' %}

とそのまま使えばよいです。


参考
https://www.bountysource.com/issues/29762758-django-1-9-compatibility-url-tag


要するに、django-oscar-paypal のテンプレートが Django 1.9 対応されていないのが原因なので、以下のように修正していきます。


sites/sandbox/templates/basket/partials/basket_content.html
<修正前>

{% extends 'oscar/basket/partials/basket_content.html' %}
{% load url from future %}
{% load i18n %}

{% block formactions %}
<div class="form-actions">
	{% if anon_checkout_allowed or request.user.is_authenticated %}
        {% if basket.total_excl_tax > 0 %}
            <a href="{% url 'paypal-redirect' %}"><img src="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"></a>
        {% endif %}
	{% endif %}
	<a href="{% url 'checkout:index' %}" class="pull-right btn btn-large btn-primary">{% trans "Proceed to checkout" %}</a>
</div>
{% endblock formactions %}

  ↓
<修正後>

{% extends 'oscar/basket/partials/basket_content.html' %}
{#{% load url from future %}#}
{% load i18n %}

{% block formactions %}
<div class="form-actions">
	{% if anon_checkout_allowed or request.user.is_authenticated %}
        {% if basket.total_excl_tax > 0 %}
            <a href="{% url 'paypal-redirect' %}"><img src="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"></a>
        {% endif %}
	{% endif %}
	<a href="{% url 'checkout:index' %}" class="pull-right btn btn-large btn-primary">{% trans "Proceed to checkout" %}</a>
</div>
{% endblock formactions %}

上記の対応後、ショッピングカート画面を確認すると、以下のように表示が少し崩れてしまっています。

f:id:akiyoko:20160529150928p:plain


こちらは、Django Oscar 側のテンプレートのスタイルの当て方が変わったのに、django-oscar-paypal の Sandbox 用のテンプレート側がまだ対応できていないことが原因のようです。

そこで、src/oscar/templates/oscar/basket/partials/basket_content.html を参考にして、以下のようにテンプレートファイルを修正します。

<再修正後>

{% extends 'oscar/basket/partials/basket_content.html' %}
{#{% load url from future %}#}
{% load i18n %}

{% block formactions %}
    <div class="form-actions">
        <div class="row">
            <div class="col-sm-8">
                {% if anon_checkout_allowed or request.user.is_authenticated %}
                {% if basket.total_excl_tax > 0 %}
                <a href="{% url 'paypal-redirect' %}"><img src="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" align="left" style="margin-right:7px;"></a>
                {% endif %}
                {% endif %}
            </div>
            <div class="col-sm-4">
                <a href="{% url 'checkout:index' %}" class="btn btn-lg btn-primary btn-block">{% trans "Proceed to checkout" %}</a>
            </div>
        </div>
    </div>
{% endblock formactions %}

これで、きちんと表示されるようになりました。
f:id:akiyoko:20160529151517p:plain


 

2) チェックアウト画面

同じように、
https://github.com/django-oscar/django-oscar-paypal/blob/master/sandbox/templates/checkout/payment_details.html
を sites/sandbox/templates/ 配下にコピーします。

$ cd /tmp/django-oscar-paypal/
$ mkdir -p /opt/webapps/myproject/sites/sandbox/templates/checkout
$ cp -a sandbox/templates/checkout/payment_details.html /opt/webapps/myproject/sites/sandbox/templates/checkout/payment_details.html

こちらも、同様のエラーが出るので、
f:id:akiyoko:20160529152118p:plain


以下のように修正を加えます。

sites/sandbox/templates/checkout/payment_details.html
<修正前>

{% extends 'oscar/checkout/payment_details.html' %}
{% load url from future %}
{% load i18n %}

{% block payment_details %}
    <div class="well">
        <div class="sub-header">
            <h3>{% trans "PayPal Express" %}</h3>
        </div>
        <p>{% trans "Click on the below icon to use Express Checkout but where the shipping address and method is already chosen on the merchant site." %}</p>
        <div style="overflow:auto"><a href="{% url 'paypal-direct-payment' %}" title="{% trans "Pay with PayPal" %}"><img src="https://www.paypal.com/en_US/i/logo/PayPal_mark_37x23.gif" align="left" style="margin-right:7px;"></a>&nbsp;</div>
    </div>

    <div class="well">
        <div class="sub-header">
            <h3>{% trans "PayPal PayFlow Pro" %}</h3>
        </div>
        <form method="post" action="{% url 'checkout:preview' %}" class="form-stacked">
            {% csrf_token %}
            <h4>{% trans "Bankcard" %}</h4>
            {% include "partials/form_fields.html" with form=bankcard_form %}
            <h4>{% trans "Billing address" %}</h4>
            {% include "partials/form_fields.html" with form=billing_address_form %}
            <div class="form-actions">
                <button type="submit" class="btn btn-large btn-primary">{% trans "Continue" %}</button>
            </div>
        </form>
    </div>

{% endblock %}

  ↓
<修正後>

{% extends 'oscar/checkout/payment_details.html' %}
{#{% load url from future %}#}
{% load i18n %}

{% block payment_details %}
    <div class="well">
        <div class="sub-header">
            <h3>{% trans "PayPal Express" %}</h3>
        </div>
        <p>{% trans "Click on the below icon to use Express Checkout but where the shipping address and method is already chosen on the merchant site." %}</p>
        <div style="overflow:auto"><a href="{% url 'paypal-direct-payment' %}" title="{% trans "Pay with PayPal" %}"><img src="https://www.paypal.com/en_US/i/logo/PayPal_mark_37x23.gif" align="left" style="margin-right:7px;"></a>&nbsp;</div>
    </div>

    <div class="well">
        <div class="sub-header">
            <h3>{% trans "PayPal PayFlow Pro" %}</h3>
        </div>
        <form method="post" action="{% url 'checkout:preview' %}" class="form-stacked">
            {% csrf_token %}
            <h4>{% trans "Bankcard" %}</h4>
            {% include "partials/form_fields.html" with form=bankcard_form %}
            <h4>{% trans "Billing address" %}</h4>
            {% include "partials/form_fields.html" with form=billing_address_form %}
            <div class="form-actions">
                <button type="submit" class="btn btn-large btn-primary">{% trans "Continue" %}</button>
            </div>
        </form>
    </div>

{% endblock %}

f:id:akiyoko:20160529152616p:plain

ここでは詳しく触れませんが、日本では「PayPal PayFlow Pro」は使えないので、最終的なテンプレートファイルは以下のようにしておきます。

<再修正後>

{% extends 'oscar/checkout/payment_details.html' %}
{#{% load url from future %}#}
{% load i18n %}

{% block payment_details %}
    <div class="well">
        <div class="sub-header">
            <h3>{% trans "PayPal Express" %}</h3>
        </div>
        <p>{% trans "Click on the below icon to use Express Checkout but where the shipping address and method is already chosen on the merchant site." %}</p>
        <div style="overflow:auto"><a href="{% url 'paypal-direct-payment' %}" title="{% trans "Pay with PayPal" %}"><img src="https://www.paypal.com/en_US/i/logo/PayPal_mark_37x23.gif" align="left" style="margin-right:7px;"></a>&nbsp;</div>
    </div>
{% endblock %}

f:id:akiyoko:20160529152636p:plain



 

3) PayPal からのリダイレクト画面

続いて、PayPal での処理処理が終わったときにリダイレクトされてくる画面のテンプレートファイルを修正します。これまで同様に、

  • Django 1.9 対応
  • 体裁修正

の対応を行います。

$ cp -r /home/vagrant/.virtualenvs/myproject/lib/python2.7/site-packages/paypal/templates/* /opt/webapps/myproject/sites/sandbox/templates/
$ rm -rf /opt/webapps/myproject/sites/sandbox/templates/paypal/payflow

$ tree sites/sandbox/templates/paypal/
sites/sandbox/templates/paypal/
└── express
    ├── dashboard
    │   ├── transaction_detail.html
    │   └── transaction_list.html
    └── preview.html

sites/sandbox/templates/paypal/express/preview.html
<修正前>

{% extends "checkout/preview.html" %}
{% load currency_filters %}
{% load i18n %}
{% load url from future %}
{% load thumbnail %}

{# Null out the actions as they can't be used here #}
{% block shipping_address_actions %}{% endblock %}
{% block shipping_method_actions %}{% endblock %}
{% block order_contents_actions %}{% endblock %}

{% block payment_method %}
    <div class="span6">
        <div class="sub-header">
            <h2>{% trans "Payment" %}</h2>
        </div>
        <div class="well well-success">
            <h4>{% trans "PayPal" %}</h4>
            <p>
                {% blocktrans with amt=paypal_amount|currency email=paypal_user_email %}
                    {{ amt }} will be deducted from your PayPal account, registered 
                    to email: {{ email }}.
                {% endblocktrans %}
            </p>
        </div>
    </div>
{% endblock %}
    ・
    ・

  ↓
<修正後>

{% extends "checkout/preview.html" %}
{% load currency_filters %}
{% load i18n %}
{#{% load url from future %}#}
{% load thumbnail %}

{# Null out the actions as they can't be used here #}
{% block shipping_address_actions %}{% endblock %}
{% block shipping_method_actions %}{% endblock %}
{% block order_contents_actions %}{% endblock %}

{% block payment_method %}
    <div class="col-sm-6">
        <div class="sub-header">
            <h2>{% trans "Payment" %}</h2>
        </div>
        <div class="well well-success">
            <p>{% blocktrans with amount=order_total.incl_tax|currency %}<strong>{{ amount }}</strong> will be debited from your bankcard.{% endblocktrans %}</p>
            <div class="alert-actions">
                <a href="{% url 'checkout:payment-details' %}" class="btn">{% trans "Change payment details" %}</a>
            </div>
        </div>
    </div>
{% endblock payment_method %}
    ・
    ・


 

4) ダッシュボード画面

Django Oscar のダッシュボード画面を使う場合は、以下の 2ファイルに Django 1.9 対応の修正を加える必要があります。


sites/sandbox/templates/paypal/express/dashboard/transaction_list.html

{% extends 'dashboard/layout.html' %}
{% load currency_filters %}
{% load i18n %}
{#{% load url from future %}#}
    ・
    ・


f:id:akiyoko:20160529154701p:plain


sites/sandbox/templates/paypal/express/dashboard/transaction_detail.html

{% extends 'dashboard/layout.html' %}
{% load currency_filters %}
{% load i18n %}
{#{% load url from future %}#}
    ・
    ・

f:id:akiyoko:20160529154718p:plain


以上で、Django Oscar の Sandbox サイトを構築するまでの作業は終了です。



GitHub にも修正内容をアップしたので、こちらも参照してください。
GitHub - akiyoko/oscar_sandbox




 

まとめ

やや細かな修正内容まで言及してしまいましたが、Django Oscar の Sandbox サイトを構築して、決済モジュールを導入するまでの手順を紹介しました。

これで、Django Oscar のいろいろな機能を試すことができるようになりました。次回は、この Sandbox サイトを使って、Django Oscar の ECサイトとしての機能を検証していきます。