pythonで作るネットショップ　django-oscarを始めよう　①インストール～概観まで

# はじめに
はじめましてidavashです。OriginallyTeeというオリジナルTシャツの作成・購入・販売ができるネットショップ（以下ECサイト）の作成・運用をしています。

OriginallyTeeはdjango-oscar（以下 oscar)という、pythonのフルスタックECサイトフレームワークです。

oscarはgithubで6000以上のスターがある人気フレームワークで、またdjangoで開発されているので、慣れれば使い方も簡単です。

ですがoscarはほぼ日本語記事が存在せず、使うためのハードルが存在します。

そこでこの記事では、oscarで0からECサイトを作る過程を丁寧に紹介したいと思います。


# なぜdjango-oscarか？

ECサイトをpythonで作りたい！という需要は大いにあると思われます。が、スクラッチで開発するのは大変なので、フレームワークを使いたいですよね？

oscarには多くの機能が備わっており、oscarならシンプルなECサイトから、複雑で独自性の高いECサイトまで作れます。

私が作成したOriginallyTeeはoscarで作られた、オリジナルTシャツのECサイトですが、OriginallyTeeではサイト上でTシャツのデザインをすることや、ユーザーがデザインしたTシャツを販売する機能も備わっています。(デザイン機能はvue3で作成)

https://originally-tee.com/

これらの機能はモール型のECサイトでは実現できません。開発が必要となりますが、oscarであればECサイトに必須の機能はすべて備わっているので、独自機能の開発に集中できます。０から開発するよりもずっと短時間で完成できます。

OriginallyTeeのケースは一例ですが、oscarを使うことで望む機能を持ったECサイトを作ることができます。

それでは早速oscarの使い方を見ていきましょう。

# インストール
ドキュメントの手順通りにインストールすればOKです
https://django-oscar.readthedocs.io/en/latest/internals/getting_started.html

#### 仮想環境を作成・起動
仮想環境名はPracticeOscarとしています
```
$ python -m venv PracticeOscar
$ .\PracticeOscar\Scripts\activate
```
####  ライブラリをインストール、プロジェクトを開始

プロジェクト名をpractice_shopとしていますが、好きな名前を付けてください

```
pip install "django-oscar[sorl-thumbnail]==3.2.4"
django-admin startproject practice_shop
```

プロジェクトをエディターで開くとsettings.pyとurls.pyがあるので、ドキュメントの通りに修正します

```python:settings.py
"""
Django settings for practice_shop project.

Generated by 'django-admin startproject' using Django 4.2.16.

For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""

from pathlib import Path
from oscar.defaults import *  # 追加

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "あなたのシークレットキー"

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
        'django.contrib.sites',
    'django.contrib.flatpages',
    # 以下追加
    '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',   # Default thumbnail backend, can be replaced
    'django_tables2',
]

# 追加
SITE_ID = 1

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    # 追加
    'oscar.apps.basket.middleware.BasketMiddleware',
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
]

# 追加
AUTHENTICATION_BACKENDS = (
    'oscar.apps.customer.auth_backends.EmailBackend',
    'django.contrib.auth.backends.ModelBackend',
)

ROOT_URLCONF = "practice_shop.urls"

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",
                # 以下追加
                "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",
            ],
        },
    },
]

WSGI_APPLICATION = "practice_shop.wsgi.application"

# 追加
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.simple_backend.SimpleEngine',
    },
}

# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

# 設定このままでOK。ATOMIC_REQUESTS使わない
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}


# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = "static/"

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

```

```python: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])),
]

```
settings.pyのSECRET_KEY にはご自分のSECRET_KEY を入力してください。

本格的な開発ではsettings.pyは以下のような変更が必要ですが、今のところは変更せず進めます。

- データベースをsqlite3から変更する(Postgresqlなど)
- 商品検索エンジンをHaystackからsolrに変更する
- css,js,画像の配信をクラウドストレージから行う(AWSのS3など)
- メール配信をメールサーバーから行う(AWSのSESなど)
- .envファイルを使って、秘密のパスワードなどが見えないようにする
- 開発と本番のsettings.pyを分ける
- 
etc

####  ローカルサーバーを起動する
```
$ python manage.py migrate
$ python manage.py runserver
```
runserverでターミナルにURLが表示されるので、そこをクリックしてページが表示されれば成功です。URLの後にdashboard/を付ければ管理画面も表示されます。 

`python manage.py createsuperuser`で管理者を作成すれば管理画面にログインできます。

この設定は次回行います。

サーバーはctrl + c で停止できます。サーバーを停止して続けます。

#### 国データを追加する
配送に国データが必須なので以下のコマンドで追加します
```
$ pip install pycountry
$ python manage.py oscar_populate_countries
```

#### settings.pyにオーダーの状態を定義する
オーダーがどのような状態をとるか・現在の次はどのような状態とるか、を定義します。ここはビジネスロジックによって決まる部分になります。とりあえずドキュメント通りに設定します。

```python: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': (),
}
```
ここまでで初期設定は完了です。お疲れ様でした

# oscarの機能概観

oscarの各機能を簡単に見ていきます。公式説明ではなく、私見によるものです。

`仮想環境名\Lib\site-packages\oscar`にoscarがインストールされているので
```
cd 仮想環境名\Lib\site-packages\oscar\apps
```
とすると以下のように機能ごとに分かれています
```
├─address
├─analytics
├─basket
├─catalogue
│  ├─reviews
├─checkout
├─communication
├─customer
├─dashboard
├─offer
├─order
├─partner
├─payment
├─search
├─shipping
├─voucher
├─wishlists
```
簡単に見ていきます

### address
主に商品配送先の住所を管理します。必要ならば請求先住所や、商品発送パートナーの住所なども管理します

### analytics
商品が見られた回数や、商品が検索された回数などの統計情報を管理します。この情報を使用して簡単な商品ランキングや商品おススメなどが作れます

### basket
商品カートです。かなり重要な部分です。ミドルウェアも含むので、場合によってはそこも変更します

### catalogue
商品カタログです。最重要です。商品レビュー機能もここに含まれます

### checkout
決済機能です。商品カートが購入手続きに移ると、checkoutで処理します。oscarでは決済部分のコードは書かれていないので、自分で実装する必要があります。OriginallyTeeではStripeを使っています

### communication
メール送信機能です。定型的なメールはテンプレートを作成して、自動で送信できます

### customer
ユーザー管理機能です。ユーザーへの商品入荷通知もここにあります。

### dashboard
上にも書いた管理画面です。oscarではdjangoのデフォルト管理画面でなく、こちらが推奨されています。（ただし自分はdjangoのデフォルトも使います。問題が生じたことはないです）

### offer
値引き機能です。あまり使ったことがないのでわかりません

### oder
注文確定後の処理です。checkoutで注文が確定した後は、oderで処理します

### partner
商品配送パートナーを管理しています。手元在庫の配送のみの時は、パートナーについての設定はありません。ただし商品の在庫や価格もなぜかこちらで管理しているので、その設定は必要です

### payment
クレジットカードやコンビニ払いなどの支払い手段を管理しています。支払い処理の多くはcheckoutの方で行うので、あまり使うことはないです

### search
検索機能です。デフォルトのHAYSTACKは貧弱ですのでsolrを使いますが、solrに移行する際、コードを追加します

### shipping
配送機能です。送料の設定はこちらで行います。デフォルトの機能でもかなり自由度の高い設定ができます

### voucher
クーポン機能です。一通りのクーポン発行方法が揃っています。OriginallyTeeではofferでなく、こちらを主に使っています

### wishlist
ウィッシュリストです。商品のお気に入り機能を設定できます。ウィッシュリストはここと、customer/wishlistに跨って機能が存在します

# 次回予定

管理者を追加して、管理画面から商品を追加します。

その後は自分のECサイトを作るにあたって、oscarのコードをどんどん修正していく必要があるので、そのやり方を見ていきます。

https://qiita.com/idavash/items/10bbf98872a1c7161f1e

# 便利なWebサイト

github
https://github.com/django-oscar/django-oscar

ドキュメント　最初のうちはここを見ることが一番多いと思います
https://django-oscar.readthedocs.io/en/latest/

フォーラム　過去の質問を見ることもできます
https://groups.google.com/g/django-oscar
https://app.slack.com/client/T1QSP0999/C1QUF61T3

oscarはdjangoで作られているので、開発時はこちらも参照します
https://github.com/django/django
https://docs.djangoproject.com/en/5.0/