├── .env ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ └── deploy.yaml ├── .gitignore ├── Caddyfile ├── Dockerfile ├── LICENSE ├── README.MD ├── _settings ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── forms.py ├── migrations │ └── __init__.py ├── models.py ├── templates │ └── registration │ │ ├── logged_out.html │ │ ├── login.html │ │ ├── password_change_done.html │ │ ├── password_change_form.html │ │ ├── password_reset_confirm.html │ │ ├── password_reset_done.html │ │ ├── password_reset_form.html │ │ └── signup.html ├── tests.py ├── urls.py └── views.py ├── docker-compose-prod.yaml ├── docker-compose.yml ├── entrypoint.sh ├── main ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── templatetags │ └── tags.py ├── tests.py ├── urls.py └── views.py ├── manage.py ├── media └── .gitkeep ├── nginx └── nginx.conf ├── poetry.lock ├── pyproject.toml ├── static ├── .gitkeep └── django-docker-sea.png └── templates ├── base.html ├── includes ├── navbar.html └── pages.html └── index.html /.env: -------------------------------------------------------------------------------- 1 | # Don't use this credentions in production! Especially Django Superuser! 2 | DB_ENGINE=django.db.backends.postgresql 3 | DB_NAME=postgres 4 | POSTGRES_USER=postgres 5 | POSTGRES_PASSWORD=postgrespostgres 6 | DB_HOST=db 7 | DB_PORT=5432 8 | SECRET_KEY=SECRET_KEYSECRET_KEYSECRET_KEY 9 | DJANGO_SUPERUSER_PASSWORD=12345678 10 | DJANGO_SUPERUSER_EMAIL=example@example.com 11 | DJANGO_SUPERUSER_USERNAME=admin 12 | DOCKER_USERNAME=matakov 13 | DOCKER_IMAGE=django-docker -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Django-Starter workflow 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | magic_deploy: 10 | name: Deploy to server with remote docker-compose 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up Python 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: 3.9 18 | 19 | - name: Install SSH key to github server 20 | uses: kielabokkie/ssh-key-and-known-hosts-action@v1.1.0 21 | with: 22 | ssh-private-key: ${{ secrets.SSH_KEY }} 23 | ssh-host: ${{ secrets.IP_HOST }} 24 | 25 | - name: Install latest version of docker with experimental compose support 26 | run: | 27 | pip install docker-compose 28 | 29 | - name: Generate env file from Base64 encoded string (base64 -i .env) 30 | uses: RollyPeres/base64-to-path@v1 31 | with: 32 | filePath: ${{ github.workspace }}/.env 33 | encodedString: ${{ secrets.ENV }} 34 | 35 | - name: Remote docker compose down/up using context (zero files) 36 | run: | 37 | docker context create remote --docker "host=ssh://${{ secrets.SSH_USER }}@${{ secrets.IP_HOST }}" 38 | docker context use remote 39 | docker image prune -f 40 | docker build -t matakov/django-docker:latest . 41 | docker compose -f docker-compose-prod.yaml down 42 | docker compose -f docker-compose-prod.yaml up -d --force-recreate 43 | 44 | send_message: 45 | name: Send telegram notification 46 | runs-on: ubuntu-latest 47 | needs: magic_deploy 48 | steps: 49 | - name: Send message 50 | uses: appleboy/telegram-action@master 51 | with: 52 | to: ${{ secrets.TELEGRAM_TO }} 53 | token: ${{ secrets.TELEGRAM_TOKEN }} 54 | message: ${{ github.workflow }} done! 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.venv/ 2 | 3 | # Static and Media contents 4 | media/* 5 | static/admin/* 6 | !media/.gitkeep 7 | !static/.gitkeep 8 | /.idea/ 9 | /static/debug_toolbar/ 10 | /.env.prod 11 | /static/bulma/ 12 | -------------------------------------------------------------------------------- /Caddyfile: -------------------------------------------------------------------------------- 1 | example.com { 2 | reverse_proxy 127.0.0.1:1111 3 | } 4 | 5 | example2.com { 6 | reverse_proxy 127.0.0.1:1122 7 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-slim 2 | 3 | # Keeps Python from generating .pyc files in the container 4 | ENV PYTHONDONTWRITEBYTECODE 1 5 | # Turns off buffering for easier container logging 6 | ENV PYTHONUNBUFFERED 1 7 | 8 | # Install essential tools 9 | RUN apt-get -y update && apt-get install -y \ 10 | wget \ 11 | gnupg \ 12 | lsb-release 13 | 14 | # Install and setup poetry 15 | RUN pip install -U pip \ 16 | && pip install poetry 17 | ENV PATH="${PATH}:/root/.poetry/bin" 18 | 19 | WORKDIR /code 20 | COPY . /code 21 | # Run poetry 22 | RUN poetry config virtualenvs.create false \ 23 | && poetry install --no-interaction --no-ansi 24 | 25 | 26 | ENTRYPOINT ["/code/entrypoint.sh"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Denis Matakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Django + Docker Template 2 | 3 | 4 | 5 | This is a magic repository for everyone who wants to start developing and do not want to worry about initial django and docker setup. 6 | 7 | You can see deployed example here: [https://django-docker.matakov.com](https://django-docker.matakov.com) 8 | 9 | Github link: [https://github.com/matacoder/django-docker](https://github.com/matacoder/django-docker) 10 | Redeployed 2024 11 | 12 | ## What's new in version 2.0 13 | 14 | * All styles now are implemented with Bulma CSS framework. 15 | * Loguru logger 16 | * Dark mode (using OS toggle, supported in Safari/Chrome/Firefox) 17 | * Auto loading README to index page 18 | * More efficient Github workflow 19 | * Added Pagination template 20 | * Drop support of Bootstrap and Crispy Forms 21 | 22 | ## What is included 23 | 24 | - Django 25 | - Nginx 26 | - PostgreSQL 27 | - Gunicorn 28 | - Docker Compose for development 29 | - Docker Compose for production 30 | - Caddy config for fast SSL + domain deploy 31 | - Poetry dependency manager 32 | - Loguru logger 33 | - Initial entrypoint to take care of django and postgres setup 34 | - Black code formatter 35 | - Basic Workflow for GitHub Actions 36 | - Accounts app with all authorization forms implemented with Bulma CSS 37 | - Basic template to test login/logout 38 | - Sign up form 39 | - Main app to immediately start writing your first business logic 40 | - Django Debug Toolbar! Analyze SQL on-the-fly 41 | 42 | ## Why project is named _settings? 43 | 44 | Do you know that frustration when you are looking for your setting file directory? 45 | 46 | I know! So underscored `_settings` folder is always close to top and easy to find. 47 | 48 | ## What next step? 49 | 50 | Export all your `.env` environment variables with command: 51 | 52 | `set -o allexport; source .env; set +o allexport` 53 | 54 | Create your app using: 55 | 56 | `python manage.py startapp my_new_app` 57 | 58 | Or just use `main` app. It is already here and urls are included! 59 | 60 | ## What You Develop is What You Get 61 | 62 | Just `docker compose up` and you will see your development version at `127.0.0.1:1111` 63 | 64 | Restart your django container (using Docker GUI) everytime you make a change in app logic. 65 | 66 | Django's templates engine is reloading without container needed to restart 67 | 68 | ## Fast Deploy Using Docker Context (Manually) 69 | 70 | Docker context is a bridge to your remote server to run docker commands on your local pc or mac. 71 | 72 | #### STEP 0: Create new context to remote control your server docker (once) 73 | 74 | `docker context create new_ip --docker "host=ssh://username@ip"` 75 | 76 | #### STEP 1: Switch to remote server docker 77 | 78 | `docker context use new_ip` 79 | 80 | #### STEP 2: Build image DIRECTLY on remote server (use variables in .env) 81 | 82 | `docker build -t username/project:latest .` 83 | 84 | #### STEP 3: Down your compose gracefully on remote server 85 | 86 | `docker compose -f docker-compose-prod.yaml down` 87 | 88 | Here consider deleting static volume if you have static files modified 89 | 90 | #### STEP 4: Up your compose, force recreate containers using new image 91 | 92 | `docker compose -f docker-compose-prod.yaml up -d --force-recreate` 93 | 94 | #### STEP 5: Don't forget to switch back to your local docker 95 | 96 | `docker context use default` 97 | 98 | # Run your site with Caddy Server 99 | 100 | Install [Caddy Server](https://caddyserver.com), replace `example.com` with your domain in `Caddyfile` and run command: 101 | 102 | ```bash 103 | sudo caddy stop 104 | sudo caddy run 105 | ``` 106 | 107 | Consider adding `caddy` to [linux start up sequence](https://caddy.community/t/want-caddy-to-run-automatically-on-boot/5240). 108 | 109 | # Deploy using GitHub Actions (automatically) 110 | 111 | You can not use experimental `docker compose` feature in GitHub Actions yet, but `docker-compose` works just fine. 112 | 113 | Do not forget to add GitHub secrets for: 114 | 115 | - SSH_KEY 116 | - IP_HOST 117 | - SSH_USER 118 | 119 | For all other docker-related secrets you can use sole `ENV` secret. Run this command within project: 120 | 121 | `base64 -i .env` 122 | 123 | That will give you string array very alike SSH key. Save it to `ENV` secret. Now look at workflow. 124 | 125 | `RollyPeres/base64-to-path@v1` action will extract this to `.env` file. That is fast and reliable way to export all your environment variable at once. 126 | 127 | This is example workflow you need to implement: 128 | 129 | ```yaml 130 | name: Django-Docker workflow 131 | 132 | on: 133 | push: 134 | branches: 135 | - master 136 | 137 | jobs: 138 | magic_deploy: 139 | name: Deploy to server with remote docker-compose 140 | runs-on: ubuntu-latest 141 | steps: 142 | - uses: actions/checkout@v2 143 | - name: Set up Python 144 | uses: actions/setup-python@v2 145 | with: 146 | python-version: 3.9 147 | 148 | - name: Install SSH key to github server 149 | uses: kielabokkie/ssh-key-and-known-hosts-action@v1.1.0 150 | with: 151 | ssh-private-key: ${{ secrets.SSH_KEY }} 152 | ssh-host: ${{ secrets.IP_HOST }} 153 | 154 | - name: Install latest version of docker with experimental compose support 155 | run: | 156 | pip install docker-compose 157 | 158 | - name: Generate env file from Base64 encoded string (base64 -i .env) 159 | uses: RollyPeres/base64-to-path@v1 160 | with: 161 | filePath: ${{ github.workspace }}/.env 162 | encodedString: ${{ secrets.ENV }} 163 | 164 | - name: Remote docker compose down/up using context (zero files) 165 | run: | 166 | docker context create remote --docker "host=ssh://${{ secrets.SSH_USER }}@${{ secrets.IP_HOST }}" 167 | docker context use remote 168 | docker image prune -f 169 | docker-compose --context remote -f docker-compose-prod.yaml down 170 | docker-compose --context remote -f docker-compose-prod.yaml up -d --build --force-recreate 171 | ``` 172 | -------------------------------------------------------------------------------- /_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/_settings/__init__.py -------------------------------------------------------------------------------- /_settings/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for _settings project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "_settings.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /_settings/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for _settings project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.3. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | import os 13 | from pathlib import Path 14 | 15 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 16 | BASE_DIR = Path(__file__).resolve().parent.parent 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = os.environ.get("SECRET_KEY") 23 | 24 | # SECURITY WARNING: don't run with debug turned on in production! 25 | DEBUG = os.environ.get("DEBUG") == "1" 26 | 27 | ALLOWED_HOSTS = ["127.0.0.1", "django-docker.matakov.com"] 28 | 29 | INTERNAL_IPS = [ 30 | "127.0.0.1", 31 | ] 32 | 33 | if DEBUG: 34 | DEBUG_TOOLBAR_CONFIG = { 35 | "SHOW_TOOLBAR_CALLBACK": lambda request: not request.is_ajax(), 36 | } 37 | 38 | # Application definition 39 | 40 | INSTALLED_APPS = [ 41 | "main", 42 | "accounts", 43 | "debug_toolbar", 44 | "django.contrib.admin", 45 | "django.contrib.auth", 46 | "django.contrib.contenttypes", 47 | "django.contrib.sessions", 48 | "django.contrib.messages", 49 | "django.contrib.staticfiles", 50 | "markdownify.apps.MarkdownifyConfig", 51 | "bulma", 52 | ] 53 | 54 | MIDDLEWARE = [ 55 | "debug_toolbar.middleware.DebugToolbarMiddleware", 56 | "django.middleware.security.SecurityMiddleware", 57 | "django.contrib.sessions.middleware.SessionMiddleware", 58 | "django.middleware.common.CommonMiddleware", 59 | "django.middleware.csrf.CsrfViewMiddleware", 60 | "django.contrib.auth.middleware.AuthenticationMiddleware", 61 | "django.contrib.messages.middleware.MessageMiddleware", 62 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 63 | ] 64 | 65 | ROOT_URLCONF = "_settings.urls" 66 | TEMPLATES_DIR = os.path.join(BASE_DIR, "templates") 67 | TEMPLATES = [ 68 | { 69 | "BACKEND": "django.template.backends.django.DjangoTemplates", 70 | "DIRS": [TEMPLATES_DIR], 71 | "APP_DIRS": True, 72 | "OPTIONS": { 73 | "context_processors": [ 74 | "django.template.context_processors.debug", 75 | "django.template.context_processors.request", 76 | "django.contrib.auth.context_processors.auth", 77 | "django.contrib.messages.context_processors.messages", 78 | ], 79 | }, 80 | }, 81 | ] 82 | 83 | MARKDOWNIFY = { 84 | "default": { 85 | "BLEACH": False, 86 | "LINKIFY_TEXT": { 87 | "PARSE_URLS": True, 88 | # Next key/value-pairs only have effect if "PARSE_URLS" is True 89 | "PARSE_EMAIL": True, 90 | "CALLBACKS": [], 91 | "SKIP_TAGS": [], 92 | }, 93 | "MARKDOWN_EXTENSIONS": [ 94 | "markdown.extensions.fenced_code", 95 | "markdown.extensions.extra", 96 | "markdown.extensions.codehilite", 97 | "markdown.extensions.nl2br", 98 | "markdown.extensions.sane_lists", 99 | "markdown.extensions.toc", 100 | ], 101 | } 102 | } 103 | 104 | WSGI_APPLICATION = "_settings.wsgi.application" 105 | 106 | # Database 107 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 108 | 109 | DATABASES = { 110 | "default": { 111 | "ENGINE": os.environ.get("DB_ENGINE"), 112 | "NAME": os.environ.get("DB_NAME"), 113 | "USER": os.environ.get("POSTGRES_USER"), 114 | "PASSWORD": os.environ.get("POSTGRES_PASSWORD"), 115 | "HOST": os.environ.get("DB_HOST"), 116 | "PORT": os.environ.get("DB_PORT"), 117 | } 118 | } 119 | 120 | # Password validation 121 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 122 | 123 | AUTH_PASSWORD_VALIDATORS = [ 124 | { 125 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 126 | }, 127 | { 128 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 129 | }, 130 | { 131 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 132 | }, 133 | { 134 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 135 | }, 136 | ] 137 | 138 | # Internationalization 139 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 140 | 141 | LANGUAGE_CODE = "en-us" 142 | 143 | TIME_ZONE = "UTC" 144 | 145 | USE_I18N = True 146 | 147 | USE_L10N = True 148 | 149 | USE_TZ = True 150 | 151 | # Static files (CSS, JavaScript, Images) 152 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 153 | 154 | STATIC_URL = "/static/" 155 | STATIC_ROOT = os.path.join(BASE_DIR, "static") 156 | 157 | MEDIA_URL = "/media/" 158 | MEDIA_ROOT = os.path.join(BASE_DIR, "media") 159 | 160 | # Default primary key field type 161 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 162 | 163 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 164 | 165 | CRISPY_TEMPLATE_PACK = "bootstrap4" 166 | 167 | LOGIN_URL = "/auth/login/" 168 | LOGIN_REDIRECT_URL = "index" 169 | -------------------------------------------------------------------------------- /_settings/urls.py: -------------------------------------------------------------------------------- 1 | """_settings URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | import debug_toolbar 17 | from django.contrib import admin 18 | from django.urls import include, path 19 | 20 | urlpatterns = [ 21 | path("admin/", admin.site.urls), 22 | path("auth/", include("accounts.urls")), 23 | path("", include("main.urls")), 24 | path("__debug__/", include(debug_toolbar.urls)), 25 | ] 26 | -------------------------------------------------------------------------------- /_settings/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for _settings project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "_settings.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/accounts/admin.py -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UsersConfig(AppConfig): 5 | name = "accounts" 6 | -------------------------------------------------------------------------------- /accounts/forms.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from django.contrib.auth.forms import UserCreationForm 3 | 4 | User = get_user_model() 5 | 6 | 7 | class CreationForm(UserCreationForm): 8 | class Meta: 9 | model = User 10 | fields = ("first_name", "last_name", "username", "email") 11 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/accounts/models.py -------------------------------------------------------------------------------- /accounts/templates/registration/logged_out.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Logged out{% endblock %} 3 | {% block header %}Logged out{% endblock %} 4 | {% block content %} 5 |
6 | Logged out 7 |
8 | 9 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Login{% endblock %} 3 | {% block header %}Login{% endblock %} 4 | {% block content %} 5 | {% load bulma_tags %} 6 |
7 |
8 | {% csrf_token %} 9 | {{ form|bulma }} 10 |

Reset password

11 | 14 |
15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/password_change_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Success{% endblock %} 3 | {% block header %}Success{% endblock %} 4 | {% block content %} 5 |
6 | Success 7 |
8 | 9 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/password_change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Change password{% endblock %} 3 | {% block header %}Change password{% endblock %} 4 | {% block content %} 5 | {% load bulma_tags %} 6 |
7 |
8 | {% csrf_token %} 9 | {{ form|bulma }} 10 |
11 | 14 |
15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Reset confirmation{% endblock %} 3 | {% block header %}Reset confirmation{% endblock %} 4 | {% block content %} 5 | {% load bulma_tags %} 6 |
7 |
8 | {% csrf_token %} 9 | {{ form|bulma }} 10 |
11 | 14 |
15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Success{% endblock %} 3 | {% block header %}Success{% endblock %} 4 | {% block content %} 5 |
6 | Success 7 |
8 | 9 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Reset password{% endblock %} 3 | {% block header %}Reset password{% endblock %} 4 | {% block content %} 5 | {% load bulma_tags %} 6 |
7 |
8 | {% csrf_token %} 9 | {{ form|bulma }} 10 |
11 | 14 |
15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /accounts/templates/registration/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Register{% endblock %} 3 | {% block header %}Register{% endblock %} 4 | {% block content %} 5 | {% load bulma_tags %} 6 |
7 |
8 | {% csrf_token %} 9 | {{ form|bulma }} 10 |
11 | 14 |
15 |
16 | {% endblock %} -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/accounts/tests.py -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import include, path 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | path("signup/", views.SignUp.as_view(), name="signup"), 7 | path("", include("django.contrib.auth.urls")), 8 | ] 9 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.urls import reverse_lazy 2 | from django.views.generic import CreateView, FormView, TemplateView 3 | 4 | from .forms import CreationForm 5 | 6 | 7 | class SignUp(CreateView): 8 | form_class = CreationForm 9 | success_url = reverse_lazy("login") 10 | template_name = "registration/signup.html" 11 | 12 | 13 | class LoginView(FormView): 14 | success_url = reverse_lazy("index") 15 | template_name = "registration/login.html" 16 | 17 | 18 | class LogoutView(TemplateView): 19 | template_name = "registration/logged_out.html" 20 | 21 | 22 | class PasswordResetView(FormView): 23 | template_name = "registration/password_reset_form.html" 24 | 25 | 26 | class PasswordResetDoneView(TemplateView): 27 | template_name = "registration/password_reset_done.html" 28 | 29 | 30 | class PasswordResetConfirmView(FormView): 31 | template_name = "registration/password_reset_confirm.html" 32 | 33 | 34 | class PasswordResetCompleteView(TemplateView): 35 | template_name = "registration/password_reset_complete.html" 36 | 37 | 38 | class PasswordChangeView(FormView): 39 | template_name = "registration/password_change_form.html" 40 | 41 | 42 | class PasswordChangeDoneView(TemplateView): 43 | template_name = "registration/password_change_done.html" 44 | -------------------------------------------------------------------------------- /docker-compose-prod.yaml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | # instruction at the end of file 3 | 4 | volumes: 5 | postgres_data: 6 | static: 7 | media: 8 | nginx_conf: 9 | 10 | services: 11 | db: 12 | image: postgres:12.4 13 | restart: always 14 | volumes: 15 | - postgres_data:/var/lib/postgresql/data/ 16 | env_file: 17 | - ./.env 18 | django: 19 | image: matakov/django-docker:latest 20 | depends_on: 21 | - db 22 | restart: always 23 | env_file: 24 | - ./.env 25 | volumes: 26 | - static:/code/static 27 | - media:/code/media 28 | - nginx_conf:/code/nginx/ 29 | entrypoint: /code/entrypoint.sh 30 | environment: 31 | - DEBUG=0 32 | 33 | nginx: 34 | image: nginx:1.19.0-alpine 35 | ports: 36 | - "127.0.0.1:1122:80" 37 | volumes: 38 | - static:/code/static 39 | - media:/code/media 40 | - nginx_conf:/etc/nginx/conf.d/ 41 | depends_on: 42 | - django 43 | restart: always 44 | 45 | 46 | #### STEP 0 #### Create new context to remote control your server docker 47 | # docker context create new_ip --docker "host=ssh://username@ip" 48 | 49 | #### STEP 1 #### Build and push your docker image on local PC (use variables in .env) 50 | # docker build -t username/project:latest . 51 | # docker push username/project:latest 52 | 53 | #### STEP 2 #### Switch to remote server docker 54 | # docker context use new_ip 55 | 56 | #### STEP 3 #### Down your compose, pull new image, up your compose 57 | # docker compose -f docker-compose-prod.yaml down 58 | # here consider deleting static volume if you have static files modified 59 | 60 | # docker pull username/project:latest 61 | # docker compose -f docker-compose-prod.yaml up -d --force-recreate 62 | 63 | #### STEP 4 #### Don't forget to switch back to your local docker 64 | # docker context use default 65 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | # run docker-compose up to start development at http://127.0.0.1:1111 3 | 4 | volumes: 5 | postgres_data: 6 | 7 | services: 8 | db: 9 | image: postgres:12.4 10 | restart: always 11 | volumes: 12 | - postgres_data:/var/lib/postgresql/data/ 13 | env_file: 14 | - ./.env 15 | django: 16 | build: . 17 | depends_on: 18 | - db 19 | restart: always 20 | env_file: 21 | - ./.env 22 | volumes: 23 | - .:/code/ 24 | environment: 25 | - DEBUG=1 26 | 27 | entrypoint: /code/entrypoint.sh 28 | 29 | nginx: 30 | image: nginx:1.19.0-alpine 31 | ports: 32 | - "127.0.0.1:1111:80" 33 | volumes: 34 | - ./static:/code/static 35 | - ./media:/code/media 36 | - ./nginx:/etc/nginx/conf.d/ 37 | depends_on: 38 | - django 39 | restart: always -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sleep 2 4 | python manage.py migrate 5 | python manage.py createcachetable 6 | 7 | if [ "$DJANGO_SUPERUSER_USERNAME" ]; then 8 | python manage.py createsuperuser \ 9 | --noinput \ 10 | --username "$DJANGO_SUPERUSER_USERNAME" \ 11 | --email $DJANGO_SUPERUSER_EMAIL 12 | fi 13 | 14 | python manage.py collectstatic --noinput 15 | gunicorn _settings.wsgi:application --bind 0.0.0.0:8000 16 | 17 | exec "$@" 18 | -------------------------------------------------------------------------------- /main/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/main/__init__.py -------------------------------------------------------------------------------- /main/admin.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/main/admin.py -------------------------------------------------------------------------------- /main/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MainConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "main" 7 | -------------------------------------------------------------------------------- /main/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/main/migrations/__init__.py -------------------------------------------------------------------------------- /main/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /main/templatetags/tags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.contrib.auth.models import User 3 | 4 | register = template.Library() 5 | 6 | 7 | @register.filter(name="times") 8 | def times(number): 9 | """A way to create for loop with range in 10 | Django Template Engine. Returns array of numbers.""" 11 | return range(number) 12 | 13 | 14 | @register.simple_tag 15 | def url_replace(request, field, value): 16 | """Used by pagination to add GET param.""" 17 | dict_ = request.GET.copy() 18 | dict_[field] = value 19 | return dict_.urlencode() 20 | -------------------------------------------------------------------------------- /main/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /main/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from main import views 4 | 5 | urlpatterns = [ 6 | path("", views.MarkDown.as_view(), name="index"), 7 | ] 8 | -------------------------------------------------------------------------------- /main/views.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from django.shortcuts import render 4 | from django.views.generic import TemplateView 5 | from loguru import logger 6 | 7 | from _settings.settings import BASE_DIR 8 | 9 | 10 | def index(request): 11 | """This is basic view for render your index.""" 12 | return render(request, "index.html", {}) 13 | 14 | 15 | class MarkDown(TemplateView): 16 | """Rendering README.MD on main page.""" 17 | 18 | template_name = "index.html" 19 | 20 | def get_context_data(self, **kwargs): 21 | path = os.path.join(BASE_DIR, "README.MD") 22 | logger.info(path) 23 | with open(path) as readme: 24 | markdowntext = readme.read() 25 | 26 | context = super().get_context_data(**kwargs) 27 | context["markdowntext"] = markdowntext 28 | 29 | return context 30 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "_settings.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /media/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/media/.gitkeep -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | upstream djangodocker { 2 | server django:8000; 3 | } 4 | 5 | server { 6 | 7 | listen 80; 8 | 9 | location / { 10 | proxy_pass http://djangodocker; 11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 12 | proxy_set_header Host $host; 13 | proxy_redirect off; 14 | } 15 | location /static/ { 16 | alias /code/static/; 17 | } 18 | 19 | location /media/ { 20 | alias /code/media/; 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "asgiref" 5 | version = "3.6.0" 6 | description = "ASGI specs, helper code, and adapters" 7 | category = "main" 8 | optional = false 9 | python-versions = ">=3.7" 10 | files = [ 11 | {file = "asgiref-3.6.0-py3-none-any.whl", hash = "sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac"}, 12 | {file = "asgiref-3.6.0.tar.gz", hash = "sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"}, 13 | ] 14 | 15 | [package.extras] 16 | tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] 17 | 18 | [[package]] 19 | name = "black" 20 | version = "21.12b0" 21 | description = "The uncompromising code formatter." 22 | category = "main" 23 | optional = false 24 | python-versions = ">=3.6.2" 25 | files = [ 26 | {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, 27 | {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, 28 | ] 29 | 30 | [package.dependencies] 31 | click = ">=7.1.2" 32 | mypy-extensions = ">=0.4.3" 33 | pathspec = ">=0.9.0,<1" 34 | platformdirs = ">=2" 35 | tomli = ">=0.2.6,<2.0.0" 36 | typing-extensions = [ 37 | {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, 38 | {version = ">=3.10.0.0,<3.10.0.1 || >3.10.0.1", markers = "python_version >= \"3.10\""}, 39 | ] 40 | 41 | [package.extras] 42 | colorama = ["colorama (>=0.4.3)"] 43 | d = ["aiohttp (>=3.7.4)"] 44 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 45 | python2 = ["typed-ast (>=1.4.3)"] 46 | uvloop = ["uvloop (>=0.15.2)"] 47 | 48 | [[package]] 49 | name = "bleach" 50 | version = "6.0.0" 51 | description = "An easy safelist-based HTML-sanitizing tool." 52 | category = "main" 53 | optional = false 54 | python-versions = ">=3.7" 55 | files = [ 56 | {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"}, 57 | {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"}, 58 | ] 59 | 60 | [package.dependencies] 61 | six = ">=1.9.0" 62 | tinycss2 = {version = ">=1.1.0,<1.2", optional = true, markers = "extra == \"css\""} 63 | webencodings = "*" 64 | 65 | [package.extras] 66 | css = ["tinycss2 (>=1.1.0,<1.2)"] 67 | 68 | [[package]] 69 | name = "click" 70 | version = "8.1.3" 71 | description = "Composable command line interface toolkit" 72 | category = "main" 73 | optional = false 74 | python-versions = ">=3.7" 75 | files = [ 76 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 77 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 78 | ] 79 | 80 | [package.dependencies] 81 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 82 | 83 | [[package]] 84 | name = "colorama" 85 | version = "0.4.6" 86 | description = "Cross-platform colored terminal text." 87 | category = "main" 88 | optional = false 89 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 90 | files = [ 91 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 92 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 93 | ] 94 | 95 | [[package]] 96 | name = "django" 97 | version = "3.2.18" 98 | description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." 99 | category = "main" 100 | optional = false 101 | python-versions = ">=3.6" 102 | files = [ 103 | {file = "Django-3.2.18-py3-none-any.whl", hash = "sha256:4d492d9024c7b3dfababf49f94511ab6a58e2c9c3c7207786f1ba4eb77750706"}, 104 | {file = "Django-3.2.18.tar.gz", hash = "sha256:08208dfe892eb64fff073ca743b3b952311104f939e7f6dae954fe72dcc533ba"}, 105 | ] 106 | 107 | [package.dependencies] 108 | asgiref = ">=3.3.2,<4" 109 | pytz = "*" 110 | sqlparse = ">=0.2.2" 111 | 112 | [package.extras] 113 | argon2 = ["argon2-cffi (>=19.1.0)"] 114 | bcrypt = ["bcrypt"] 115 | 116 | [[package]] 117 | name = "django-bulma" 118 | version = "0.8.3" 119 | description = "Bulma CSS Framework for Django projects" 120 | category = "main" 121 | optional = false 122 | python-versions = ">=3.7" 123 | files = [ 124 | {file = "django-bulma-0.8.3.tar.gz", hash = "sha256:b794b4e64f482de77f376451f7cd8b3c8448eb68e5a24c51b9190625a08b0b30"}, 125 | {file = "django_bulma-0.8.3-py3-none-any.whl", hash = "sha256:0ef6e5c171c2a32010e724a8be61ba6cd0e55ebbd242cf6780560518483c4d00"}, 126 | ] 127 | 128 | [package.dependencies] 129 | django = ">=2.2" 130 | 131 | [[package]] 132 | name = "django-debug-toolbar" 133 | version = "3.8.1" 134 | description = "A configurable set of panels that display various debug information about the current request/response." 135 | category = "main" 136 | optional = false 137 | python-versions = ">=3.7" 138 | files = [ 139 | {file = "django_debug_toolbar-3.8.1-py3-none-any.whl", hash = "sha256:879f8a4672d41621c06a4d322dcffa630fc4df056cada6e417ed01db0e5e0478"}, 140 | {file = "django_debug_toolbar-3.8.1.tar.gz", hash = "sha256:24ef1a7d44d25e60d7951e378454c6509bf536dce7e7d9d36e7c387db499bc27"}, 141 | ] 142 | 143 | [package.dependencies] 144 | django = ">=3.2.4" 145 | sqlparse = ">=0.2" 146 | 147 | [[package]] 148 | name = "django-markdownify" 149 | version = "0.9.3" 150 | description = "Markdown template filter for Django." 151 | category = "main" 152 | optional = false 153 | python-versions = "*" 154 | files = [ 155 | {file = "django-markdownify-0.9.3.tar.gz", hash = "sha256:acf42614a418aef55535a66d4b3426b181cf8c8f990e265f453df900c3ad3d25"}, 156 | {file = "django_markdownify-0.9.3-py3-none-any.whl", hash = "sha256:df00291bc338400b9ef999402751fc12c30623d266b7c04e43336d27d0eadee6"}, 157 | ] 158 | 159 | [package.dependencies] 160 | bleach = {version = ">=5.0.0", extras = ["css"]} 161 | Django = "*" 162 | markdown = "*" 163 | 164 | [[package]] 165 | name = "gunicorn" 166 | version = "20.1.0" 167 | description = "WSGI HTTP Server for UNIX" 168 | category = "main" 169 | optional = false 170 | python-versions = ">=3.5" 171 | files = [ 172 | {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, 173 | {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, 174 | ] 175 | 176 | [package.dependencies] 177 | setuptools = ">=3.0" 178 | 179 | [package.extras] 180 | eventlet = ["eventlet (>=0.24.1)"] 181 | gevent = ["gevent (>=1.4.0)"] 182 | setproctitle = ["setproctitle"] 183 | tornado = ["tornado (>=0.2)"] 184 | 185 | [[package]] 186 | name = "importlib-metadata" 187 | version = "6.1.0" 188 | description = "Read metadata from Python packages" 189 | category = "main" 190 | optional = false 191 | python-versions = ">=3.7" 192 | files = [ 193 | {file = "importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"}, 194 | {file = "importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"}, 195 | ] 196 | 197 | [package.dependencies] 198 | zipp = ">=0.5" 199 | 200 | [package.extras] 201 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 202 | perf = ["ipython"] 203 | testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] 204 | 205 | [[package]] 206 | name = "loguru" 207 | version = "0.5.3" 208 | description = "Python logging made (stupidly) simple" 209 | category = "main" 210 | optional = false 211 | python-versions = ">=3.5" 212 | files = [ 213 | {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, 214 | {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, 215 | ] 216 | 217 | [package.dependencies] 218 | colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} 219 | win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} 220 | 221 | [package.extras] 222 | dev = ["Sphinx (>=2.2.1)", "black (>=19.10b0)", "codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)", "tox-travis (>=0.12)"] 223 | 224 | [[package]] 225 | name = "markdown" 226 | version = "3.4.3" 227 | description = "Python implementation of John Gruber's Markdown." 228 | category = "main" 229 | optional = false 230 | python-versions = ">=3.7" 231 | files = [ 232 | {file = "Markdown-3.4.3-py3-none-any.whl", hash = "sha256:065fd4df22da73a625f14890dd77eb8040edcbd68794bcd35943be14490608b2"}, 233 | {file = "Markdown-3.4.3.tar.gz", hash = "sha256:8bf101198e004dc93e84a12a7395e31aac6a9c9942848ae1d99b9d72cf9b3520"}, 234 | ] 235 | 236 | [package.dependencies] 237 | importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} 238 | 239 | [package.extras] 240 | testing = ["coverage", "pyyaml"] 241 | 242 | [[package]] 243 | name = "mypy-extensions" 244 | version = "1.0.0" 245 | description = "Type system extensions for programs checked with the mypy type checker." 246 | category = "main" 247 | optional = false 248 | python-versions = ">=3.5" 249 | files = [ 250 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 251 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 252 | ] 253 | 254 | [[package]] 255 | name = "pathspec" 256 | version = "0.11.1" 257 | description = "Utility library for gitignore style pattern matching of file paths." 258 | category = "main" 259 | optional = false 260 | python-versions = ">=3.7" 261 | files = [ 262 | {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, 263 | {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, 264 | ] 265 | 266 | [[package]] 267 | name = "platformdirs" 268 | version = "3.2.0" 269 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 270 | category = "main" 271 | optional = false 272 | python-versions = ">=3.7" 273 | files = [ 274 | {file = "platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, 275 | {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, 276 | ] 277 | 278 | [package.extras] 279 | docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] 280 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] 281 | 282 | [[package]] 283 | name = "psycopg2-binary" 284 | version = "2.9.5" 285 | description = "psycopg2 - Python-PostgreSQL Database Adapter" 286 | category = "main" 287 | optional = false 288 | python-versions = ">=3.6" 289 | files = [ 290 | {file = "psycopg2-binary-2.9.5.tar.gz", hash = "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c"}, 291 | {file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85"}, 292 | {file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ec46ed947801652c9643e0b1dc334cfb2781232e375ba97312c2fc256597632"}, 293 | {file = "psycopg2_binary-2.9.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3520d7af1ebc838cc6084a3281145d5cd5bdd43fdef139e6db5af01b92596cb7"}, 294 | {file = "psycopg2_binary-2.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cbc554ba47ecca8cd3396ddaca85e1ecfe3e48dd57dc5e415e59551affe568e"}, 295 | {file = "psycopg2_binary-2.9.5-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:5d28ecdf191db558d0c07d0f16524ee9d67896edf2b7990eea800abeb23ebd61"}, 296 | {file = "psycopg2_binary-2.9.5-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:b9c33d4aef08dfecbd1736ceab8b7b3c4358bf10a0121483e5cd60d3d308cc64"}, 297 | {file = "psycopg2_binary-2.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:05b3d479425e047c848b9782cd7aac9c6727ce23181eb9647baf64ffdfc3da41"}, 298 | {file = "psycopg2_binary-2.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1e491e6489a6cb1d079df8eaa15957c277fdedb102b6a68cfbf40c4994412fd0"}, 299 | {file = "psycopg2_binary-2.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:9e32cedc389bcb76d9f24ea8a012b3cb8385ee362ea437e1d012ffaed106c17d"}, 300 | {file = "psycopg2_binary-2.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46850a640df62ae940e34a163f72e26aca1f88e2da79148e1862faaac985c302"}, 301 | {file = "psycopg2_binary-2.9.5-cp310-cp310-win32.whl", hash = "sha256:3d790f84201c3698d1bfb404c917f36e40531577a6dda02e45ba29b64d539867"}, 302 | {file = "psycopg2_binary-2.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:1764546ffeaed4f9428707be61d68972eb5ede81239b46a45843e0071104d0dd"}, 303 | {file = "psycopg2_binary-2.9.5-cp311-cp311-macosx_10_9_universal2.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:426c2ae999135d64e6a18849a7d1ad0e1bd007277e4a8f4752eaa40a96b550ff"}, 304 | {file = "psycopg2_binary-2.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7cf1d44e710ca3a9ce952bda2855830fe9f9017ed6259e01fcd71ea6287565f5"}, 305 | {file = "psycopg2_binary-2.9.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024030b13bdcbd53d8a93891a2cf07719715724fc9fee40243f3bd78b4264b8f"}, 306 | {file = "psycopg2_binary-2.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcda1c84a1c533c528356da5490d464a139b6e84eb77cc0b432e38c5c6dd7882"}, 307 | {file = "psycopg2_binary-2.9.5-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:2ef892cabdccefe577088a79580301f09f2a713eb239f4f9f62b2b29cafb0577"}, 308 | {file = "psycopg2_binary-2.9.5-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:af0516e1711995cb08dc19bbd05bec7dbdebf4185f68870595156718d237df3e"}, 309 | {file = "psycopg2_binary-2.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e72c91bda9880f097c8aa3601a2c0de6c708763ba8128006151f496ca9065935"}, 310 | {file = "psycopg2_binary-2.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e67b3c26e9b6d37b370c83aa790bbc121775c57bfb096c2e77eacca25fd0233b"}, 311 | {file = "psycopg2_binary-2.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5fc447058d083b8c6ac076fc26b446d44f0145308465d745fba93a28c14c9e32"}, 312 | {file = "psycopg2_binary-2.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d892bfa1d023c3781a3cab8dd5af76b626c483484d782e8bd047c180db590e4c"}, 313 | {file = "psycopg2_binary-2.9.5-cp311-cp311-win32.whl", hash = "sha256:2abccab84d057723d2ca8f99ff7b619285d40da6814d50366f61f0fc385c3903"}, 314 | {file = "psycopg2_binary-2.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:bef7e3f9dc6f0c13afdd671008534be5744e0e682fb851584c8c3a025ec09720"}, 315 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:6e63814ec71db9bdb42905c925639f319c80e7909fb76c3b84edc79dadef8d60"}, 316 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:212757ffcecb3e1a5338d4e6761bf9c04f750e7d027117e74aa3cd8a75bb6fbd"}, 317 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f8a9bcab7b6db2e3dbf65b214dfc795b4c6b3bb3af922901b6a67f7cb47d5f8"}, 318 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:56b2957a145f816726b109ee3d4e6822c23f919a7d91af5a94593723ed667835"}, 319 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:f95b8aca2703d6a30249f83f4fe6a9abf2e627aa892a5caaab2267d56be7ab69"}, 320 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:70831e03bd53702c941da1a1ad36c17d825a24fbb26857b40913d58df82ec18b"}, 321 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:dbc332beaf8492b5731229a881807cd7b91b50dbbbaf7fe2faf46942eda64a24"}, 322 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:2d964eb24c8b021623df1c93c626671420c6efadbdb8655cb2bd5e0c6fa422ba"}, 323 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:95076399ec3b27a8f7fa1cc9a83417b1c920d55cf7a97f718a94efbb96c7f503"}, 324 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-win32.whl", hash = "sha256:3fc33295cfccad697a97a76dec3f1e94ad848b7b163c3228c1636977966b51e2"}, 325 | {file = "psycopg2_binary-2.9.5-cp36-cp36m-win_amd64.whl", hash = "sha256:02551647542f2bf89073d129c73c05a25c372fc0a49aa50e0de65c3c143d8bd0"}, 326 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:63e318dbe52709ed10d516a356f22a635e07a2e34c68145484ed96a19b0c4c68"}, 327 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7e518a0911c50f60313cb9e74a169a65b5d293770db4770ebf004245f24b5c5"}, 328 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9d38a4656e4e715d637abdf7296e98d6267df0cc0a8e9a016f8ba07e4aa3eeb"}, 329 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:68d81a2fe184030aa0c5c11e518292e15d342a667184d91e30644c9d533e53e1"}, 330 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:7ee3095d02d6f38bd7d9a5358fcc9ea78fcdb7176921528dd709cc63f40184f5"}, 331 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:46512486be6fbceef51d7660dec017394ba3e170299d1dc30928cbedebbf103a"}, 332 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b911dfb727e247340d36ae20c4b9259e4a64013ab9888ccb3cbba69b77fd9636"}, 333 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:422e3d43b47ac20141bc84b3d342eead8d8099a62881a501e97d15f6addabfe9"}, 334 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c5682a45df7d9642eff590abc73157c887a68f016df0a8ad722dcc0f888f56d7"}, 335 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-win32.whl", hash = "sha256:b8104f709590fff72af801e916817560dbe1698028cd0afe5a52d75ceb1fce5f"}, 336 | {file = "psycopg2_binary-2.9.5-cp37-cp37m-win_amd64.whl", hash = "sha256:7b3751857da3e224f5629400736a7b11e940b5da5f95fa631d86219a1beaafec"}, 337 | {file = "psycopg2_binary-2.9.5-cp38-cp38-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:043a9fd45a03858ff72364b4b75090679bd875ee44df9c0613dc862ca6b98460"}, 338 | {file = "psycopg2_binary-2.9.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9ffdc51001136b699f9563b1c74cc1f8c07f66ef7219beb6417a4c8aaa896c28"}, 339 | {file = "psycopg2_binary-2.9.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15ba5982c177bc4b23a7940c7e4394197e2d6a424a2d282e7c236b66da6d896"}, 340 | {file = "psycopg2_binary-2.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc85b3777068ed30aff8242be2813038a929f2084f69e43ef869daddae50f6ee"}, 341 | {file = "psycopg2_binary-2.9.5-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:215d6bf7e66732a514f47614f828d8c0aaac9a648c46a831955cb103473c7147"}, 342 | {file = "psycopg2_binary-2.9.5-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:7d07f552d1e412f4b4e64ce386d4c777a41da3b33f7098b6219012ba534fb2c2"}, 343 | {file = "psycopg2_binary-2.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a0adef094c49f242122bb145c3c8af442070dc0e4312db17e49058c1702606d4"}, 344 | {file = "psycopg2_binary-2.9.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:00475004e5ed3e3bf5e056d66e5dcdf41a0dc62efcd57997acd9135c40a08a50"}, 345 | {file = "psycopg2_binary-2.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:7d88db096fa19d94f433420eaaf9f3c45382da2dd014b93e4bf3215639047c16"}, 346 | {file = "psycopg2_binary-2.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:902844f9c4fb19b17dfa84d9e2ca053d4a4ba265723d62ea5c9c26b38e0aa1e6"}, 347 | {file = "psycopg2_binary-2.9.5-cp38-cp38-win32.whl", hash = "sha256:4e7904d1920c0c89105c0517dc7e3f5c20fb4e56ba9cdef13048db76947f1d79"}, 348 | {file = "psycopg2_binary-2.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:a36a0e791805aa136e9cbd0ffa040d09adec8610453ee8a753f23481a0057af5"}, 349 | {file = "psycopg2_binary-2.9.5-cp39-cp39-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:25382c7d174c679ce6927c16b6fbb68b10e56ee44b1acb40671e02d29f2fce7c"}, 350 | {file = "psycopg2_binary-2.9.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9c38d3869238e9d3409239bc05bc27d6b7c99c2a460ea337d2814b35fb4fea1b"}, 351 | {file = "psycopg2_binary-2.9.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c6527c8efa5226a9e787507652dd5ba97b62d29b53c371a85cd13f957fe4d42"}, 352 | {file = "psycopg2_binary-2.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e59137cdb970249ae60be2a49774c6dfb015bd0403f05af1fe61862e9626642d"}, 353 | {file = "psycopg2_binary-2.9.5-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:d4c7b3a31502184e856df1f7bbb2c3735a05a8ce0ade34c5277e1577738a5c91"}, 354 | {file = "psycopg2_binary-2.9.5-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:b9a794cef1d9c1772b94a72eec6da144c18e18041d294a9ab47669bc77a80c1d"}, 355 | {file = "psycopg2_binary-2.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5254cbd4f4855e11cebf678c1a848a3042d455a22a4ce61349c36aafd4c2267"}, 356 | {file = "psycopg2_binary-2.9.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c5e65c6ac0ae4bf5bef1667029f81010b6017795dcb817ba5c7b8a8d61fab76f"}, 357 | {file = "psycopg2_binary-2.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:74eddec4537ab1f701a1647214734bc52cee2794df748f6ae5908e00771f180a"}, 358 | {file = "psycopg2_binary-2.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:01ad49d68dd8c5362e4bfb4158f2896dc6e0c02e87b8a3770fc003459f1a4425"}, 359 | {file = "psycopg2_binary-2.9.5-cp39-cp39-win32.whl", hash = "sha256:937880290775033a743f4836aa253087b85e62784b63fd099ee725d567a48aa1"}, 360 | {file = "psycopg2_binary-2.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:484405b883630f3e74ed32041a87456c5e0e63a8e3429aa93e8714c366d62bd1"}, 361 | ] 362 | 363 | [[package]] 364 | name = "pytz" 365 | version = "2023.3" 366 | description = "World timezone definitions, modern and historical" 367 | category = "main" 368 | optional = false 369 | python-versions = "*" 370 | files = [ 371 | {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, 372 | {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, 373 | ] 374 | 375 | [[package]] 376 | name = "setuptools" 377 | version = "67.6.1" 378 | description = "Easily download, build, install, upgrade, and uninstall Python packages" 379 | category = "main" 380 | optional = false 381 | python-versions = ">=3.7" 382 | files = [ 383 | {file = "setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"}, 384 | {file = "setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"}, 385 | ] 386 | 387 | [package.extras] 388 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] 389 | testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] 390 | testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] 391 | 392 | [[package]] 393 | name = "six" 394 | version = "1.16.0" 395 | description = "Python 2 and 3 compatibility utilities" 396 | category = "main" 397 | optional = false 398 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 399 | files = [ 400 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 401 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 402 | ] 403 | 404 | [[package]] 405 | name = "sqlparse" 406 | version = "0.4.3" 407 | description = "A non-validating SQL parser." 408 | category = "main" 409 | optional = false 410 | python-versions = ">=3.5" 411 | files = [ 412 | {file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"}, 413 | {file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"}, 414 | ] 415 | 416 | [[package]] 417 | name = "tinycss2" 418 | version = "1.1.1" 419 | description = "A tiny CSS parser" 420 | category = "main" 421 | optional = false 422 | python-versions = ">=3.6" 423 | files = [ 424 | {file = "tinycss2-1.1.1-py3-none-any.whl", hash = "sha256:fe794ceaadfe3cf3e686b22155d0da5780dd0e273471a51846d0a02bc204fec8"}, 425 | {file = "tinycss2-1.1.1.tar.gz", hash = "sha256:b2e44dd8883c360c35dd0d1b5aad0b610e5156c2cb3b33434634e539ead9d8bf"}, 426 | ] 427 | 428 | [package.dependencies] 429 | webencodings = ">=0.4" 430 | 431 | [package.extras] 432 | doc = ["sphinx", "sphinx_rtd_theme"] 433 | test = ["coverage[toml]", "pytest", "pytest-cov", "pytest-flake8", "pytest-isort"] 434 | 435 | [[package]] 436 | name = "tomli" 437 | version = "1.2.3" 438 | description = "A lil' TOML parser" 439 | category = "main" 440 | optional = false 441 | python-versions = ">=3.6" 442 | files = [ 443 | {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, 444 | {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, 445 | ] 446 | 447 | [[package]] 448 | name = "typing-extensions" 449 | version = "4.5.0" 450 | description = "Backported and Experimental Type Hints for Python 3.7+" 451 | category = "main" 452 | optional = false 453 | python-versions = ">=3.7" 454 | files = [ 455 | {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, 456 | {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, 457 | ] 458 | 459 | [[package]] 460 | name = "webencodings" 461 | version = "0.5.1" 462 | description = "Character encoding aliases for legacy web content" 463 | category = "main" 464 | optional = false 465 | python-versions = "*" 466 | files = [ 467 | {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, 468 | {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, 469 | ] 470 | 471 | [[package]] 472 | name = "win32-setctime" 473 | version = "1.1.0" 474 | description = "A small Python utility to set file creation time on Windows" 475 | category = "main" 476 | optional = false 477 | python-versions = ">=3.5" 478 | files = [ 479 | {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, 480 | {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, 481 | ] 482 | 483 | [package.extras] 484 | dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] 485 | 486 | [[package]] 487 | name = "zipp" 488 | version = "3.15.0" 489 | description = "Backport of pathlib-compatible object wrapper for zip files" 490 | category = "main" 491 | optional = false 492 | python-versions = ">=3.7" 493 | files = [ 494 | {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, 495 | {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, 496 | ] 497 | 498 | [package.extras] 499 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 500 | testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] 501 | 502 | [metadata] 503 | lock-version = "2.0" 504 | python-versions = "^3.9" 505 | content-hash = "fc69279ae6c251223de70e74c3b9c30c677c294715607da4e1f85449c0e426f6" 506 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "django-docker" 3 | version = "0.1.0" 4 | description = "Django template for fast development and deployment using Docker Compose" 5 | authors = ["Denis Matakov "] 6 | license = "MIT License" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.9" 10 | Django = "^3.2.3" 11 | black = "^21.5b1" 12 | gunicorn = "^20.1.0" 13 | psycopg2-binary = "^2.8.6" 14 | django-debug-toolbar = "^3.2.1" 15 | django-markdownify = "^0.9.0" 16 | loguru = "^0.5.3" 17 | django-bulma = "^0.8.3" 18 | 19 | [tool.poetry.dev-dependencies] 20 | 21 | [build-system] 22 | requires = ["poetry-core>=1.0.0"] 23 | build-backend = "poetry.core.masonry.api" 24 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/static/.gitkeep -------------------------------------------------------------------------------- /static/django-docker-sea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matacoder/django-docker/2340fe5a27d2c096d1ef0445b51e0a4e0baeadee/static/django-docker-sea.png -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block title %}Main page{% endblock %} | Django-Docker 8 | 9 | 10 | 11 | 12 |
13 | {% include "includes/navbar.html" %} 14 |
15 |

16 | {% block header %}Main Page{% endblock %} 17 |

18 | 19 | {% block content %} 20 | 21 | {% endblock content %} 22 |
23 |
24 | 25 | -------------------------------------------------------------------------------- /templates/includes/navbar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/includes/pages.html: -------------------------------------------------------------------------------- 1 | {% load tags %} 2 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Django-Docker{% endblock %} 4 | {% block header %}{% endblock %} 5 | 6 | {% block content %} 7 | {% load markdownify %} 8 | 9 |
10 |
11 |

Version 2.0

12 | 13 |
14 |
15 |

16 | New Django-Docker version now uses Bulma.io for rendering styles.

17 |
18 |
19 |
20 | {{ markdowntext|markdownify }} 21 |
22 | {% endblock %} 23 | --------------------------------------------------------------------------------