Merge branch 'new-template' into 'master'

update template to add test and other functions

See merge request ccsolutions.io/open-source/templates/django!1
This commit is contained in:
Andros Fenollosa 2022-08-02 07:07:34 +00:00
commit f07b4d01b9
31 changed files with 330 additions and 192 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.idea/* .idea/*
static/admin/ static/admin/
static/django_extensions/ static/django_extensions/
static/rest_framework/

18
Caddyfile.dev Normal file
View File

@ -0,0 +1,18 @@
http://project.localhost {
root * /usr/src/app/
encode gzip zstd
@notStatic {
not path /static/* /media/*
}
reverse_proxy @notStatic django:8000
file_server /static/*
file_server /media/*
}
http://webmail.localhost {
reverse_proxy mailhog:8025
}

View File

@ -1,4 +1,4 @@
http://ccstech.localhost https://project.com
root * /usr/src/app/ root * /usr/src/app/

View File

@ -1,4 +1,4 @@
FROM debian:11 FROM python:3.10-slim
# Prevents Python from writing pyc files to disc (equivalent to python -B option) # Prevents Python from writing pyc files to disc (equivalent to python -B option)
ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONDONTWRITEBYTECODE 1

View File

@ -2,16 +2,16 @@
help: help:
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}' @perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}'
lint: ## Check style with black
black --check --exclude="/(postgres|venv|migrations|\.git)/" .
format: ## Format style with black format: ## Format style with black
black --exclude="/(postgres|venv|migrations|\.git)/" . black --exclude="/(postgres_data|venv|migrations|\.git)/" core/ apps/ scripts/ tests/
test: ## Tests
docker-compose -f docker-compose.dev.yaml exec -T django bash -c "pytest"
docker.recreate.django: ## Recreate Django image docker.recreate.django: ## Recreate Django image
docker-compose -f docker-compose.yaml build --no-cache --force-rm django docker-compose -f docker-compose.dev.yaml build --no-cache --force-rm django
docker-compose -f docker-compose.yaml up --force-recreate --no-deps -d django docker-compose -f docker-compose.dev.yaml up --force-recreate --no-deps -d django
make run.loaddata ## make run.loaddata
run.makemigrations: ## Makemigrations run.makemigrations: ## Makemigrations
docker-compose -f docker-compose.yaml exec -T django bash -c "python3 manage.py makemigrations" docker-compose -f docker-compose.yaml exec -T django bash -c "python3 manage.py makemigrations"
@ -21,18 +21,19 @@ run.migrate: ## Migrate
run.loaddata: ## Load initial data run.loaddata: ## Load initial data
# Remove database # Remove database
rm -rf database.sqlite docker-compose exec -T django bash -c "python3 manage.py flush --noinput"
# Remove media # Remove media
rm -rf media rm -rf media
# Migrate # Migrate
docker-compose -f docker-compose.yaml exec -T django bash -c "python3 manage.py migrate" docker-compose exec -T django bash -c "python3 manage.py migrate"
run.loaddata.test: ## Load initial data test run.loaddata.test: ## Load initial data test
make run.loaddata make run.loaddata
# Add superuser: alias "admin" - password "admin" # Add superuser: alias "admin" - password "admin"
docker-compose -f docker-compose.yaml exec -T django bash -c "cat data/create_superuser.py | python3 manage.py shell" docker-compose -f docker-compose.dev.yaml exec -T django bash -c "cat data/create_superuser.py | python3 manage.py shell"
# Add more users: alias random - password "password"
docker-compose -f docker-compose.yaml exec -T django bash -c "cat data/create_users.py | python3 manage.py shell"
run.server: ## Run server run.server.dev: ## Run server
docker-compose -f docker-compose.yaml up docker-compose -f docker-compose.dev.yaml up
run.server.pro: ## Run server
docker-compose -f docker-compose.pro.yaml up

View File

@ -8,7 +8,7 @@ make run.server
Now open: Now open:
`http://ccstech.localhost` `http://project.localhost`
## Gulp ## Gulp
@ -68,15 +68,15 @@ make run.loaddata.test
## Other domains ## Other domains
- Caddy: `http://ccstech.localhost`. - Caddy: `http://project.localhost`.
- Gulp: `http://ccstech.localhost:3000`. - Gulp: `http://project.localhost:3000`.
- Django: `http://ccstech.localhost:8000`. - Django: `http://project.localhost:8000`.
- Mailhog: `http://ccstech.localhost:8025`. - Mailhog: `http://project.localhost:8025`.
### Bash Django ### Bash Django
``` shell ``` shell
docker exec -it ccstech_django_1 bash docker exec -it project-django bash
``` ```
# Run production # Run production
@ -85,4 +85,41 @@ docker exec -it ccstech_django_1 bash
docker-compose -f docker-compose.pro.yaml up docker-compose -f docker-compose.pro.yaml up
``` ```
Open `https://ccstech.io`. Open `https://proyect.com`.
# Enviroment (.env)
```text
PROJECT_NAME=project
# Domain
DOMAIN=project.localhost
DOMAIN_URL=http://project.localhost
# Database
DB_NAME=project_db
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=postgresql
DB_PORT=5432
# Django options
DJANGO_SECRET_KEY=mysecret
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# Caddy
CADDY_PORT_ONE=80
CADDY_PORT_TWO=443
# Email
DEFAULT_FROM_EMAIL=no-reply@project.localhost
EMAIL_CONTACT=info@project.localhost
EMAIL_HOST=mailhog
EMAIL_USER=
EMAIL_PASSWORD=
EMAIL_PORT=1025
EMAIL_USE_TLS=False
EMAIL_USE_SSL=False
```

View File

@ -1,6 +0,0 @@
from django.apps import AppConfig
class WebsiteConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'app.website'

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

6
apps/website/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class WebsiteConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.website"

7
apps/website/urls.py Normal file
View File

@ -0,0 +1,7 @@
from django.urls import path
from apps.website.views import home
urlpatterns = [
path("", home, name="home"),
]

View File

@ -2,4 +2,4 @@ from django.shortcuts import render
# Create your views here. # Create your views here.
def home(request): def home(request):
return render(request, 'home.html') return render(request, "home.html")

View File

@ -1,16 +0,0 @@
"""
WSGI config for ccstech project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ccstech.settings')
application = get_wsgi_application()

View File

@ -1,5 +1,5 @@
""" """
ASGI config for ccstech project. ASGI config for core project.
It exposes the ASGI callable as a module-level variable named ``application``. It exposes the ASGI callable as a module-level variable named ``application``.
@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ccstech.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
application = get_asgi_application() application = get_asgi_application()

View File

@ -10,6 +10,7 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/ https://docs.djangoproject.com/en/3.2/ref/settings/
""" """
import os import os
import dj_database_url
from pathlib import Path from pathlib import Path
from django.db.backends.signals import connection_created from django.db.backends.signals import connection_created
@ -35,39 +36,40 @@ if not os.environ.get("ALLOWED_HOSTS") == None:
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
'django_extensions', "django_extensions",
'app.website', "rest_framework",
"apps.website",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
ROOT_URLCONF = 'ccstech.urls' ROOT_URLCONF = "core.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [os.path.join(BASE_DIR, "app", "templates")], "DIRS": [os.path.join(BASE_DIR, "app", "templates")],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
], ],
}, },
}, },
@ -78,14 +80,9 @@ TEMPLATES = [
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = { DATABASES = {
"default": { "default": dj_database_url.config(
"ENGINE": os.environ.get("DB_ENGINE"), default=f"postgres://{os.environ.get('DB_USER')}:{os.environ.get('DB_PASSWORD')}@{os.environ.get('DB_HOST')}:{os.environ.get('DB_PORT')}/{os.environ.get('DB_NAME')}"
"NAME": os.environ.get("DB_NAME"), )
"USER": os.environ.get("DB_USER"),
"PASSWORD": os.environ.get("DB_PASSWORD"),
"HOST": os.environ.get("DB_HOST"),
"PORT": os.environ.get("DB_PORT"),
}
} }
# Password validation # Password validation
@ -93,16 +90,16 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
}, },
] ]
@ -110,9 +107,9 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/ # https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'es-es' LANGUAGE_CODE = "es-es"
TIME_ZONE = 'UTC' TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
@ -152,12 +149,10 @@ CHANNEL_LAYERS = {
} }
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
if DEBUG: if DEBUG:
CACHES = { CACHES = {

View File

@ -1,4 +1,4 @@
"""ccstech URL Configuration """template URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see: The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/topics/http/urls/ https://docs.djangoproject.com/en/4.0/topics/http/urls/
@ -14,10 +14,9 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path from django.urls import path, include
from app.website import views as website_views
urlpatterns = [ urlpatterns = [
path('', website_views.home, name='home'), path("", include("apps.website.urls")),
path('admin/', admin.site.urls), path("admin/", admin.site.urls),
] ]

View File

@ -12,6 +12,6 @@ python3 manage.py migrate
# Start server # Start server
echo "Starting server" echo "Starting server"
## With WebSockets ## With WebSockets
uvicorn --host 0.0.0.0 --port 8000 --reload ccstech.asgi:application python3 manage.py runserver 0.0.0.0:8000
## without WebSockets #echo "*****Start server with production mode*****"
#gunicorn --workers=4 -b 0.0.0.0:8000 --reload ccstech.wsgi:application #daphne -b 0.0.0.0 -p 8000 core.asgi:application

80
docker-compose.dev.yaml Normal file
View File

@ -0,0 +1,80 @@
version: '3.8'
services:
postgresql:
image: postgres
container_name: ${PROJECT_NAME}-postgresql
restart: "no"
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
ports:
- ${DB_PORT}:5432
django:
build:
context: ./
dockerfile: ./Dockerfiles/django/Dockerfile
container_name: ${PROJECT_NAME}-django
restart: "no"
entrypoint: /django-launcher.sh
volumes:
- .:/usr/src/app/
environment:
DEBUG: "False"
ALLOWED_HOSTS: ${DOMAIN}
SECRET_KEY: ${DJANGO_SECRET_KEY}
DB_NAME: ${DB_NAME}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
DOMAIN: ${DOMAIN}
DOMAIN_URL: ${DOMAIN_URL}
STATIC_URL: /static/
STATIC_ROOT: static
MEDIA_URL: /media/
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
EMAIL_HOST: ${EMAIL_HOST}
EMAIL_USE_TLS: ${EMAIL_USE_TLS}
EMAIL_USE_SSL: ${EMAIL_USE_SSL}
EMAIL_PORT: ${EMAIL_PORT}
EMAIL_USER: ${EMAIL_USER}
EMAIL_PASSWORD: ${EMAIL_PASSWORD}
expose:
- 8000
depends_on:
- postgresql
links:
- redis
caddy:
image: caddy:alpine
container_name: ${PROJECT_NAME}-caddy
restart: "no"
ports:
- ${CADDY_PORT_ONE}:80
- ${CADDY_PORT_TWO}:443
volumes:
- ./Caddyfile.dev:/etc/caddy/Caddyfile
- ./caddy_data:/data
- .:/usr/src/app/
depends_on:
- django
redis:
image: redis:alpine
container_name: ${PROJECT_NAME}-redis
restart: "no"
expose:
- ${REDIS_PORT}
mailhog:
image: mailhog/mailhog:latest
container_name: ${PROJECT_NAME}-mailhog
restart: "no"
expose:
- 1025

73
docker-compose.pro.yaml Normal file
View File

@ -0,0 +1,73 @@
version: '3.8'
services:
postgresql:
image: postgres
container_name: ${PROJECT_NAME}-postgresql
restart: always
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
ports:
- ${DB_PORT}:5432
django:
build:
context: ./
dockerfile: ./Dockerfiles/django/Dockerfile
container_name: ${PROJECT_NAME}-django
restart: always
entrypoint: /django-launcher.sh
volumes:
- .:/usr/src/app/
environment:
DEBUG: "False"
ALLOWED_HOSTS: ${DOMAIN}
SECRET_KEY: ${DJANGO_SECRET_KEY}
DB_NAME: ${DB_NAME}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
DOMAIN: ${DOMAIN}
DOMAIN_URL: ${DOMAIN_URL}
STATIC_URL: /static/
STATIC_ROOT: static
MEDIA_URL: /media/
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
EMAIL_HOST: ${EMAIL_HOST}
EMAIL_USE_TLS: ${EMAIL_USE_TLS}
EMAIL_USE_SSL: ${EMAIL_USE_SSL}
EMAIL_PORT: ${EMAIL_PORT}
EMAIL_USER: ${EMAIL_USER}
EMAIL_PASSWORD: ${EMAIL_PASSWORD}
expose:
- 8000
depends_on:
- postgresql
links:
- redis
caddy:
image: caddy:alpine
container_name: ${PROJECT_NAME}-caddy
restart: always
ports:
- ${CADDY_PORT_ONE}:80
- ${CADDY_PORT_TWO}:443
volumes:
- ./Caddyfile.pro:/etc/caddy/Caddyfile
- ./caddy_data:/data
- .:/usr/src/app/
depends_on:
- django
redis:
image: redis:alpine
container_name: ${PROJECT_NAME}-redis
restart: always
expose:
- ${REDIS_PORT}

View File

@ -1,75 +0,0 @@
version: '3.8'
services:
postgresql:
image: postgres
restart: "no"
environment:
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "postgres"
POSTGRES_DB: "ccstech"
ports:
- 5432:5432
django:
build:
context: ./
dockerfile: ./Dockerfiles/django/Dockerfile
restart: "no"
entrypoint: /django-launcher.sh
volumes:
- .:/usr/src/app/
environment:
DEBUG: "True"
ALLOWED_HOSTS: "ccstech.localhost"
SECRET_KEY: "misecreto"
DB_ENGINE: "django.db.backends.postgresql"
DB_NAME: "ccstech"
DB_USER: "postgres"
DB_PASSWORD: "postgres"
DB_HOST: "postgresql"
DB_PORT: "5432"
DOMAIN: "ccstech.localhost"
DOMAIN_URL: "http://ccstech.localhost"
STATIC_URL: "/static/"
STATIC_ROOT: "static"
MEDIA_URL: "/media/"
REDIS_HOST: "redis"
REDIS_PORT: "6379"
EMAIL_HOST: "mailhog"
EMAIL_USE_TLS: "False"
EMAIL_PORT: "1025"
EMAIL_USER: ""
EMAIL_PASSWORD: ""
expose:
- 8000
depends_on:
- postgresql
caddy:
image: caddy:alpine
restart: "no"
ports:
- 80:80
- 443:443
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./caddy_data:/data
- .:/usr/src/app/
depends_on:
- django
redis:
image: redis:alpine
restart: "no"
expose:
- 6379
mailhog:
image: mailhog/mailhog:latest
restart: "no"
expose:
- 1025
ports:
- 8025:8025

View File

@ -6,7 +6,7 @@ import sys
def main(): def main():
"""Run administrative tasks.""" """Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ccstech.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError as exc:

5
pytest.ini Normal file
View File

@ -0,0 +1,5 @@
[pytest]
DJANGO_SETTINGS_MODULE = core.settings
# -- recommended but optional:
python_files = test_*.py

View File

@ -1,18 +1,31 @@
# Django # Django
django===4.0.5 django===4.0.6
django-extensions===3.1.5 django-extensions===3.2.0
dj-database-url==0.5.0
# Django REST
djangorestframework==3.13.1
django-cors-headers==3.10.0
# PostgreSQL driver # PostgreSQL driver
psycopg2-binary===2.9.3 psycopg2-binary===2.9.3
# Servidor para Django sin Websockets
gunicorn===20.1.0 # Check connection
# Servidor para Django con Websockets redis==4.3.4
uvicorn===0.18.1
websockets===10.3 # Django Server
# Channels daphne===3.0.2
channels==3.0.5
asgiref===3.5.2 asgiref===3.5.2
# Conector de Redis para Channels
channels_redis===3.4.0 # Templates
# Template ## Image processing
# Pillow Pillow===9.2.0
Pillow===9.1.1
# Testing
pytest==7.1.2
pytest-django==4.5.2
# Quality code
black==22.6.0
flake8==4.0.1
isort==5.10.1

0
scripts/__ini__.py Normal file
View File

0
tests/__ini__.py Normal file
View File

3
tests/test_start.py Normal file
View File

@ -0,0 +1,3 @@
def test_hello_world():
assert "hello_world" == "hello_world"
assert "foo" != "bar"