使用Docker Compose构建开发环境(NGINX + uWSGI + PostgreSQL)来开发Web应用程序

首先

使用Docker Compose搭建包含NGINX、uWSGI和PostgreSQL运行的Docker容器,记录在浏览器上验证通过Django(Python)开发的Web应用程序的步骤。
※此文章基于Mac OS。
正在使用macOS Catalina 10.15.3进行操作。

No.項目説明1Docker Compose複数のDocker コンテナを一元管理するツールです。
本投稿では、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/

FireShot Capture 192 - Install Docker Desktop on _ - https___docs.docker.com_docker-for-mac_install_.png
FireShot Capture 193 - Docker Hub - https___hub.docker.com__overlay=onboarding.png

1-2. 安装

请运行下载的 Docker.dmg 文件。

スクリーンショット 2020-02-09 18.57.37.png

请在应用程序中执行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

[文件/目录的说明]

No.名称説明1requirements.txt利用するPythonのパッケージ(ライブラリ)を指定するファイル2DockerfileDocker コンテナの構成情報を記述するためのファイル3docker-compose.ymlアプリケーションを動かすための処理を記述するファイル4nginxNGINXのルートディレクトリ5nginx/confNGINXの設定ファイルを配置するディレクトリ6nginx/conf/mainproject_nginx.confNGINXの設定を記述するためのファイル
※ ファイル名は任意です、拡張子は”.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. 确认动作

FireShot Capture 001 - Django_ the Web framework for perfectionists with deadlines. - 0.0.0.0.png

通过前面的步骤,已成功构建了包含 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”。

スクリーンショット 2020-03-09 0.44.16.png
スクリーンショット 2020-03-09 0.52.03.png

(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. 確認動作

FireShot Capture 008 - - 0.0.0.0.png
FireShot Capture 009 - - 0.0.0.0.png

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模型。

FireShot Capture 006 - Log in - Django site admin - 0.0.0.0.png
FireShot Capture 007 - Site administration - Django site admin - 0.0.0.0.png

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。

FireShot Capture 011 - - 0.0.0.0.png

参照来源

撰写文件版本3参考
Docker Compose教程:将Heroku的Postgres快速复制到本地
支持的标签及相应的Dockerfile链接
第一次创建Django应用程序,第1部分
尝试用Django的QuerySet API编写SQL的SELECT语句
Django中类基视图的入门和使用示例

广告
将在 10 秒后关闭
bannerAds