使用Docker Compose构建开发环境(NGINX + uWSGI + PostgreSQL)来开发Web应用程序
首先
使用Docker Compose搭建包含NGINX、uWSGI和PostgreSQL运行的Docker容器,记录在浏览器上验证通过Django(Python)开发的Web应用程序的步骤。
※此文章基于Mac OS。
正在使用macOS Catalina 10.15.3进行操作。
本投稿では、NGINX、uWSGI、PostgreSQLが動作するDocker コンテナを
構築します。2NGINXWebサーバです。
本投稿では、ここに静的ファイルを配置します。3uWSGIアプリケーションサーバです。
Pythonで作成したWebアプリケーションを配置します。4PostgreSQLDBサーバです。
Webアプリケーションで利用するデータを保持します。5DjangoPythonのWebフレームワークです。
前提条件
在下载Docker for Mac时,需要在Docker官方网站上登录。请创建一个用于登录Docker官方网站的用户。
1. Mac上的Docker
首先,我们将安装Docker for Mac。
Docker Compose已经包含在Docker for Mac中。
1-1. 下载
我将从以下网站进行下载:
https://docs.docker.com/docker-for-mac/install/
1-2. 安装
请运行下载的 Docker.dmg 文件。
请在应用程序中执行Docker。
1-3. 确认
打开终端,并执行命令 “docker –version”。
检查已安装的Docker版本。
$ docker --version
Docker version 19.03.5, build 633a0ea
接下来,执行命令”docker-compose –version”来检查Docker Compose的版本。
$ docker-compose --version
docker-compose version 1.25.4, build 8d51620a
构建 Docker 容器
构建一个包含NGINX、uWSGI和PostgreSQL的Docker容器。
创建工作目录
请创建一个任意的工作目录。
在本文中,我们将创建一个名为”django”的目录。
$ mkdir django
2-2. 准备文件/目录。
准备执行Docker Compose所需的文件以及Web应用程序的源代码存放目录等。
(1) 切換至作業目錄
$ cd django
(2) 创建 requirements.txt
$ touch requirements.txt
(3) 创作 Dockerfile
$ touch Dockerfile
(4) 创建 docker-compose.yml
$ touch docker-compose.yml
创建nginx目录
$ mkdir nginx
创建 nginx/conf 目录
$ mkdir nginx/conf
创建 nginx/conf/mainproject_nginx.conf。
$ touch nginx/conf/mainproject_nginx.conf
(8) 创建 nginx/uwsgi_params 文件
$ touch nginx/uwsgi_params
(9) 创建 src 文件夹
$ mkdir src
(10) 创建 src/static 文件夹
$ mkdir src/static
创建dbdata目录
$ mkdir dbdata
[文件/目录的说明]
※ ファイル名は任意です、拡張子は”.conf”にして下さい。7nginx/uwsgi_paramsNGINXとuWSGIを連携させるためのファイル8srcWebアプリケーションを配置するディレクトリ9src/staticcss、JavaScript、画像などの静的ファイルを配置するディレクトリ10dbdataPostgreSQLのデータファイルを保持するディレクトリ
[文件结构至此]
$ tree .
.
├── Dockerfile
├── dbdata
├── docker-compose.yml
├── nginx
│ ├── conf
│ │ └── mainproject_nginx.conf
│ └── uwsgi_params
├── requirements.txt
└── src
└── static
5 directories, 5 files
2-3. 設定 requirements.txt 的要求
打开requirements.txt文件,写入以下内容并保存。
requirements.txt文件会在接下来解释的Dockerfile中被使用。
(即在”RUN pip install -r requirements.txt”这一行)
Django
django-bootstrap4
uwsgi
psycopg2
以下是一种可能的中文翻译:
[说明]
① Django
安装Python的Web框架Django。
② django-bootstrap4
安装用于在Django中使用Bootstrap4的包。
※如果不使用Bootstrap4,则无需安装。
最后,将介绍如何在Django创建的页面中应用Bootstrap4。
③ uwsgi
安装应用程序服务器。
④ psycopg2
安装用于从Python连接到PostgreSQL的驱动程序。
2-4. Dockerfile的配置方式
打开Dockerfile并写下以下内容后保存。
Dockerfile将在接下来介绍的docker-compose.yml中使用。
(位于”build: .”的部分)
FROM python:3.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY requirements.txt /code/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
COPY . /code/
[說明]
① 從python:3.7開始
在Docker的基本映像中指定”python3.7″
從”Docker Hub”的映像創建。
② ENV PYTHONUNBUFFERED 1
設定Python的標準輸出和標準錯誤輸出不緩衝。
如果緩衝區被啟用,將不顯示標準輸出的中間狀態,
而會在所有任務完成後一起顯示。
③ RUN mkdir /code
在容器中創建代碼目錄。
④ WORKDIR /code
將代碼目錄指定為容器的工作目錄。
⑤ COPY requirements.txt /code/
將本地機器的requirements.txt添加到容器的代碼目錄中。
⑥ RUN pip install –upgrade pip
將容器中的pip升級到最新版本。
⑦ RUN pip install -r requirements.txt
在容器中安裝requirements.txt中列出的Python包(庫)。
⑧ 將本地機器的當前目錄內容添加到容器的代碼目錄中。
2-5. docker-compose.yml的配置
打开docker-compose.yml文件,将以下内容写入并保存。
version: '3.7'
volumes:
pgdata:
driver_opts:
type: none
device: $PWD/dbdata
o: bind
services:
nginx:
image: nginx
container_name: container.nginx
ports:
- "8000:8000"
volumes:
- ./nginx/conf:/etc/nginx/conf.d
- ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
- ./src/static:/static
- ./nginx/log:/var/log/nginx
depends_on:
- web
web:
build: .
container_name: container.uwsgi
command: uwsgi --ini /code/mainproject/django.ini
volumes:
- ./src:/code
expose:
- "8001"
depends_on:
- db
db:
image: postgres
restart: always
container_name: container.postgres
ports:
- "5432:5432"
environment:
POSTGRES_DB: "postgresdb"
POSTGRES_USER: "admin"
POSTGRES_PASSWORD: "test"
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=C"
volumes:
- pgdata:/var/lib/postgresql/data
hostname: postgres
[说明]
①版本:’3.7′
这是用于docker-compose的版本。
每个版本的docker-compose.yml的写法都不同。
※有关与Docker本身版本的关联,请参阅“Compose file version 3 reference”。
②卷:
顶级卷是指具有名称的卷。
在这里,指定了名为“pgdata”的具名卷。
“device: $PWD/dbdata”表示本地机器的工作目录下的dbdata目录。
③服务:
描述要构建的容器。
在这里,描述了”nginx”、”web”和”db”。
这个名称是可以任意指定的。
例如,”db”也可以是”database”等。
③-1 nginx:
③-1-1 image: nginx
NGINX运行的容器将从”Docker Hub”的映像中创建。
③-1-2 container_name: container.nginx
给容器指定一个任意的名称”container.nginx”。
③-1-3 ports:
将8000端口指定给NGINX的端口号。
③-1-4 volumes:
设置本地机器的工作目录下的每个文件/目录
和NGINX容器的文件/目录的挂载。
a) ./nginx/conf:/etc/nginx/conf.d
这将使”nginx/conf/mainproject_nginx.conf”挂载到”/etc/nginx/conf.d”。
放置在”/etc/nginx/conf.d”的扩展名为”.conf”的文件,
将由父配置文件”/etc/nginx/nginx.conf”加载。
* “/etc/nginx/nginx.conf”在nginx容器中是默认存在的。
b) ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
“/etc/nginx/uwsgi_params”在接下来的”nginx/conf/mainproject_nginx.conf”中使用。
(位于”include /etc/nginx/uwsgi_params;”的位置)
c) ./src/static:/static
挂载静态文件目录。
这是为了从NGINX提供css等文件。
d) ./nginx/log:/var/log/nginx
挂载日志文件目录。
这样,在本地机器上就可以查看日志。
③-1-5 depends_on:
在启动”web”,也就是uWSGI容器之后启动NGINX容器。
③-2 web:
③-2-1 build: .
用Dockerfile中记录的容器配置信息创建uWSGI运行的容器。
“build: .”表示使用的Dockerfile的路径。
换句话说,使用Dockerfile中记录的容器配置信息创建此容器。
③-2-2 container_name: container.uwsgi
给容器指定一个任意的名称”container.uwsgi”。
③-2-3 command: uwsgi –ini /code/mainproject/django.ini
在容器启动后,根据配置文件”/code/mainproject/django.ini”
启动uWSGI。
③-2-4 volumes:
设置本地机器的工作目录下的每个目录
和uWSGI容器的目录的挂载。
③-2-5 expose:
将8001端口指定给uWSGI的端口号。
③-2-6 depends_on:
在启动”db”,也就是PostgreSQL容器之后启动uWSGI容器。
③-3 db:
③-3-1 image: postgres
PostgreSQL运行的容器将从”Docker Hub”的映像中创建。
③-3-2 restart: always
在启动主机操作系统时自动启动容器。
③-3-3 container_name: container.postgres
给容器指定一个任意的名称”container.postgres”。
③-3-4 ports:
将5432端口指定给PostgreSQL的端口号。
③-3-5 environment:
a) POSTGRES_DB: “postgresdb”
指定容器启动时所创建的默认数据库名称。
如果不指定,则使用POSTGRES_USER的值。
b) POSTGRES_USER: “admin”
指定超级用户的名称。
如果不指定,则使用”postgres”。
c) POSTGRES_PASSWORD: “test”
指定超级用户的密码。
如果不指定,则使用POSTGRES_USER的值。
d) POSTGRES_INITDB_ARGS: “–encoding=UTF-8 –locale=C”
指定执行创建数据库的命令(postgres initdb)时使用的参数。
指定编码为”UTF-8″,区域设定为”C”。
※有关environment的详细信息,请参阅“Supported tags and respective Dockerfile links”。
③-3-6 volumes:
设置具名卷”pgdata”
和PostgreSQL容器的”/var/lib/postgresql/data”的挂载。
通过这个设置,数据库中的数据将持久保存。
(即使删除容器,数据也会保留在本地机器上。)
③-3-7 hostname:
给主机一个任意的名称”postgres”。
2-6. 主项目的nginx.conf配置
打开nginx/conf/mainproject_nginx.conf文件,将以下内容写入并保存。
# the upstream component nginx needs to connect to
upstream django {
ip_hash;
server web:8001;
}
# configuration of the server
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; # adjust to taste
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
}
}
[说明]
① 针对upstream django的细节设置我们不再赘述,关于”server web:8001;”,
它指的是在docker-compose.yml文件中所描述的名为web的服务(端口号为8001),
实际上指向的是uWSGI。
② server
对于”location / {“,我们也不再详细说明设置方法,
当NGINX接收到根目录的访问时,将会将请求传递给前面所描述的uWSGI进行处理。
此外,这里也与我们在③-1-4中解释的/etc/nginx/uwsgi_params配套进行协调。
而对于”location /static {“,
这是一个有关静态文件的设置,会使用NGINX的static目录下的文件。
2-7. 设置nginx/uwsgi_params的参数
打开nginx/uwsgi_params文件,写入以下内容并保存。
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;
2-9. 创建Django项目
执行以下命令,创建Django项目。
项目名称可以任意命名。(在此我们使用了“mainproject”作为名称。)
$ docker-compose run --rm web django-admin startproject mainproject .
尽管会输出以下警告:“由于图像不存在,因此进行了构建”,但这只是一个提示,没有问题。
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
[检查执行结果①(文件结构)]
文件结构如下所示。
由于在dbdata目录下会生成大量挂载的PostgreSQL数据(/var/lib/postgresql/data),我们进行了省略。
$ tree .
.
├── Dockerfile
├── dbdata
│ ├── PG_VERSION
│ ├── base
│ │ └── ・・・ 省略
│ │ └── ・・・ 省略
│ └── ・・・ 省略
├── docker-compose.yml
├── nginx
│ ├── conf
│ │ └── mainproject_nginx.conf
│ └── uwsgi_params
├── requirements.txt
└── src
├── mainproject
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── static
请执行”docker ps -a”命令,确认Docker容器的状态。
以下是正在运行的PostgreSQL容器示例。
请注意,由于尚未创建uWSGI Docker容器的ini文件,因此不会启动uWSGI Docker容器(位于docker-compose.yml的”command: uwsgi –ini /code/mainproject/django.ini”部分)。
请注意,NGINX Docker容器的启动是基于uWSGI Docker容器的启动作为前提条件,因此NGINX Docker容器尚未启动。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9d68d40adee0 postgres "docker-entrypoint.s…" 25 hours ago Up 25 hours 0.0.0.0:5432->5432/tcp container.postgres
创建uWSGI的ini文件。
请在src/mainproject下创建一个名为django.ini的新文件,并写入以下内容。
[uwsgi]
socket = :8001
module = mainproject.wsgi
wsgi-file = /code/mainproject/wsgi.py
logto = /code/mainproject/uwsgi.log
py-autoreload = 1
[说明]
① socket = :8001
指定启动uWSGI的端口号。
② module = mainproject.wsgi
指定要加载的wsgi模块。
③ wsgi-file = /code/mainproject/wsgi.py
指定要加载的wsgi文件。
④ logto = /code/mainproject/uwsgi.log
指定输出日志的位置。
用于查看应用程序发生错误时的日志。
⑤ py-autoreload = 1
指定自动重载功能的间隔。
在此设置中,如果有请求,则每秒重新加载一次。
※ 详细信息,请参阅「uWSGI Options」。
2-11. 进行ALLOWED_HOST、DB和静态文件的设置。
打开src/mainproject/settings.py文件,进行以下修改并保存。
(1) 添加import os
进行以下修正。
添加到开头的概述注释后面。
※2022/09/添加
如果不添加这个,将在运行wsgi.py时出现找不到os库的错误。
(修正后)
from pathlib import Path
(修正后)
import os
from pathlib import Path
(2)允许的主机设置
进行以下修正:
设置要公开的域名。
※在Django 1.5及更高版本的settings.py中,已添加了ALLOWED_HOSTS项目。
如果不设置它,在调试模式为true时会出错。
(修正后)
要求在中文中对以下内容进行同义转述,只需提供一种选项:
ALLOWED_HOSTS = []
(修订后)
ALLOWED_HOSTS = ["*"]
(3)连接到数据库的设置
将进行以下修改。
将与docker-compose.yml文件中的db环境相配合。
(修改前)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
(修正后)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgresdb',
'USER': 'admin',
'PASSWORD': 'test',
'HOST': 'db',
'PORT': 5432,
}
}
(4)静态文件配置
我们将进行以下修改。
(改正後)
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
(经过修正后)
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
# All applications can use Static files of this directory
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "mainproject/static/"),
)
# Collectstatic command put STATICFILES_DIRS and each application's Static files together into this directory
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
# Django template files read this directory to use Static files(example {% static 'style.css' %})
STATIC_URL = '/static/'
【说明】
① STATICFILES_DIRS
指定路径可任意设置。
在这里,我们指定了Django项目(mainproject)下的static目录,这在“2-9.创建Django项目”中有解释。
在这个目录下,我们将放置各个应用程序共用的静态文件。
稍后会提到,本篇文章中我们将放置网站图标(favicon)。
② STATIC_ROOT
在执行Collectstatic命令时,将收集STATICFILES_DIRS指定的共用静态文件以及各个应用程序下的static目录静态文件,并将它们放置在指定的目录中。
BASE_DIR指的是工作目录(src),因此STATIC_ROOT为src/static。
这与“2-5.配置docker-compose.yml”中解释的NGINX静态文件挂载源相匹配(即”-./src/static:/static”中的./src/static部分)。
③ STATIC_URL
是即将在Django模板文件中加载静态文件的目录。
与“2-5.配置docker-compose.yml”中解释的NGINX静态文件挂载目标相匹配(即”-./src/static:/static”中的/static部分)。
我认为如果将「Django静态文件」结合起来看,会更容易理解。
2-12. 开启 Docker 容器。
执行下列指令。
$ docker-compose up -d
请执行”docker ps -a”命令,以确认Docker容器的状态。
以下是NGINX、uWSGI、PostgreSQL容器的启动状态。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f41f7a5b634d nginx "nginx -g 'daemon of…" 10 minutes ago Up 10 minutes 80/tcp, 0.0.0.0:8000->8000/tcp container.nginx
c12eee7ac189 django_web "uwsgi --ini /code/m…" 10 minutes ago Up 10 minutes 8001/tcp container.uwsgi
9d68d40adee0 postgres "docker-entrypoint.s…" 27 hours ago Up 27 hours 0.0.0.0:5432->5432/tcp container.postgres
2-13. 确认动作
通过前面的步骤,已成功构建了包含 NGINX、uWSGI、PostgreSQL 的 Docker 容器。
创建Django Web应用程序
我要创建一个使用Django输出 “Hello world.” 的Web应用程序。
在创建Django应用程序时。
执行以下命令,创建Django应用程序。
应用程序名称可以任意指定。(在这里,我们将其命名为”app”。)
$ docker-compose run --rm web python manage.py startapp app
[确认执行结果①(文件组织)]
将在src目录下创建一个app目录。
$ tree src
src
├── app
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── mainproject
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ ├── settings.cpython-37.pyc
│ │ ├── urls.cpython-37.pyc
│ │ └── wsgi.cpython-37.pyc
│ ├── asgi.py
│ ├── django.ini
│ ├── settings.py
│ ├── urls.py
│ ├── uwsgi.log
│ └── wsgi.py
├── manage.py
└── static
5 directories, 19 files
3-2. 创建视图
这是一个输出”Hello world.”的文件。
打开src/app/views.py文件,并进行以下修改后保存。
(修正后)
from django.shortcuts import render
# Create your views here.
(改正后)
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello world.")
3-3. URL的配对
为了从浏览器访问创建的视图,需要进行URL映射。
(1)在app目录下创建一个新的urls.py文件。
创建urls.py文件可以生成URLconf,用于映射URL。
请按照以下内容进行编写。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
(2)将mainproject目录下的urls.py进行更新。
在项目的根目录(URLconf)中反映app.urls模块的描述。
具体步骤如下:
① 添加django.urls.include的导入语句。
② 将include(‘app.urls’)插入到urlpatterns列表中。
※ 修正前后的文件省略了开头的注释部分。
※ include()函数允许引用其他URLconf。
修正后的”path(‘app/’, include(‘app.urls’))”表示当访问app/时,将参考app目录下的URLconf。
(修缮后)
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
(修改后)
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('app/', include('app.urls')),
path('admin/', admin.site.urls),
]
3-4. 檢查動作是否正確
打开浏览器,访问”http://0.0.0.0:8000/app/”,确认屏幕上显示”Hello world.”。
4. 数据库的设置
我会进行设置,以便在Django中使用数据库(PostgreSQL)。
※由于我喜欢咖啡馆,所以我会用咖啡馆的信息作为例子进行说明。
4-1. 模型的创建
首先,在Web应用程序中定义要使用的模型。
在这里,我们将创建三个模型:Area、Cafe和Utility。
打开src/app/models.py文件,并写入以下内容后保存。
(修正中文后)
from django.db import models
# Create your models here.
(修改之后)
from django.db import models
class Area(models.Model):
name = models.CharField(max_length=100)
create_date = models.DateTimeField('date published')
def __str__(self):
return self.name;
class Cafe(models.Model):
area = models.ForeignKey(Area, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
memo = models.CharField(max_length=400)
website = models.URLField()
image_path = models.CharField(max_length=400)
create_date = models.DateTimeField('date published')
def __str__(self):
return self.name;
class Utility(models.Model):
key = models.CharField(max_length=100)
value = models.CharField(max_length=100)
create_date = models.DateTimeField('date published')
def __str__(self):
return self.key;
【说明】
① 区域
这是管理咖啡厅区域信息(地点)的主数据。
② 咖啡厅
这是保存咖啡厅信息的表格。
※ 使用ForeignKey定义了关系。
每个咖啡厅关联到一个区域。
③ 实用工具
这是保存通用数据的主数据。
在此次中,将用于切换显示方法。
通过控制数据的更改,无需每次都修改程序。
启用模型。
(1) 模型激活的准备
打开src/mainproject/settings.py文件,将”app.apps.AppConfig”添加到INSTALLED_APPS中。
执行后续的migrate命令时,将根据INSTALLED_APPS中的应用程序,创建每个应用程序所需的表。
注意:app.apps.AppConfig表示src/app/apps.py文件中的AppConfig类。
(修正后)
(修正前)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
(修正后)
INSTALLED_APPS = [
'app.apps.AppConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
(2) 创建迁移文件
执行以下指令,创建包含模型变更内容的迁移文件。
$ docker-compose run --rm web python manage.py makemigrations app
会输出如下消息,并创建src/app/migrations/0001_initial.py文件。
※ src/app/migrations/0001_initial.py文件可以手动进行调整。
$ docker-compose run --rm web python manage.py makemigrations app
Starting container.postgres ... done
Migrations for 'app':
app/migrations/0001_initial.py
- Create model Area
- Create model Utility
- Create model Cafe
使用迁移文件创建模型的表。
执行以下命令。
$ docker-compose run --rm web python manage.py migrate
输出以下消息并创建表格。
$ docker-compose run --rm web python manage.py migrate
Starting container.postgres ... done
Operations to perform:
Apply all migrations: admin, app, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying app.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
(4)表的确认
使用名为DBeaver的SQL客户端工具来确认所创建的表。
如果您从未使用过DBeaver,请参考”DBeaver的安装与连接到PostgreSQL”。
(5) 数据的登记
请执行以下SQL语句,并注册初期数据。
insert into app_area (name, create_date) values ('清澄白河', now());
insert into app_area (name, create_date) values ('神保町', now());
insert into app_area (name, create_date) values ('代々木公園', now());
insert into app_cafe (name, memo, website, image_path, create_date, area_id) values ('ブルーボトルコーヒー', 'カフェモカはここが一番美味しい。', 'https://bluebottlecoffee.jp/', 'bluebottlecoffee_IMG.jpg', now(), '1');
insert into app_cafe (name, memo, website, image_path, create_date, area_id) values ('iki ESPRESSO', 'オセアニアンスタイルのカフェ。フードもコーヒーも美味しい。', 'https://www.ikiespresso.com/', 'ikiespresso_IMG.jpg', now(), '1');
insert into app_cafe (name, memo, website, image_path, create_date, area_id) values ('GLITCH COFFEE', 'コーヒーが好きになったきっかけのカフェ。一番好きです。', 'https://glitchcoffee.com/', 'glitchcoffee_IMG.jpg', now(), '2');
insert into app_cafe (name, memo, website, image_path, create_date, area_id) values ('DIXANS', 'とてもオシャレなカフェ。デザートが絶品です。', 'http://www.dixans.jp/', 'dixans_IMG.jpg', now(), '2');
insert into app_cafe (name, memo, website, image_path, create_date, area_id) values ('Fuglen Tokyo', 'コーヒーがとても美味しいです。代々木公園で遊んだ時は必ず寄ります。', 'https://fuglencoffee.jp/', 'fuglencoffee_IMG.jpg', now(), '3');
commit;
5. 创作图像
我将创建一个能够输出数据库中存储的信息的Web应用程序。
我将创建一个简单的列表页面和详细页面。
5-1. 创建列表页面
在src/app的子文件夹下创建一个名为”templates”的目录,
在”templates”目录下创建一个名为”list.html”的文件。
$ mkdir -p src/app/templates
$ touch src/app/templates/list.html
打开src/app/templates/list.html文件,并以以下内容保存。
{% load static %}
<html lang="ja">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="{% static 'app_css/style.css' %}">
<link rel="shortcut icon" href="{% static 'pj_image/armx8-1ibhc-001.ico' %}" type="image/vnd.microsoft.icon">
</head>
<body>
<table border="1">
<thead>
<tr>
<th>カフェ</th>
<th>特徴</th>
<th>エリア</th>
<th>サイト</th>
</tr>
</thead>
<tbody>
{% for cafe in cafe_list %}
<tr>
<td><a href="{% url 'app:detail' cafe.id %}">{{ cafe.name }}</a></td>
<td>{{ cafe.memo }}</td>
<td>{{ cafe.area.name }}</td>
<td><a href="{{ cafe.website }}">{{ cafe.website }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
5-2. 制作详细画面
在src/app/templates下创建一个名为”detail.html”的文件。
$ touch src/app/templates/detail.html
打开 src/app/templates/detail.html 文件,并以以下内容保存。
{% load static %}
<html lang="ja">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="{% static 'app_css/style.css' %}">
<link rel="shortcut icon" href="{% static 'pj_image/armx8-1ibhc-001.ico' %}" type="image/vnd.microsoft.icon">
</head>
<body>
<h1>{{ cafe.name }}</h1>
<h2><img src="{% static 'app_image/' %}{{ cafe.image_path }}" alt="{{ cafe.name }}のイメージ" title="{{ cafe.name }}のイメージ" width="384" height="384"></h2>
<h2>特徴:{{ cafe.memo }}</h2>
<h2>エリア:{{ cafe.area.name }}</h2>
<h2>サイト:<a href="{{ cafe.website }}">{{ cafe.website }}</a></h2>
<a href="{% url 'app:list' %}">戻る</a>
</body>
</html>
5-3. 视图的编辑
打开src/app/views.py文件并进行以下修改后保存,以便输出在3-2步骤中创建的“Hello world.”的内容。
(修正后)
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello world.")
(The revised version)
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Area, Cafe, Utility
class IndexView(generic.ListView):
template_name = 'list.html'
context_object_name = 'cafe_list'
def get_queryset(self):
"""Return the last five published records."""
return Cafe.objects.order_by('name')[:5]
class DetailView(generic.DetailView):
model = Cafe
template_name = 'detail.html'
5-4. 将URL与网页对应
请编辑一个将URL与3-3创建的文件相关联的文件。
打开src/app/urls.py,并进行以下修改后保存。
※ 添加path()并将其与新的view绑定到app.urls模块。
(修改后)
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
(经过修改)
from django.urls import path
from django.contrib.auth.views import LoginView
from . import views
app_name = 'app'
urlpatterns = [
path('', views.IndexView.as_view(), name='list'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
]
5-5. 静态文件的设置
(1) 创建应用程序的静态文件目录。
$ mkdir -p src/app/static/app_css
$ mkdir -p src/app/static/app_image
$ mkdir -p src/app/static/app_js
(2) 我们将创建一个应用程序的 CSS 文件。
请创建一个名为 src/app/static/app_css/style.css 的新文件,并写入以下内容。
table {
background-color: #ffffff;
border-collapse: collapse; /* セルの線を重ねる */
}
th {
background-color: #000080;
color: #ffffff; /* 文字色指定 */
}
th, td {
border: solid 1px; /* 枠線指定 */
padding: 10px; /* 余白指定 */
}
(3)将在数据库中注册的咖啡馆图片文件放置到src/app/static/app_image中。
请准备好任意的图片文件。
如果没有准备好图片文件,也没有关系,只是无法显示图片而已,可以跳过这一步。
(4)创建mainproject项目的静态文件目录。
$ mkdir -p src/mainproject/static/pj_css
$ mkdir -p src/mainproject/static/pj_image
$ mkdir -p src/mainproject/static/pj_js
(5) 将favicon放置在src/mainproject/static/pj_image中。
※ 请准备一个任意的favicon。
即使没有favicon,只是不会显示favicon,跳过也没问题。
(6) 进行静态文件的收集。
执行以下命令。
$ docker-compose run web ./manage.py collectstatic
以下的消息將被輸出:
根據“2-11. ALLOWED_HOST、DB及靜態文件的設定”所述,
它將收集由STATICFILES_DIRS指定的共用靜態文件,
以及各個應用程式下的static目錄中的靜態文件。
此外,它還會將src/app/static/app_css/style.css和src/app/static/app_image中的圖片文件,
以及src/mainproject/static/pj_image中的favicon,
複製到src/static目錄中。
$ docker-compose run web ./manage.py collectstatic
Starting container.postgres ... done
137 static files copied to '/code/static'.
5-6. 確認動作
NGINX、uWSGI和PostgreSQL运行在Docker容器中,至此完成了Django Web应用的验证步骤。我相信我已经介绍了创建Web应用的基本要点,希望本帖对大家有所帮助。
6. 参考资料(Django 管理界面)
在本投稿中,我们使用DBeaver进行了数据的注册,但也可以使用Django提供的管理界面”Django Admin”进行数据的注册。
6-1. 创建管理员用户
我們將執行以下指令。
$ docker-compose run --rm web python manage.py createsuperuser
在命令提示符中,按照下面的方式输入任意信息:
用户名:管理员
电子邮件地址:admin@example.com
密码:管理员
$ docker-compose run --rm web python manage.py createsuperuser
Starting container.postgres ... done
Username (leave blank to use 'root'): admin
Email address: admin@example.com
Password:
Password (again):
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
将模型注册到Django Admin中。
让我们可以在Django Admin中编辑通过「4-1. 创建模型」创建的模型。
打开src/app/admin.py文件,进行以下修正并保存。
(修正后)
from django.contrib import admin
# Register your models here.
(经修正后)
from django.contrib import admin
from .models import Area
from .models import Cafe
from .models import Utility
admin.site.register(Area)
admin.site.register(Cafe)
admin.site.register(Utility)
6-3. 确认操作
打开浏览器,访问”http://0.0.0.0:8000/admin/”。
Django Admin的登录页面将打开,请使用在”6-1. 创建管理用户”中创建的管理用户登录。
登录后,请确认可以参照、添加和更新Area、Cafe、Utility模型。
7. 引用资料(Bootstrap4)
以下是说明如何使用Bootstrap4的方法。
正如在“2-3. requirements.txt的设置”中所述,
我们正在安装Django的Bootstrap4包,以便在Django中使用Bootstrap4,
通过执行以下步骤,您可以使用Bootstrap4的css和Javascript。
7-1. Django-Bootstrap4的配置
打开src/mainproject/settings.py文件,并进行以下修改后保存。
将django-bootstrap4添加到INSTALLED_APPS中。
(修正后)
INSTALLED_APPS = [
'app.apps.AppConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
(修改后)
INSTALLED_APPS = [
'app.apps.AppConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap4',
]
(2) 将bootstrap4.templatetags.bootstrap4添加到TEMPLATES的builtins中。
※ 通过添加此内容,无需在每个html文件中编写{% load bootstrap4 %}。
(修剪后)
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',
],
},
},
]
(剪裁)
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',
],
'builtins':[
'bootstrap4.templatetags.bootstrap4',
],
},
},
]
7-2. 在Utility表中添加一个控制标志(附加信息1)。
在Utility表中添加控制是否使用Bootstrap4的css的数据。
使用此数据,在列表页面的HTML中确定是否加载Bootstrap4的css。
* 如果不使用,请将value列的值设置为除了”1″之外的其他值。
insert into app_utility (key, value, create_date) values ('bootstrap_flg', '1', now());
commit;
7-3. 修改列表界面.
(1) 打开 src/app/views.py 文件,进行以下修改并保存(附加内容2)。
使用 get_context_data 函数,将在「7-2. Utilityテーブル添加控制标志」中添加的数据用于在 HTML 中使用。
只需要一种选项:请将以下内容用中文进行本地化改写:
(原文)
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Area, Cafe, Utility
class IndexView(generic.ListView):
template_name = 'list.html'
context_object_name = 'cafe_list'
def get_queryset(self):
"""Return the last five published records."""
return Cafe.objects.order_by('name')[:5]
class DetailView(generic.DetailView):
model = Cafe
template_name = 'detail.html'
(修正后)
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Area, Cafe, Utility
class IndexView(generic.ListView):
template_name = 'list.html'
context_object_name = 'cafe_list'
def get_queryset(self):
"""Return the last five published records."""
return Cafe.objects.order_by('name')[:5]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["bootstrap_flg"] = Utility.objects.all().filter(key='bootstrap_flg').first()
return context
class DetailView(generic.DetailView):
model = Cafe
template_name = 'detail.html'
打开 src/app/templates/list.html 文件,并进行以下修改后保存:
当 bootstrap_flg.value 的值为 “1” 时,添加 {% bootstrap_css %} 的代码来加载。
通过添加额外的功能①②,我们已经实现了根据表格数据来控制是否加载 Bootstrap4 的 css。
但如果你只是简单地想使用它,可以跳过额外的功能①②,只需在 html 中添加 {% bootstrap_css %} 即可使用。
{% load static %}
<html lang="ja">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="{% static 'app_css/style.css' %}">
<link rel="shortcut icon" href="{% static 'pj_image/armx8-1ibhc-001.ico' %}" type="image/vnd.microsoft.icon">
</head>
<body>
<table border="1">
<thead>
<tr>
<th>カフェ</th>
<th>特徴</th>
<th>エリア</th>
<th>サイト</th>
</tr>
</thead>
<tbody>
{% for cafe in cafe_list %}
<tr>
<td><a href="{% url 'app:detail' cafe.id %}">{{ cafe.name }}</a></td>
<td>{{ cafe.memo }}</td>
<td>{{ cafe.area.name }}</td>
<td><a href="{{ cafe.website }}">{{ cafe.website }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
(修正后)可以以母语中文给以下内容改写,只需要一种选项:
{% load static %}
<html lang="ja">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="{% static 'app_css/style.css' %}">
{% if bootstrap_flg.value == "1" %}
{% bootstrap_css %}
{% endif %}
<link rel="shortcut icon" href="{% static 'pj_image/armx8-1ibhc-001.ico' %}" type="image/vnd.microsoft.icon">
</head>
<body>
<table border="1">
<thead>
<tr>
<th>カフェ</th>
<th>特徴</th>
<th>エリア</th>
<th>サイト</th>
</tr>
</thead>
<tbody>
{% for cafe in cafe_list %}
<tr>
<td><a href="{% url 'app:detail' cafe.id %}">{{ cafe.name }}</a></td>
<td>{{ cafe.memo }}</td>
<td>{{ cafe.area.name }}</td>
<td><a href="{{ cafe.website }}">{{ cafe.website }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
7-4. 进行动作确认
打开浏览器,在地址栏输入”http://0.0.0.0:8000/app/”,然后确认列表页面正在使用Bootstrap4的css。
参照来源
撰写文件版本3参考
Docker Compose教程:将Heroku的Postgres快速复制到本地
支持的标签及相应的Dockerfile链接
第一次创建Django应用程序,第1部分
尝试用Django的QuerySet API编写SQL的SELECT语句
Django中类基视图的入门和使用示例