はじめに
この記事では、Djangoのプロジェクトの作成から、ホーム画面とアカウント作成画面、ログイン画面を表示までを行います。
ほとんど、個人用のメモですが、参考になれば幸いです。動作の保証はできません。
認証は、django-allauthを用いています。
django-allauthをによる画面の編集、テストは、Django allauthにおけるログイン画面の作成に記載しています。
インストール/登録
- pythonのインストール
- stripeへ登録 使わない場合しなくても良いです。
プロジェクトを始める
以下のコマンドでdjangoのプロジェクトの場所を作成する。
mkdir ec-django
pythonの仮想環境の作成し、必要なパッケージをインストールする。
cd ec-django/
python -m venv venv
//仮想環境へ入る
source venv/bin/activate
//仮想環境内でパッケージインストール
pip install Django==2.2
pip install django-allauth==0.39.1 //ログイン機能などのauthentication機能
pip install django-environ==0.4.5 //環境変数を.envファイルから読み込むため
pip install mysqlclient==1.4.4 //Mysql データベース用
//pip install stripe==2.35.0 //stripeによる決済機能
プロジェクトを作成する。
django-admin startproject config .
ユーザを管理するアプリ(main)を作成する。
./manage.py startapp main
その他必要なディレクトリを作成する。
//簡単な処理を行うpythonファイルをディレクトリ
mkdir script
touch ./script/__init__.py
// templatesファイル(.htmlなど)を置くディレクトリ
mkdir templates
//静的ファイルを置くディレクトリ
mkdir static
envファイルによる環境変数の設定
.envファイルの作成
touch .env
以下の.envファイルに機能追加の都度、環境変数を追加していく。
もし、gitなどネットに公開する場合、アップロードしないように注意する。
DEBUG=Ture
SECRET_KEY=<django-secret-key> //./config/setting.pyのsecret key
//以下データベースに関する設定である。(記事後半で設定するDBに合わせる。)
DB_NAME=databese-name
DB_USER=user-name
DB_PASS=password
環境変数を読み込むプログラムを作成する。
以下のプログラムでは、本記事の後半で設定する、DB情報に関するものと、Djangoプロジェクトのベースとなるディレクトリのパスも読み込んでいる。
import environ
import os
from config.settings.base import BASE_DIR #後ほど設定
import logging
logger = logging.getLogger(__file__)
def get_env_dict(env_path):
env = {}
try:
read_env = environ.Env()
environ.Env.read_env(env_path)
#以下に、.envファイルから読み込むパラメータについて書く。
if read_env('DEBUG') == 'True' or True:
env['DEBUG'] = True
elif read_env('DEBUG') == 'False' or False:
env['DEBUG'] = False
#secret keys
env['SECRET_KEY'] = read_env('SECRET_KEY')
#DB setting
env['DB_NAME'] = read_env('DB_NAME')
env['DB_USER'] = read_env('DB_USER')
env['DB_PASS'] = read_env('DB_PASS')
except environ.ImproperlyConfigured as e:
logger.info('設定されていないkeyが設定されている: {}'.format(e))
except Exception as e:
logger.info('環境変数設定のエラー: {e}'.format(e))
return env
env_path = os.path.join(BASE_DIR, '.env')
env = get_env_dict(env_path)
MySQLデータベースを設定
以下を参考にしました。
いつもDjangoでMySQL(utf8mb4)を利用するときに行っているDjangoのDATABASE設定
Mac での MySQL セットアップ
brew install mysql
//mysql --version
//mysql Ver 14.14 Distrib 5.7.25, for osx10.14 (x86_64) using EditLine wrapper
mysql.server start
mysql -u root -p
//DB名 database-name, ユーザー名 user-name, パスワード passwordとすると
mysql> CREATE DATABASE database-name;
mysql> CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON database-name.* TO 'user-name'@'localhost';
mysql> FLUSH PRIVILEGES;
//もしDjangoにおいて、テストを実行する場合
mysql> GRANT ALL PRIVILEGES ON test_django_test.* TO 'mysiteuser'@'localhost';
Djangoのパラメータの設定
設定ファイルを作成する。
設定ファイルは。./config/settings.pyであるが、以下のように開発用の設定ファイルを作成する。
mkdir ./config/settings
touch ./config/settings/__init__.py
touch ./config/settings/base.py
touch ./config/settings/development.py
基本パラメータを設定
import os
###############
# Build paths #
###############
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #ファイル変更により修正
PROJECT_NAME = os.path.basename(BASE_DIR)
############
# Security #
############
DEBUG = False
ALLOWED_HOSTS = []
#################
# Core settings #
#################
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
#django-allauth
'allauth',
'allauth.account',
'allauth.socialaccount',
#main アプリ
'main.apps.MainConfig',
]
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',
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates', 'allauth'), #ログインテンプレート等などを置く場所
os.path.join(BASE_DIR, 'templates'), #テンプレートを置く場所
],
'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',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
##################
# Authentication #
##################
AUTH_USER_MODEL = "main.User" #main/model.pyで設定予定のUserモデルを認証に使用するため
#ログイン処理後に遷移するURL
LOGIN_REDIRECT_URL = 'home'
#ログアウト処理後に遷移するURL
ACCOUNT_LOGOUT_REDIRECT_URL = 'home'
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend', #CustomUserにおいてEmail設定を行っているため設定が必要
)
# 認証方法をメールアドレスにする
ACCOUNT_AUTHENTICATION_METHOD = 'email'
# メールアドレスをアカウント作成時に要求する
ACCOUNT_EMAIL_REQUIRED = True
#ユーザー登録確認メールは送信しない :送信する場合は'option'
ACCOUTN_EMAIL_VERIFICATION = 'none'
#USER名を使用しない(以下をコメントアウトしていので、今回のプロジェクトでは、アカウント作成時に要求する:デフォルト)
#ACCOUNT_USERNAME_REQUIRED = False
#ログアウトボタンにより、ログアウト画面に遷移せず、即座にリダイレクト先へ遷移
ACCOUNT_LOGOUT_ON_GET = True
#all-authがサイトを判別するために使用
SITE_ID = 1
############
# Database #
############
DATABASES = {}
############
# Messages #
############
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
###########
# Logging #
###########
LOGGING = {}
#######################
# Password validation #
#######################
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 #
########################
LANGUAGE_CODE = 'ja' #日本用に設定
TIME_ZONE = 'Asia/Tokyo' #日本用に設定
USE_I18N = True
USE_L10N = True
USE_TZ = True
################
# Static files #
################
#静的ファイルを置く場所を設定
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_ROOT = '/var/www/{}/static'.format(PROJECT_NAME)
#メディアファイルを置く場所を設定
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/{}/media'.format(PROJECT_NAME)
開発用のパラメータを設定
from .base import *
from script.get_env_dict import env
#####################
# Security settings #
#####################
DEBUG = True
SECRET_KEY = env['SECRET_KEY']
ALLOWED_HOSTS = ['*']
############
# Database #
############
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': env['DB_NAME'], # 作成したデータベース名
'USER': env['DB_USER'], # ログインユーザー名
'PASSWORD': env['DB_PASS'],
'HOST': 'localhost',
'PORT': '3306',
'ATOMIC_REQUESTS': True, #トランザクション
'OPTIONS': {
'charset': 'utf8mb4',
'sql_mode': 'TRADITIONAL,NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY',
},
"TEST": {
'NAME' : 'test_django_test'
}
}
}
###########
# Logging #
###########
LOGGING = {
# バージョンは「1」固定
'version': 1,
# 既存のログ設定を無効化しない
'disable_existing_loggers': False,
# ログフォーマット
'formatters': {
# 開発用
'develop': {
'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d ' '%(message)s'
},
},
# ハンドラ
'handlers': {
# コンソール出力用ハンドラ
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'develop',
},
},
# ロガー
'loggers': {
# 自作アプリケーション全般のログを拾うロガー
'': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
},
# Django本体が出すログ全般を拾うロガー
'django-test': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
},
}
################
# Static files #
################
STATIC_ROOT = os.path.join(BASE_DIR, 'static-root')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
##################
# Email settings #
##################
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
.envファイルのDEBUGがTrueのとき、development.pyが選択されるように./manage.pyを変更する。
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
from script.get_env_dict import env
def main():
#.envファイルのDEBUGがTrueのとき、development.pyを読み込む
if env['DEBUG'] == True:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.development')
elif env['DEBUG'] == False:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.development') ## TODO : 本番環境に関する設定は、別途記載
from django.db.backends.mysql.schema import DatabaseSchemaEditor
DatabaseSchemaEditor.sql_create_table += " ROW_FORMAT=DYNAMIC"
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
ホームページを表示してみる!!
URLのルーティングを作成
ここでは、プロジェクト管理画面、django-allauthにおけるログインなどの画面、main/urls.pyに関する画面へのURLパターンを設定する。
from django.contrib import admin
from django.urls import path, include
from script.get_env_dict import env
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls), #プロジェクト管理画面
path('accounts/', include('allauth.urls')), #ログインなどのアカウント管理機能
path('', include('main.urls')), #home画面などmainアプリに関するもの
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
mainアプリに関する画面のurlを設定する。
./mainアプリ内には、urls.pyが含まれていないため、urls.pyを作成
User名の登録時に、validationの機能として、正規表現による制限(username_regex)と、最小文字数の制限(MinLengthValidator)を追加している。
touch ./main/urls.py
ホーム画面へのパス設定する。
from django.contrib import admin
from django.views.generic import TemplateView
from django.urls import path, include
from main import views
urlpatterns = [
path('', TemplateView.as_view(template_name="main/home.html"), name='home'),
]
ログイン機能のためのユーザーモデルを作成
Userモデルとして、アカウント作成に必要な、username, emailを設定している。
ここでは、usernameに使用できる文字を制限している。
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.core.validators import MinLengthValidator, RegexValidator
from django.utils.translation import gettext_lazy as _ #翻訳機能など国際化のため
class User(AbstractUser):
"""Custom user to perform authentication by email """
username_validator = UnicodeUsernameValidator()
username_regex = RegexValidator(regex=r'^[a-zA-Z0-9][a-zA-Z0-9\-]+', message="ユーザネームに使用できない文字が指定されています。")
username = models.CharField(_('username'), max_length=150, unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
validators=[username_validator, username_regex, MinLengthValidator(5)],
error_messages={
'unique': _("A user with that username already exists."),
},
)
email = models.EmailField('emial address', unique=True)
データベースマイグレーション
models.pyにUserモデルを設定したため、マイグレーションを行う。
//DBの起動
mysql.server start
//マイグレーションファイルの作成
./manage.py makemigrations
//DBにマイグレート
./manage.py migrate
もし、モデルを間違えてDBのマイグレートをやり直した場合、かつ、開発中でDBを消して良い場合、以下のコマンドで初期化できる。
//マイグレーションファイルを削除
find . -path "*/migrations/0*.py" -delete
find . -path "*/migrations/__pycache__/0*.pyc" -delete
//データベースを削除・再設定
mysql -u root -p
mysql> drop database database-name;
mysql>create database database-name;
mysql>exit;
mysql.server restart
homeテンプレートの作成
./main/urls.pyで設定した、main/home.htmlを作成する。
mkdir ./templates/main
touch ./templates/main/home.html
<!DOCTYPE html>
<html lang="js">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Hello djanog !!</h1>
</body>
</html>
ホームページを表示
以下のコマンドでサーバを起動
./manage.py runserver
ブラウザで、http://localhost:8000/ にアクセスすると、Hello djanog !!と表示された画面が表示されるはずです。
また、http://localhost:8000/accounts/signup/ にアクセスした場合、アカウント作成画面が表示されます。
また、http://localhost:8000/accounts/login/ にアクセスした場合、ログイン画面が表示されます。
参考文献
本記事の多くの部分は、以下の教科書を参考にしました。
おそらくこの記事のみでは、補完できないと思うので、以下の本を買いましょう!!
めっちゃいい本です。