7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Djangoのプロジェクトを始める

Last updated at Posted at 2019-12-20

はじめに

この記事では、Djangoのプロジェクトの作成から、ホーム画面とアカウント作成画面、ログイン画面を表示までを行います。
ほとんど、個人用のメモですが、参考になれば幸いです。動作の保証はできません。

認証は、django-allauthを用いています。
django-allauthをによる画面の編集、テストは、Django allauthにおけるログイン画面の作成に記載しています。

インストール/登録

プロジェクトを始める

以下のコマンドで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などネットに公開する場合、アップロードしないように注意する。

.env
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

基本パラメータを設定

./config/settings/base.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)

開発用のパラメータを設定

./config/settings/development.py
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を変更する。

./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パターンを設定する。

./config/urls.py
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

ホーム画面へのパス設定する。

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に使用できる文字を制限している。

./main/models.py
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/ にアクセスした場合、ログイン画面が表示されます。

例えば、以下のような画面が表示されます。
スクリーンショット 2019-08-16 23.41.31.png

参考文献

本記事の多くの部分は、以下の教科書を参考にしました。
おそらくこの記事のみでは、補完できないと思うので、以下の本を買いましょう!!
めっちゃいい本です。

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?