-Added pip install
when you want to add a module during development
-I had a very wrong understanding of the docker-compose run
command, so I corrected it and changed to using the docker exec
command as an alternative.
Now that you've covered the basics of Python, the next step is to build an environment to get used to Django, and the planner's article has just a tutorial on the basics of Django. This is the output when you do that.
Articles that enable system development with Django (Python)_Introduction
Create a django environment with docker-compose (MariaDB + Nginx + uWSGI) Docker-Compose with Python3.6 + NGINX + MariaDB10 + uWSGI's Django environment greedy set
It was built in the following environment with reference to the above two articles and the environment.
・ Windows10 home ・ Docker version 19.03.1 (Docker Toolbox specification) -VirtualBox 6.0.16 ・ Python3.8 ・ Django 3 ・ Mariadb 10.1 ・ Nginx 1.13
.
├── db
│ ├── data
│ └── sql
│ └── init.sql
├── docker-compose.yml
├── nginx
│ ├── conf
│ │ └── app_nginx.conf
│ ├── log
│ └── uwsgi_params
├── python
│ ├── Dockerfile
│ └── requirements.txt
├── src
│ └── project
│ ├── app
│ │ └── __init__.py
│ │ └── settings.py
│ │ └── urls.py
│ │ └── uwsgi.log
│ │ └── views.py
│ │ └── wsgi.py
│ │
│──── ──├── migrations
│ │
│ ├── project
│ │ └── __init__.py
│ │ └── settings.py
│ │ └── urls.py
│ │ └── uwsgi.log
│ │ └── views.py
│ │ └── wsgi.py
│ │
│ └── manage.py
│ └── uwsgi.ini
└── static
Dockerfile
FROM python:3.8-alpine
ENV PYTHONUNBUFFERED 1
ENV PYTHONIOENCODEING utf-8
ENV APP_PATH code
# /$APP_It is also possible with PARH, but this time it is described because it is bug avoidance and practice.
WORKDIR /code
# /code is$APP_Also possible with PATH
COPY ./requirements.txt /$APP_PATH
RUN apk add --no-cache --virtual .build-deps bash gcc musl-dev libffi-dev \
g++ libgcc libstdc++ libxml2-dev libxslt-dev openssl-dev curl \
&& apk add --no-cache --virtual --update-cache\
jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
mariadb-dev mariadb-connector-c-dev \
&& pip install cython && pip install -U pip && pip install -r requirements.txt
RUN rm -rf /var/cache/apk/* && \
rm -rf /tmp/*
Let's review here again. As for FROM and ENV, I will take away the first appearance as it is like a spell. First, the notation alpine. It's like Alpine Linux, an ultra-lightweight version of Linux. And since Docker is like a book of Linux, trying to reduce the weight of the image in Docker based on this is like -alpine notation ... .. In addition, there is also -slim notation, and with -alpine, it seems that some packages such as Numpy may have a problem when building with Docker. This is because C-type processing is built into such a package, but the image of alpine notation is For the time being, let's just understand that the alpine notation in Docker makes the image lighter.
Next, WORKDIR and COPY, WORKDIR is the specification of the working directory in the virtual environment. Later, I will set it with docker-compose.yml, but this time I will share the src folder on the host side and the code folder of the virtual environment, that is, the project folder of the application will be expanded in this .. COPY is a command to copy the files in the path to the folder specified by $ APP_PATH in the virtual environment. Since the path on the host side is specified based on the directory where the Dockerfile is located, that is, the location one step down from the parent folder seen from the Dockerfile is specified, so it is as described above.
After that, install various packages with RUN, mainly for avoiding errors in C processing caused by using alpine (up to gcc ~ libxslt-dev) and connectors for connecting to MariaDB. Finally, put cython (accelerated Python using C language know-how) with pip, upgrade pip, and install the package described in requirements.txt.
requirements.txt
Django==3.0
django-bootstrap4
flake8==3.7.9
ipython==7.10.1
mysqlclient==1.4.6
Pillow==6.2.1
uwSGI==2.0.18
dj-static
whitenoise
I've included it as a trial, Django, django-bootstrap4, and mysqlclient are enough to use it at the level where you start studying like me. Since uwSGI is implemented as a reference source, I will try it because it is a big deal.
A module for simply writing Bootstrap registration / correction forms in Python. To explain how to use it in detail, it is necessary to understand the mechanism of View in Django a little more, so let's move on with the understanding that if you use bootstrap 4 with Django, you should include it.
mysqlclient
Modules needed to connect to MySQL with Python
Simply put, it's an AP server, or application server. Up to this point, I have been learning with a fluffy understanding that I have to prepare for the Web server and application server for the time being. This time I had the opportunity to get into the technology called uWSGI, so I delved a little deeper based on the following reference articles.
Differences between web server and application server in Rails development (translation) Introduction to uWSGI About "uWSGI" and Application Server I will explain the difference between a web server and an application server in an easy-to-understand manner What is the role of the AP server? Let's understand the difference from the Web server
When I put it together
・ What is WSGI?
→ Abbreviation for "Web Server Gateway Interface", which is a rule of communication between a Python web application and a web server ... In other words, a protocol. Of course, communication is not possible without a protocol, but apparently the problem is that the framework's support and non-support for Web servers are different. In Python, it seems that the background of WSGI introduction is that by creating a common protocol in this way, any framework that supports WSGI can be operated.
・ Then what is uWSGI?
→ It is a kind of application server that supports WSGI. You can use HTTP communication and UNIX domain socket communication methods, but I'll leave this as it can't be helped if I dig deeper now.
・ What are Web servers and application servers in the first place?
→ The Web server is for performing some processing after receiving a request from the user. In other words, unless you are in a local environment, the image is that the sent request basically first goes to the Web server and decides what to do with it. Except for dynamic requests (requests for things that can change frequently such as CSS, Javascript, images, videos), you can process them here. Conversely, when those requests come in, it can be said that it has the role of passing the requests to the application server. Of course, in CSS and images, if they are static, you can process them here.
So, what is an application server? In short, it is the one that runs the application. Requests and responses are passed where it is easy to understand. Taking the login process as an example
It turns out that. I felt that even one login is actually a rather complicated process.
docker-compose.yml
version: '3.7'
volumes:
django.db.volume:
name: django.db.volume
services:
nginx:
image: nginx:1.13
container_name: app_nginx
ports:
- "8000:8000"
volumes:
- ./nginx/conf:/etc/nginx/conf.d
- ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
- ./static:/static
- ./nginx/log:/var/log/nginx
depends_on:
- python
db:
tty: true
image: mariadb:10.1
container_name: app_mariadb
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
TZ: 'Asia/Tokyo'
volumes:
- django.db.volume:/var/lib/mariadb
- ./db/sql:/docker-entrypoint-initdb.d
python:
build: ./python
image: python_blog
container_name: app_python
command: uwsgi --ini /code/project/uwsgi.ini
environment:
- DATABASE_HOST=db
volumes:
- ./src:/code
- ./static:/static
- ./python:/code/python
expose:
- "8888"
depends_on:
- db
As a recap, the path specification in volumes is only host side: virtual environment side
and tty: true
is a description that keeps the container up.
This time, I was addicted to the swamp because I was dealing with Docker on Windows, or because of the system of Docker's container, it was quite difficult to eliminate the connection error to the DB.
As a result of the investigation, both of them were raised as the reason, but I think that the reason for the latter is that I reflected the change and terminated Docker with down.
Anyway, this time, in the volume of DB, prepare a directory to store DB information on the host side and share it to hold DB data in Docker.
First of all, in order to do volume mount at the beginning, I solved it by making it only for persistence of mariadb container.
By the way, django.db.volume doesn't exist in the directory on the Windows side? However, in the case of Docker Toolbox, this is very complicated, that is
Windows ⇒ Virtual Box ⇒ Docker == Main host ⇒ Host seen from Docker (guest when viewed from Windows) ⇒ Guest
That's the relationship, and since the Volume created this time is in Virtual Box, it will not be displayed on Windows, which is confusing. Anyway, one of the advantages of Docker is that you can easily create and delete containers, but if data such as DB is not persisted, it will cause a connection error, so be sure to make it a means of persistence. Let's take it. By the way, if you are using dokcer-compose.yml, you should probably make various changes and updates by playing with this instead of Dockerfile, but in that case, remember that build can be reflected in up without needing it. It was. In the case of Dockerfile, build is required, so if you do not make DB persistent, you will probably get an error (experienced)
For nginx, write the settings in the conf file and prepare a parameter file for uWSGI.
app_nginx.conf
upstream django {
ip_hash;
server python:8888;
}
# configuration of the server(Server configuration)
server {
# the port your site will be served on
listen 8000;
# the domain name it will serve for
server_name 127.0.0.1; # substitute your machine`s IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M;
location /static {
alias /static;
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
}
}
Access is first received on port 8000. Next, if it is a request to a static file, pass it to static of nginx. If you need to pass the request to another application server (uWSGI), skip the request to port 8888. Don't forget to specify the directory where the uWSGI parameter files are located at the end.
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
It's a so-called spell.
If you want to install additional packages during development, you can go directly into the container and do python -m pip install
, but since I made requirements.txt
, I will use this I want to do it.
However, if nothing is done, an error will occur even if you use python -m pip install requirements.txt
, for example.
Did you do COPY
and ʻADD` in DockerFile? I had a question, so I decided to check it for the time being.
# docker exec -it app_find from python bash./Command execution result
./
./project
./project/app
./project/app/admin.py
./project/app/apps.py
./project/app/migrations
./project/app/migrations/0001_initial.py
./project/app/migrations/0002_sampledb.py
./project/app/migrations/__init__.py
./project/app/migrations/__pycache__
./project/app/migrations/__pycache__/0001_initial.cpython-38.pyc
./project/app/migrations/__pycache__/0002_sampledb.cpython-38.pyc
./project/app/migrations/__pycache__/__init__.cpython-38.pyc
./project/app/models.py
./project/app/tests.py
./project/app/urls.py
./project/app/views.py
./project/app/__init__.py
./project/app/__pycache__
./project/app/__pycache__/admin.cpython-38.pyc
./project/app/__pycache__/apps.cpython-38.pyc
./project/app/__pycache__/models.cpython-38.pyc
./project/app/__pycache__/urls.cpython-38.pyc
./project/app/__pycache__/views.cpython-38.pyc
./project/app/__pycache__/__init__.cpython-38.pyc
./project/manage.py
./project/media
./project/polls
./project/polls/admin.py
./project/polls/apps.py
./project/polls/migrations
./project/polls/migrations/0001_initial.py
./project/polls/migrations/0002_auto_20200408_1848.py
./project/polls/migrations/__init__.py
./project/polls/migrations/__pycache__
./project/polls/migrations/__pycache__/0001_initial.cpython-38.pyc
./project/polls/migrations/__pycache__/0002_auto_20200408_1848.cpython-38.pyc
./project/polls/migrations/__pycache__/__init__.cpython-38.pyc
./project/polls/models.py
./project/polls/tests.py
./project/polls/urls.py
./project/polls/views.py
./project/polls/__init__.py
./project/polls/__pycache__
./project/polls/__pycache__/admin.cpython-38.pyc
./project/polls/__pycache__/apps.cpython-38.pyc
./project/polls/__pycache__/models.cpython-38.pyc
./project/polls/__pycache__/tests.cpython-38.pyc
./project/polls/__pycache__/urls.cpython-38.pyc
./project/polls/__pycache__/views.cpython-38.pyc
./project/polls/__pycache__/__init__.cpython-38.pyc
./project/project
./project/project/settings.py
./project/project/urls.py
./project/project/uwsgi.log
./project/project/views.py
./project/project/wsgi.py
./project/project/__init__.py
./project/project/__pycache__
./project/project/__pycache__/settings.cpython-38.pyc
./project/project/__pycache__/urls.cpython-38.pyc
./project/project/__pycache__/views.cpython-38.pyc
./project/project/__pycache__/wsgi.cpython-38.pyc
./project/project/__pycache__/__init__.cpython-38.pyc
./project/templates
./project/templates/admin
./project/templates/admin/base_site.html
./project/templates/admin/index.html
./project/templates/app_folder
./project/templates/app_folder/page01.html
./project/templates/app_folder/page02.html
./project/templates/app_folder/top_page.html
./project/templates/base.html
./project/templates/polls
./project/templates/polls/detail.html
./project/templates/polls/index.html
./project/templates/polls/results.html
./project/uwsgi.ini
The find ./
command is a Linux command, which means search and display directories under the root folder
.
I've also mixed some files for the Django tutorials from this article onwards, but a closer look reveals that requirements.txt
is missing.
In DockerFile, it is COPY ./requirements.txt / code
and it is a container created based on that image, but I do not understand why.
However, one thing I have in mind is that my understanding of the docker-compose run
command was too diverse and too diverse, resulting in an infinite number of containers ...
If anyone knows, please let me know.
Now, the solution for now is to mount requirements.txt
on the container.
So I added the description of ./python:/code/python
to docker-compose.yml
.
Now you can do ʻup, enter with the
docker execcommand, and do
pip install -r ./python/requirements.txt`, so you can install additional packages.
When you're ready, try creating a container with docker-compose up -d --build
.
As a recap, the -d option keeps the container running in the background.
…… It's okay to do it, but if you start it up as it is, it won't actually start up well.
The reason is that uWSGI is not ready yet.
If you look at docker-comopose.yml
again, you'll see that the nginx and python containers have depend_on specified.
We've previously learned that this is an indication of container dependencies.
In other words, the nginx and python containers cannot be started unless the db container is started.
However, the essential db server does not work without the application server, so uWSGI is not ready now and the container does not start ... This is what happens.
So, first create a Django project and create a uwsgi config file.
docker-compose run --rm python django-admin.py startproject project
The run command ** creates a new container ** and executes the specified command.
So ** If you use it a lot, you can create an infinite number of containers **.
So be sure to use the --rm
command unless you have a specific intention.
By the way, there is also a command called docker-compose exec $ {service_name} $ {command}
that executes the command in the running container.
For example, if you do docker-compose exec python bash
, you can enter the container of the python service and execute the bash command there.
Now, after run, specify the docker-compose.yml
set service name and the spell that will generate the Django project.
Then, a folder with the name specified after start project
will be created in the area specified by WORKDIR.
And finally the container is deleted with the --rm
command.
However, since the result of django-admin.py startproject project
remains on the host side, it can be reflected in the subsequent container startup, so there is no problem.
uwsgi.ini
[uwsgi]
socket = :8888
module = project.wsgi
wsgi-file = /code/project/project/wsgi.py
logto = /code/project/project/uwsgi.log
chdir=/code/project
py-autoreload = 1
After that, create a configuration file as described above and place it in the same directory as manage.py
of the created project file.
What is written is the port used by uWSGI, the log file, and the location of the wsgi file.
As an aside, keep in mind that Django projects always base their directory to manage.py
and execute commands.
When you're done so far
$ docker-compose up -d
$ docker ps -a
And cast the spell. You can see the list of containers with the last spell, so make sure that 3 containers are up and all are up. As I mentioned at the beginning, when using MySQL with docker, it sometimes happens that it does not become up here but immediately becomes exit. This time, I think that there is no problem because I have taken measures that can be done so far, but personally I thought that it is better to prepare the following table first before casting the spell here. ..
sql:./db/sql/init.sql
CREATE DATABASE IF NOT EXISTS Arbitrary database name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS 'Any username'@'%' IDENTIFIED BY 'password';
Database name specified on GRANT ALL PRIVILEGES ON.* TO 'Database name specified above'@'%';
FLUSH PRIVILEGES; #will not forget
A spell with the familiar SQL style.
MySQL always creates a database and a user, and if you do not first give the created user full rights in that database (it can also be given in table units), you will be in a bad mood, so set this first I will do it.
By the way, the user name and password on the second line can also be set in docker-compose.yml
.
This time, the root password of MySQL is set in the part MYSQL_ROOT_PASSWORD: root
.
This time we will give full rights to the entire database, so set the root user.
By the way, the user name and password are set as root, but of course this is allowed because it is local, and in the production environment it is too unpleasant for security, so let's set it properly.
As you can see by writing so far, the point is that this is the SQL initialization file.
Once you've got this far, let's take a look at the Django config file.
project/project/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_test',
'USER': 'root',
'PASSWORD': 'root',
'HOST': 'db',
'PORT': '3306',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
}
}
#Omission
STATIC_ROOT = '/static'
STATIC_URL = '/static/'
You can almost understand what is written.
It seems that the ENGINE part may be different depending on the version of Django, but in that case please rewrite it to an appropriate one.
After that, set the database name and items related to the root user.
For the HOST part, set the service name of the container that contains the database specified in docker-compose.yml
, and for PORT, set the port specified there as well.
OPTION is a spell.
'init_command':" SET sql_mode ='STRICT_TRANS_TABLES' "
It is recommended to specify this here, so let's set it.
It seems to be a mode that solves many data integrity problems in MySQL.
By the way, I got an error if I didn't set it.
The last part is the directory setting of the static file, otherwise the static file will not be read.
When you're done so far
Enter the container with docker exec -it app_python bash
cd ./project/
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
Let's cast the spell. If the migration is completed successfully without throwing an error here, it means that the database access was successful, so let's create a container with up -d earlier.
Once you've done that, it's time to set up Django. Before that, first create an application folder in the project
Enter the container with docker exec -it app_python bash
cd ./project/
python manage.py startapp folder name
After executing, set settings.py
as follows.
project/project/settings.py
"""
Django settings for project project.
Generated by 'django-admin startproject' using Django 2.1.5.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '&$l0ho%f&-w%&t_2l=@98u(i_58t15d-jn+ln5fuyvy(^l88^t'
# 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',
'app.apps.AppConfig', #add to
'bootstrap4' #add to
]
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',
'whitenoise.middleware.WhiteNoiseMiddleware', #add to
]
ROOT_URLCONF = 'project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], #Specify the directory of the folder containing the html 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',
],
'builtins':[
'bootstrap4.templatetags.bootstrap4',#Add here!
],
},
},
]
WSGI_APPLICATION = 'project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_test',
'USER': 'root',
'PASSWORD': 'root',
'HOST': 'db',
'PORT': '3306',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8mb4',
},
}
}
# Password validation
# https://docs.djangoproject.com/en/2.1/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/2.1/topics/i18n/
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = '/static'
# Custom User
AUTH_USER_MODEL = 'app.User'
#Media file settings
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
When excerpting
'app.apps.AppConfig', #add to
'bootstrap4' #add to
apps.py
from django.apps import AppConfig
class AppConfig(AppConfig):
name = 'app'
This part specifies the location of ʻapps.py above. As you can see, ʻapps.py
imports the ʻAppConfig object of the
django.appsmodule. Don't forget to set
name ='application folder name'where you created the class below. By the way, if you do not add
'app.apps.AppConfig'` after creating the application folder, an error will be thrown (experience story).
The bottom part is the setting for using bootstrap with Django, so add this as well.
'builtins':[
'bootstrap4.templatetags.bootstrap4',#Add here!
],
Don't forget to add this as it is also a specification for using bootstrap.
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
Specify the time zone and Djnago setting language.
# Custom User
AUTH_USER_MODEL = 'app.User'
It is a setting for the custom user to be created later.
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
It becomes the access setting of the media file. It is used when implementing the upload function and the function to display the uploaded file as content on the screen in the application. This completes the basic preparations for using Django.
From here, we will create a template. Since Django is a framework, it's made up of MVC models like Laravel. This is called the MVT model in Django.
In other words, it's a Model / Tenmplaete / View model
.
As a role
Model: Database control Template: Control the screen. View's role in MVC model View: The role of the overall control. Role of controller in MVC model
It will be. Note that the View in the MVC model and the View in the MTV model have different roles. Therefore, Django can also use templates, so we will set them.
template/base.html
<!DOCTYPE html>
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='slim' %}
{% load static %}
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type='text/css' href="{% static 'css/style.css' %}">
<link rel="stylesheet" href="https://cccabinet.jpn.org/bootstrap4/css/style.css">
<title>Django development sample</title>
{% block extra_css %}{% endblock %}
</head>
<body>
<!-- navbar -->
<div class="container">
<div class="row">
<div class="col-12">
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bs-navbar" style="background-color:cadetblue;" id='bs-navbar'>
<a class="navbar-brand mr-md-2" href="/app/top_page">
Sample development screen
</a>
<!-- layout_dammy -->
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a class='nav-link' href="#"></a></li>
<li class="nav-item"><a class='nav-link' href="#"></a></li>
</ul>
<!-- layout -->
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="/#">Sample 1</a></li>
<li class="nav-item"><a class="nav-link" href="/#">Sample 2</a></li>
<li class="nav-item"><a class="nav-link" href="/#">Sample 3</a></li>
<li class="nav-item"><a class="nav-link" href="/accounts/login">Login</a></li>
<li class="nav-item"><a class="nav-link" href="/accounts/logout">Log out</a></li>
</ul>
</nav>
</div><!-- /.col-12 -->
</div><!-- /.row -->
</div>
<!-- sidebar&main-contents -->
<div class="container-fluid" id="content">
<div class="row flex-xl-nowrap">
<!-- sidebar -->
<div id="sidemenu" class="col-2 d-none d-md-block bg-light sidebar align-self-start">
<div class="sidebar-sticky">
<ul class='nav flex-column'>
<li class="nav-item">
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="/#">
<span data-feather=""></span>TOP page
</a>
</nav>
</li>
<li class="nav-item">
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="/#">
<span data-feather=""></span>Sidebar 1
</a>
</nav>
</li>
<li class="nav-item">
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="/#">
<span data-feather=""></span>Sidebar 2
</a>
</nav>
</li>
<li class="nav-item">
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="/#">
<span data-feather=""></span>Sidebar 3
</a>
</nav>
</li>
<li class="nav-item">
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="/#">
<span data-feather=""></span>Sidebar 4
</a>
</nav>
</li>
<li class="nav-item">
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="/#">
<span data-feather=""></span>Sidebar 5
</a>
</nav>
</li>
</ul>
</div><!-- /.sidebar-sticky -->
</div><!-- /#sidemenu -->
<div class="col-10">
{% block contents %}
{% endblock %}
</div><!-- /.col-10 -->
</div><!-- /.row -->
</div><!-- /#content -->
</body>
</html>
<!-- sidebar-icon -->
<!-- use-icon: https://voyager-jp.com/blog/javascript/feather/ -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/feather-icons/4.9.0/feather.min.js"></script>
<script>feather.replace()</script>
First, create a template for the part common to each page.
It's a header or a navigation bar.
Notations like {%%}
are spells used in templates.
Here are some excerpts
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='slim' %}
{% load static %}
Loads the bootstrap module, jQuery, and static files. If you don't specify it, bootstrap will not be applied, so don't forget. If there is a spell like a command like this
<link rel="stylesheet" type='text/css' href="{% static 'css/style.css'%}">
You can also use it to simplify the path specification. By the way
{% block %}
{% endblock %}
That is the designation of the area. For example
{% block extra_css %}{% endblock %}
This means that block
to ʻendblock will be changed to
block named ʻextra_css
.
The block
specified in this way becomes the default value, and when it is inherited by the child template below
The area if the name of block
is not specified, such as{% block%} ~ {% endblock%}
, or if{% block extra_css%} {% endblock%}
is specified. Will be inserted.
Therefore
{% block contents %}
{% endblock %}
If you cast a spell like the one above, you can see that the part of the child template that casts the same spell is inserted.
By the way, this time I'm loading Bootstrap on the CDN, but there are various problems with the CDN, so if possible I would like to download the package and load the one that I put locally.
After that, I will make a child template
templates/app_folder/top_page.html
{% extends 'base.html' %}
{% block contents %}
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center mt-5 border-bottom">
<h1 class="h2">top page</h1>
</div>
<div>
<h4>Describe the content here</h4>
</div>
{% endblock %}
templates/app_folder/page01.html
{% extends 'base.html' %}
{% block contents %}
<h4 class="mt-5 mb-4 border-bottom">Enter search conditions</h4>
<form action="{% url 'app:top_page' %}" method="post">
<div class="container-fluid">
<div class="row">
<div class="col-2">
<input class="form-control" type="next" name="input_data" maxlength="255">
</div><!-- /.col-2 -->
<div class="col-2">
<div class="text-left align-bottom">
<button type="submit" name="button" class="btn btn-info">
Search
</button>
</div><!-- /.text-left -->
</div><!-- /.col-2 -->
</div><!-- /.row -->
</div><!-- /.container-fluid -->
{% csrf_token %}
</form>
{% endblock %}
templates/app_folder/page02.html
{% extends 'base.html' %}
{% block contents %}
<h4 class="mt-5 mb-4 border-bottom">Display DB search results</h4>
<div class="container-fluid">
<div class="row">
<div class="col-4">
<p>sample1:{{result_sample1}}</p>
<p>sample2:{{result_sample2}}</p>
</div>
</div>
</div>
{% endblock %}
The {% extends'base.html'%}
spell inherits the previous parent template.
The contents of page01 and page02
・ Receive search conditions from the input form on the screen -Obtain data from DB based on search conditions -Pass the acquired data to the template (screen)
It means that you have created a UI to perform the process on the management screen.
Now that the template is finished, set the View and the Model as well.
Quoting from the article of the planner listed in the reference article
app_config / views.py: Rough control over the whole app_folder / views.py: Control individual features
Note that the same views.py
as, but with different roles, which is confusing.
By the way, this time
ʻApp_config / views.py is
project / project / views.py (located in the same directory as settings.py). Replace ʻapp_folder / views.py
with project / app / views.py
.
project/project/views.py
from django.shortcuts import render, redirect, reverse
from django.views import View
class index(View):
def get(self, request, *args, **kwargs):
return redirect(reverse('app:top_page'))
index = index.as_view()
If the system is accessed, it will be skipped to the top page.
project/app/views.py
from django.shortcuts import render
from django.views import View
from .models import SampleDB
class SampleView(View):
def get(self, request, *args, **kwargs):
return render(request, 'app_folder/page01.html')
def post(self, request, *args, **kwargs):
input_data = request.POST['input_data']
result = SampleDB.objects.filter(sample1=input_data)
result_sample1 = result[0].sample1
result_sample2 = result[0].sample2
context={'result_sample1':result_sample1, 'result_sample2':result_sample2}
return render(request, 'app_folder/page02.html', context=context,)
top_page = SampleView.as_view()
Be careful of typos.
Don't make a mistake because from and import at the beginning are spells. The last part is to import the table objects from the Model.
def get(self, request, *args, **kwargs):
return render(request, 'app_folder/page01.html')
The render method will be a method that returns an HttpResponse object. By setting a request in the argument and specifying the path of the screen where you want to return the result in the second argument, the result including the information around session will be returned there.
def post(self, request, *args, **kwargs):
input_data = request.POST['input_data']
result = SampleDB.objects.filter(sample1=input_data)
result_sample1 = result[0].sample1
result_sample2 = result[0].sample2
context={'result_sample1':result_sample1, 'result_sample2':result_sample2}
return render(request, 'app_folder/page02.html', context=context,)
This is the method to receive the POST request from the input form. In the context variable, the process is to map from the "variable name" passed to the template to the "variable value" and pass it to the variable with the render method. You will return it to ʻapp_folder / page02.html`.
It's just right, so let's set the Model here as well.
project/app/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class SampleDB(models.Model):
class Meta:
db_table = 'sample_table' # tablename
verbose_name_plural = 'sample_table' # Admintablename
sample1 = models.IntegerField('sample1', null=True, blank=True) #Variables and settings to store numbers
sample2 = models.CharField('sample2', max_length=255, null=True, blank=True) #Variables and settings to store strings
Each class is each table.
In other words, if you write like this, the User table and SampleDB will be created.
Since the table used in the template created this time is SampleDB, create a class, set models.Model
as an argument, and write the table settings under class Meta.
db_table = 'sample_table' # tablename
verbose_name_plural = 'sample_table' # Admintablename
This part is the setting of the table name and the table name displayed on the management screen.
sample1 = models.IntegerField('sample1', null=True, blank=True) #Variables and settings to store numbers
sample2 = models.CharField('sample2', max_length=255, null=True, blank=True) #Variables and settings to store strings
By writing like this, you will set the data of the table. In other words, this table will store ID and string data.
Set the URL required to access the system from the web screen. Is it a routing setting in Laravel?
Just like views.py
app_config / urls.py: System-wide URL design app_folder / urls.py: URL design within individual apps
Please note that it has the same file name as and has a different role. By the way, this time
ʻApp_config / views.py is
project / project / urls.py (located in the same directory as settings.py). Replace ʻapp_folder / views.py
with project / app / urls.py
.
project/app/urls.py
from django.urls import path
from . import views
# URL_setting
app_name = 'app'
urlpatterns = [
path('top_page/', views.top_page, name='top_page')
]
Write the path of each page in the part of ʻurl patterns`. This time, only the TOP page is created (page01 and page02 are excluded because they are templates for the management screen), so there is only one.
project/project/urls.py
"""project URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from . import views
urlpatterns = [
#URL to access the management site
path('admin/', admin.site.urls),
#URL to access the application "app" created this time
path('app/', include('app.urls')),
#If you do not specify any URL (app_config/views.With py, "app" automatically_(Already set to access "folder")
path('', views.index, name='index'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Finally, create a management screen.
Because you have to create an admin user for that
Enter the container with docker exec -it app_python bash
cd ./project/
python manage.py createsuperuser
And cast the spell. What do you set your user name, email address, and password to when you get stuck? You will be asked, so please set it arbitrarily. Next is the setting of the management site.
project/app/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
from.models import SampleDB
admin.site.register(User, UserAdmin)
admin.site.register(SampleDB)
The management site is
Normally, you need to learn MySQL etc. to operate DB Even though Python (Django) is full, MySQL is impossible. .. Let's operate the DB on the screen from the management site!
So, set it as above according to the table to be used.
Now let's boot the system.
Before that, migrate the table and apply css at the management site.
I did the migration once a long time ago, but since I have defined a new SampleDB table, I will do it again.
This is the spell.
Enter the container with docker exec -it app_python bash
cd ./project/
python manage.py migrate
Next is the application of css. This would be done when using uWSGI. The spells are:
python manage.py collectstatic
Finally when it's done safely
python manage.py runserver
The system is started.
If no error is thrown, the startup is completed successfully. Thank you for your hard work.
If that doesn't work, try docker-compose up -d
again or see the error message as appropriate.
You can see how it works when you have lived the experience of doing Laravel. However, after all, I'm going to use the built-in method of the template and how to write the spell of the Model part in the first place, and I can not remember unless I check it each time and repeat the input and output steadily. I felt the same as when I made the portfolio in. Since I will dare to participate in the project this time with the skill level of Laravel on the shelf, I will understand Django and the skill level of the Web knowledge that accompanies it so that I can steal even a little contribution and stealing in the project. I hope it can be raised even a little. First, take a look at Django's official tutorial.
Articles that enable system development with Django (Python)_Introduction Create a django environment with docker-compose (MariaDB + Nginx + uWSGI) Docker-Compose with Python3.6 + NGINX + MariaDB10 + uWSGI's Django environment greedy set Differences between web server and application server in Rails development (translation) Introduction to uWSGI About "uWSGI" and Application Server I will explain the difference between a web server and an application server in an easy-to-understand manner What is the role of the AP server? Let's understand the difference from the Web server