[PYTHON] Start a Django project

Introduction

In this article, you'll go from creating a Django project to displaying your home, account, and login screens. Most of them are personal notes, but I hope you find them helpful. Operation cannot be guaranteed.

Authentication uses django-allauth. Editing and testing screens with django-allauth is described in Creating a Login Screen with Django allauth.

Installation / registration

Start a project

Create a django project location with the following command.

mkdir ec-django

Create a virtual environment for python and install the required packages.

cd ec-django/

python -m venv venv

//Enter the virtual environment
source venv/bin/activate

//Package installation in virtual environment
pip install Django==2.2
pip install django-allauth==0.39.1 //Authentication functions such as login function
pip install django-environ==0.4.5 //Environment variables.To read from an env file
pip install mysqlclient==1.4.4 //For Mysql database
//pip install stripe==2.35.0 //Payment function by stripe

Create a project.


django-admin startproject config .

Create an application (main) that manages users.


./manage.py  startapp main

Create other necessary directories.

//Directory of python files for easy processing
mkdir script
touch ./script/__init__.py

//templates file(.html etc.)Directory to put
mkdir templates

//Directory to put static files
mkdir static

Setting environment variables with env file

Creating an .env file


touch .env

Environment variables are added to the following .env file each time a function is added. If you publish it on the net such as git, be careful not to upload it.

.env


DEBUG=Ture

SECRET_KEY=<django-secret-key> //./config/setting.py secret key

//The following are the settings related to the database. (Match with the DB set in the latter half of the article.)
DB_NAME=databese-name
DB_USER=user-name
DB_PASS=password

Create a program that reads environment variables. The following program also reads the DB information and the path to the base directory of your Django project, which you'll set later in this article.

import environ
import os
from config.settings.base import BASE_DIR #Set later

import logging
logger = logging.getLogger(__file__)

def get_env_dict(env_path):
    env = {}
    try:
        read_env = environ.Env()
        environ.Env.read_env(env_path)

        #less than,.Write about the parameters to read from the env file.
        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 that is not set is set: {}'.format(e))
        
    except Exception as e:
        logger.info('Environment variable setting error: {e}'.format(e))
    
    return env
        

env_path = os.path.join(BASE_DIR, '.env')
env = get_env_dict(env_path)

Set up a MySQL database

I referred to the following. Django's DATABASE settings that I always do when using MySQL (utf8mb4) with Django MySQL Setup on Mac

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 name database-name,Username user-name,Password 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;

//If you run tests in Django
mysql> GRANT ALL PRIVILEGES ON test_django_test.* TO 'mysiteuser'@'localhost';

Django parameter settings

Create a configuration file. The configuration file is. Although it is ./config/settings.py, create a configuration file for development as follows.

mkdir ./config/settings
touch ./config/settings/__init__.py
touch ./config/settings/base.py
touch ./config/settings/development.py

Set basic parameters

python:./config/settings/base.py


import os

###############
# Build paths #
###############

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) #Fixed by file change
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 app
    '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'), #Place to put login template etc.
            os.path.join(BASE_DIR, 'templates'), #Where to put the template
        ],
        '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.To use the User model to be set in py for authentication

#URL to transition after login process
LOGIN_REDIRECT_URL = 'home'

#URL to transition to after logout processing
ACCOUNT_LOGOUT_REDIRECT_URL = 'home'

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend', #Email settings are made in Custom User, so settings are required
)

#Set the authentication method to an email address
ACCOUNT_AUTHENTICATION_METHOD = 'email' 

#Request an email address when creating an account
ACCOUNT_EMAIL_REQUIRED = True 

#Do not send user registration confirmation email:When sending'option'
ACCOUTN_EMAIL_VERIFICATION = 'none'

#Do not use USER name (I commented out the following, so in this project, I will request it when creating an account: default)
#ACCOUNT_USERNAME_REQUIRED = False 

#With the logout button, you can immediately transition to the redirect destination without transitioning to the logout screen.
ACCOUNT_LOGOUT_ON_GET = True 

#all-auth used to determine site
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' #Set for Japan

TIME_ZONE = 'Asia/Tokyo' #Set for Japan

USE_I18N = True

USE_L10N = True

USE_TZ = True


################
# Static files #
################

#Set where to put static files
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_ROOT = '/var/www/{}/static'.format(PROJECT_NAME)

#Set the location to put the media files
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/{}/media'.format(PROJECT_NAME)

Set parameters for development

python:./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'], #Created database name
        'USER': env['DB_USER'], #Login user name
        'PASSWORD': env['DB_PASS'],
        'HOST': 'localhost',
        'PORT': '3306',
        'ATOMIC_REQUESTS': True, #transaction
        'OPTIONS': {
            'charset': 'utf8mb4',
            'sql_mode': 'TRADITIONAL,NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY',
        },
        "TEST": {
            'NAME' : 'test_django_test'
        }
    }
}

###########
# Logging #
###########

LOGGING = {
    #Version is fixed to "1"
    'version': 1,
    #Do not invalidate existing log settings
    'disable_existing_loggers': False,
    #Log format
    'formatters': {
        #For development
        'develop': {
            'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d ' '%(message)s'
        },
    },
    #handler
    'handlers': {
        #Handler for console output
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'develop',
        },
    },
    #Logger
    'loggers': {
        #A logger that picks up logs for all self-made applications
        '': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        #A logger that picks up all the logs that Django itself puts out
        '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'

Modify ./manage.py so that development.py is selected when DEBUG in the .env file is True.

python:./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():
#.Development when DEBUG of env file is True.Load 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 :Settings related to the production environment are described separately.

        
    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()

Try to display the homepage !!

Create URL routing

Here, set the URL pattern to the project management screen, login screen in django-allauth, and screen related to main / urls.py.

python:./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), #Project management screen
    path('accounts/', include('allauth.urls')), #Account management functions such as login
    path('', include('main.urls')), #Things related to the main application such as the home screen
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Set the url of the screen related to the main application.

./main Since urls.py is not included in the app, create urls.py

When registering a User name, a regular expression limit (username_regex) and a minimum number of characters limit (MinLengthValidator) are added as validation functions.

touch ./main/urls.py

Set the path to the home screen.

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'),
]

Create a user model for the login function

As a User model, username and email required for account creation are set. Here, the characters that can be used for username are restricted.

python:./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 _ #For internationalization such as translation function


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="Characters that cannot be used in the user name are specified.")
    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)

Database migration

Since the User model is set in models.py, migration is performed.


//DB startup
mysql.server start

//Creating a migration file
./manage.py makemigrations

//Migrate to DB
./manage.py migrate

If you make a mistake in the model and re-migrate the DB, and if you can delete the DB during development, you can initialize it with the following command.


//Delete migration file
find . -path "*/migrations/0*.py" -delete
find . -path "*/migrations/__pycache__/0*.pyc" -delete

//Delete / reset database
mysql -u root -p

mysql> drop database database-name;
mysql>create database database-name;
mysql>exit;

mysql.server restart

home template creation

Create main / home.html set in ./main/urls.py.

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>

Display home page

Start the server with the following command

./manage.py runserver

If you access http: // localhost: 8000 / in your browser, you should see a screen that says Hello djanog !!. Also, if you access http: // localhost: 8000 / accounts / signup /, the account creation screen will be displayed. Also, if you access http: // localhost: 8000 / accounts / login /, the login screen will be displayed.

For example, the following screen will be displayed. スクリーンショット 2019-08-16 23.41.31.png

References

For many parts of this article, I referred to the following textbooks. Perhaps this article alone is not enough to complement, so buy the following books !! It's a really good book.

Recommended Posts

Start a Django project
Django --start project without start project
Steps to create a Django project
A solution when you can't start project Django on Windows
Start Django Tutorial 1
Django Project Baseline
Commands for creating a new django project
Create a Django schedule
Django project environment construction
Start Django in a virtual environment with Pipenv
[Django] Rename the project
Start today with Django
Create a Django project and application in a Python virtual environment and start the server
What is a dog? Django App Creation Start Volume--startapp
What is a dog? Django App Creation Start Volume--startproject
Tasks at the start of a new python project
To myself as a Django beginner (1) --Create a project app--
How to reference static files in a Django project
Django Getting Started: 2_ Project Creation
Create a homepage with django
Shell to create django project
Create a Django login screen
django project development environment construction
Deploy django project to heroku
[Note] Django project creation and terminology
Django: Import a class from a string
Deploy Django + React from scratch to GKE (3) Create a GCP project
Register your Django application in your project
Deploy a Django application with Docker
Django
Django Tips-Create a ranking site with Django-
Implement a Django app on Hy
Start SQLite in a programming language
Make a filter with a django template
Start Django for the first time
Create a file uploader with Django
Create a LINE Bot in Django
Install Django in a pipenv virtual environment
A site that helped me study Django
Create a new Python numerical calculation project
Create a model for your Django schedule
Build a TOP screen for Django users
What is a dog? Django installation volume
Creating a login screen with Django allauth
Dynamically specify a ModelChoiceField queryset in Django
Get a reference model using Django Serializer
[Django] A memo when log was not
A note on enabling PostgreSQL with Django
Use Django from a local Python script
Django project structure customization (splitting and structuring)
Memo about Sphinx Part 1 (Creating a project)
Implement a Custom User Model in Django
Write a short if-else for Django Template
I made a WEB application with Django
[Python] Introduce UIKit3 to your Django project