Django/Docker - Hello world!
Bài đăng này đã không được cập nhật trong 6 năm
Python là một ngôn ngữ lập trình được sử dụng rộng rãi, với kho thư viện hỗ trợ phong phú và mạnh mẽ. Từ develop các web applications, desktop applications hay là machine learning thì Python đều góp mặt. Quả là một anh chàng đa di năng phải không mọi người? =))
Django
Tại thời điểm hiện tại, nếu như nhắc tới PHP bạn nghĩ ngay tới Laravel và Symfony thì nhắc tới Python để develop web người ta sẽ nghĩ ngay tới Django, một web framework khá nổi tiếng, được release từ năm 2005. Quả là rất lâu rồi phải không các bạn? :v
Nếu so sánh với Laravel, tuy ra mắt khá lâu, già cỗi nhưng gừng càng già càng cay; Ưu điểm nổi trội của Django so với Laravel chính là về khả năng về tốc độ giúp tăng khả năng chịu tải. Trong một cuộc speed test giữa các ngôn ngữ lập trình được thực hiện năm 2016 bởi một vài chuyên viên lập trình, Django đã cho thấy sức mạnh của mình.

Kết quả:
-
Django: Plaintext test — 3127 requests/giây, JSON test — 3060 requests/ giây, Random SQLite Fetch test — 2137 requests/giây.
-
Laravel: Plaintext test — 212 requests/giây, JSON test — 167 requests/ giây, Random SQLite Fetch test — 140 requests/giây.
Tốc nhanh hơn Laravel 15 lần khi response Plaintext, 18 lần khi response JSON.
Mặt khác về bảo mật, Django cũng tích hợp sẵn cơ chế phòng ngừa tấn công XSS, Database Injection hay CSRF giúp website trở nên an toàn hơn. Cùng với đó là cộng đồng contribute đông đảo từ lâu, documentation rõ ràng giúp việc tiếp cận với Django trở nên dễ dàng với tutorial đầy đủ.
Getting started
Nếu bạn đã thấy hứng với Django, hãy đọc tiếp bài viết để cùng làm một practice với Django nhé! 
Xuyên suốt bài viết này sẽ dev với stack như sau:
- Python 3
- Django 2.0.4
- Docker & docker-compose (có hướng dẫn sau cho các bạn không dùng docker - Mình khuyến khích dùng docker)
- Ubuntu 16.04 LTS
- Postgres
- Nginx
Docker stack rất đơn giản:
- Container web - Python 3: Là môi trường để chạy code python, run project django tại port 8000.
- Container Postgres: Làm database storage
- Container web-proxy - Nginx: Làm proxy tới container Python ở trên.
Bạn đầu mình để dev, nên chưa định có Nginx, cơ mà loay hoay mà chưa public được cái project trong web-python, ra cho nó chạy tại 0.0.0.0:8000 nên mình dùng tạm nginx cho đỡ mất thời gian.
Nếu các bạn dùng hệ điều hành khác mà gặp khó khăn để bắt đầu, đừng ngần ngại hãy comment xuống bên dưới để mình giúp nếu có thể. Hoặc các bạn có thể tạo question trên Viblo nhờ sự giúp đỡ từ các thành viên khác.
Khởi tạo project
Yêu cầu
- Máy tính đã cài đặt docker và docker-compose với các bạn muốn dùng docker.
- Máy tính đã cài đặt Python3 với các bạn không dùng docker. Trường hợp này chúng ta sẽ sử dụng python virtual environment cho tiện. Nếu các bạn dùng Pycharm để code, khi tạo mới project với template Django, nó cũng sẽ sử dụng virtualenv để cài đặt Django.
- Hướng dẫn cài đặt Python Virtual Environment ở đây. (phần này chưa có hướng dẫn trong bài viết)
Tùy chọn
Cài đặt
Tạo thư mục myfirstweb để chứa code và thực hiện setup môi trường.
cd ~
mkdir myfirstweb
cd myfirstweb
Sử dụng Docker
Tại thư mục myfirstweb bạn tạo cấu trúc folder và file như sau:
___________
myfirstweb |
___________|
|
|__ .docker
| |
| |__ web
| | |__ Dockerfile
| | |__ requirements.txt
| |
| |__ nginx
| |__ Dockerfile
| |__ nginx.conf
|
|__ docker-compose.yml
- .docker/web/Dockerfile:
FROM python:3
WORKDIR /srv
ENV PYTHONUNBUFFERED 1
ADD requirements.txt /srv
RUN pip install -r requirements.txt
- .docker/web/requirements.txt:
Django
psycopg2-binary
python-decouple
django-pdb
- .docker/nginx/Dockerfile:
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
- .docker/nginx/nginx.conf: Cấu hình nginx làm web proxy tới Django web:
worker_processes 1;
events { worker_connections 1024; }
http {
server_tokens off;
sendfile on;
upstream web-app {
server web:8000;
}
server {
listen 80;
location / {
proxy_pass http://web-app;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
- ./docker-compose.yml:
version: "3"
services:
# Web proxy to web app
web-proxy:
container_name: django_proxy
build: .docker/nginx
restart: always
links:
- web
ports:
- ${DOCKER_WEB_PORT:-8000}:80
# Web app
web:
container_name: django_web
build: .docker/web
restart: always
tty: true
volumes:
- ./:/srv
working_dir: /srv
# command: python3 manage.py runserver 0:8000
links:
- db
expose:
- 8000
# Database storage:
db:
container_name: django_db
image: postgres
restart: always
volumes:
- ${DOCKER_DATA_PATH:-.docker/data}/postgres:/var/lib/postgresql/data
expose:
- ${DB_PORT:-5432}
environment:
POSTGRES_DB: ${DB_DATABASE:-django}
POSTGRES_USER: ${DB_USERNAME:-django}
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
# Database storage for testing:
db_test:
container_name: django_db_test
image: postgres
restart: always
volumes:
- ${DOCKER_DATA_PATH:-.docker/data}/postgres_test:/var/lib/postgresql/data
expose:
- ${DB_PORT_TEST:-5432}
environment:
POSTGRES_DB: ${DB_DATABASE_TEST:-django_test}
POSTGRES_USER: ${DB_USERNAME_TEST:-django_test}
POSTGRES_PASSWORD: ${DB_PASSWORD_TEST:-secret}
Sau khi bổ sung nội dung cho các file như ở trên, bạn chạy lệnh sau để build docker:
docker-compose up --build -d
Kiểm tra setup docker thành công:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb488b5ff35e myfirstweb_web-proxy "nginx -g 'daemon of…" 7 hours ago Up 7 hours 0.0.0.0:8000->80/tcp django_proxy
3478f7bb65a2 myfirstweb_web "python3 manage.py r…" 7 hours ago Up 7 hours 8000/tcp django_web
8f6e12c3b83a postgres "docker-entrypoint.s…" 7 hours ago Up 7 hours 5432/tcp django_db_test
ef49202cffa2 postgres "docker-entrypoint.s…" 7 hours ago Up 7 hours 5432/tcp django_db
Để tắt docker Django đi:
docker-compose down --remove-orphans
Bạn access vào container python có tên django_web để thực hiện các lệnh command với python sử dụng cho các phần tiếp dưới đây:
docker exec -it django_web bash
Tạo Django project
Startproject
django-admin startproject mysite .
Sau khi thực hiện lệnh trên, Django project có tên là mysite sẽ được tạo ra trong myfirstweb với cấu trúc như sau:
___________
myfirstweb |
___________|
|
|__ mysite
| |
| |__ __init__.py // File rỗng để nói mysite là một python package
| |__ settings.py // Chứa các config của project
| |__ urls.py // Khai báo các url, định tuyến cho website
| |__ wsgi.py // Cấu hình để deploy python website
|
|__ manage.py // Giúp thực hiện một số lệnh Django command line
Để chắc chắn đã cài đặt Django thành công, chúng ta thực hiện run Django server lên bằng cách:
python manage.py runserver 0:8000
Rồi, truy cập http://localhost:8000 từ trình duyệt và xem kết quả, bạn thấy một trang welcome mặc định của Django sẽ hiển thị ra màn hình.
WHATTTTTT???? Chuyện gì vậy? Tại sao nó lại hiển thị được nhỉ? Không cần phải config apache hay gì khác nữa à? Câu trả lời là đúng vậy. Mọi thứ đã được setup với docker.
Vậy cấu trúc của project này nó hoạt động như nào?? Điều kỳ diệu nằm ở config docker compose: command python3 manage.py runserver 0:8000 trong file docker-compose.yml. Khi run docker, command này sẽ được chạy kèm, đây là command của Django giúp chạy project tại ip: 0.0.0.0 tại port 8000. Không cần docker, không cần nginx bạn vẫn có thể thấy được trang welcome ban nãy.
Nếu bạn không chạy thủ công dòng lệnh runserver trên, bạn mở docker-compose.yml tìm dòng 22:
#command: python3 manage.py runserver 0:8000
Sửa lại thành:
command: python3 manage.py runserver 0:8000
Sau đó lưu lại và chạy docker-compose up -d lại một lần nữa. Từ bây giờ, mỗi khi bạn tắt docker rồi bật lại docker thì lệnh runserver trên sẽ tự động được chạy ngầm để tiện cho việc phát triển hơn.
Migrate database:
Config
mysite/settings.py, sửa đoạn database thành như sau:
from decouple import config
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_DATABASE', default='django'),
'USER': config('DB_USERNAME', default='django'),
'PASSWORD': config('DB_PASSWORD', default='secret'),
'HOST': config('DB_HOST', default='db'),
'PORT': config('DB_PORT', default=5432, cast=int),
'TEST': {
'NAME': config('DB_DATABASE_TEST', default='django_test'),
'USER': config('DB_USERNAME_TEST', default='django_test'),
'PASSWORD': config('DB_PASSWORD_TEST', default='secret'),
'HOST': config('DB_HOST_TEST', default='db_test'),
'PORT': config('DB_PORT_TEST', default=5433, cast=int),
}
}
Mình sử dụng decouple để dynamic các giá trị cấu hình database từ file .env.
Migrate
python manage.py migrate
Hệ thống sẽ thực hiện migrate cấu trúc cơ sở dữ liệu mặc định cho admin và hiện thông báo thành công. Mặc định admin được truy cập qua url: /admin/.
All rights reserved