Created
May 12, 2026 09:26
-
-
Save sunmeat/25cecce643e41278fbe2fc15636ccd41 to your computer and use it in GitHub Desktop.
збереження файлів та зображень на сервері (MEDIA_ROOT / MEDIA_URL)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| settings.py: | |
| import os # !!! | |
| import posixpath | |
| from pathlib import Path | |
| BASE_DIR = Path(__file__).resolve().parent.parent | |
| SECRET_KEY = '545bb8a0-f016-4d1b-8b4f-22bd108e577a' | |
| DEBUG = True | |
| ALLOWED_HOSTS = [] | |
| INSTALLED_APPS = [ | |
| 'app', | |
| 'django.contrib.admin', | |
| 'django.contrib.auth', | |
| 'django.contrib.contenttypes', | |
| 'django.contrib.sessions', | |
| 'django.contrib.messages', | |
| 'django.contrib.staticfiles', | |
| ] | |
| MIDDLEWARE = [ | |
| 'django.middleware.security.SecurityMiddleware', | |
| 'django.contrib.sessions.middleware.SessionMiddleware', | |
| 'django.middleware.common.CommonMiddleware', | |
| 'django.middleware.csrf.CsrfViewMiddleware', | |
| 'django.contrib.auth.middleware.AuthenticationMiddleware', | |
| 'django.contrib.messages.middleware.MessageMiddleware', | |
| 'django.middleware.clickjacking.XFrameOptionsMiddleware', | |
| ] | |
| ROOT_URLCONF = 'Forms.urls' | |
| TEMPLATES = [ | |
| { | |
| 'BACKEND': 'django.template.backends.django.DjangoTemplates', | |
| 'DIRS': [], | |
| 'APP_DIRS': True, | |
| 'OPTIONS': { | |
| 'context_processors': [ | |
| 'django.template.context_processors.debug', | |
| 'django.template.context_processors.request', | |
| 'django.contrib.auth.context_processors.auth', | |
| 'django.contrib.messages.context_processors.messages', | |
| ], | |
| }, | |
| }, | |
| ] | |
| WSGI_APPLICATION = 'Forms.wsgi.application' | |
| DATABASES = { | |
| 'default': { | |
| 'ENGINE': 'django.db.backends.sqlite3', | |
| 'NAME': BASE_DIR / 'db.sqlite3', | |
| } | |
| } | |
| AUTH_PASSWORD_VALIDATORS = [ | |
| {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, | |
| {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'}, | |
| {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, | |
| {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, | |
| ] | |
| LANGUAGE_CODE = 'uk' | |
| TIME_ZONE = 'Europe/Kiev' | |
| USE_I18N = True | |
| USE_TZ = True | |
| # !!! STATIC & MEDIA !!! | |
| STATIC_URL = '/static/' | |
| STATIC_ROOT = BASE_DIR / 'static' | |
| # медіа-файли (завантажені користувачами) | |
| MEDIA_URL = '/media/' | |
| MEDIA_ROOT = BASE_DIR / 'media' | |
| # DEFAULT_AUTO_FIELD - це налаштування, яке визначає тип поля, що використовується за замовчуванням для автоматичних первинних ключів у моделях Django | |
| # у цьому випадку встановлено 'django.db.models.BigAutoField', що означає, що всі автоматичні первинні ключі будуть використовувати тип BigAutoField, який є 64-бітовим цілим числом і може зберігати значно більше значень, ніж стандартний AutoField (32-бітовий) | |
| # це корисно для проєктів, які можуть мати велику кількість записів у БД | |
| DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' | |
| ================================================================================================================ | |
| views.py: | |
| import os | |
| from datetime import datetime | |
| from pathlib import Path | |
| from django.http import HttpRequest | |
| from django.shortcuts import render, redirect | |
| from django.contrib import messages | |
| from .forms import ContactForm | |
| def contact(request): | |
| """Обробка форми відправки резюме""" | |
| if request.method == 'POST': | |
| form = ContactForm(request.POST, request.FILES) | |
| if form.is_valid(): | |
| resume = form.cleaned_data.get('resume_file') | |
| avatar = form.cleaned_data.get('avatar') | |
| # !!! збереження файлів на сервері (у папках media/resumes та media/avatars) | |
| saved_files = [] | |
| # створюються папки, якщо їх немає | |
| media_root = Path('media') | |
| (media_root / 'resumes').mkdir(parents=True, exist_ok=True) | |
| (media_root / 'avatars').mkdir(parents=True, exist_ok=True) | |
| # збереження резюме | |
| if resume: | |
| # унікальне ім'я | |
| ext = os.path.splitext(resume.name)[1].lower() | |
| new_filename = f"resume_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}" | |
| file_path = media_root / 'resumes' / new_filename | |
| with open(file_path, 'wb+') as destination: | |
| for chunk in resume.chunks(): | |
| destination.write(chunk) | |
| saved_files.append(f"Резюме: {new_filename}") | |
| # збереження аватарки | |
| if avatar: | |
| ext = os.path.splitext(avatar.name)[1].lower() | |
| new_filename = f"avatar_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}" | |
| file_path = media_root / 'avatars' / new_filename | |
| with open(file_path, 'wb+') as destination: | |
| for chunk in avatar.chunks(): | |
| destination.write(chunk) | |
| saved_files.append(f"Фото: {new_filename}") | |
| # вивід в термінал | |
| print("\n" + "="*80) | |
| print("НОВЕ РЕЗЮМЕ ОТРИМАНО!") | |
| print("="*80) | |
| print(f"Дата та час: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") | |
| print("-" * 80) | |
| for field_name, value in form.cleaned_data.items(): | |
| label = form.fields[field_name].label or field_name | |
| print(f"{label:35} : {value}") | |
| if saved_files: | |
| print("-" * 80) | |
| for file_info in saved_files: | |
| print(file_info) | |
| print("="*80 + "\n") | |
| messages.success(request, 'Резюме успішно надіслано! Дякуємо.') | |
| return redirect('contact') # залишаємо на сторінці форми | |
| else: | |
| messages.error(request, 'Будь ласка, виправте помилки у формі.') | |
| else: | |
| form = ContactForm() | |
| return render(request, 'app/contact.html', { | |
| 'form': form, | |
| 'title': 'Відправка резюме', | |
| 'year': datetime.now().year, | |
| }) | |
| def home(request): | |
| return render(request, 'app/index.html', { | |
| 'title': 'Home Page', | |
| 'year': datetime.now().year, | |
| }) | |
| def about(request): | |
| return render(request, 'app/about.html', { | |
| 'title': 'About', | |
| 'message': 'Your application description page.', | |
| 'year': datetime.now().year, | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment