В данном руководстве показано, как реализовать загрузку файлов с Django. Для этого создадим простой клон Instagram, который будет работать с изображениями.
Содержание
- Установка Django в Python 3
- Создание проекта и приложения в Django
- Создаем модели в Django
- Настройка MEDIA_ROOT в Django 2
- Панель администратора (админка) в Django
- Настройка urls.py в Django
- Представления views в Django
- Шаблоны templates в Django
- Форма для добавления записи в Django
Установка Django в Python 3
Для простоты папку с обучающим примером лучше поместить на рабочем столе, но в общем и целом расположение особого значения не имеет. Главное, чтобы директория проекта была легко доступной.
Откройте командную строку и создайте директорию insta для хранения файлов. Для установки как Django, так и Pillow мы будем использовать Pipenv . Pillow является библиотекой для обработки изображений. Для загрузки других типов файлов Pillow не понадобится.
Активируем новую виртуальную среду:
|
1 2 3 4 5 |
$ cd ~/Desktop $ mkdir insta && cd insta $ pipenv install django==2.1.5 pillow==5.4.1 $ pipenv shell (insta) $ |
Об активации виртуальной среды сообщит изменение в (insta). Вы также можете в любое время ввести команду exit для выхода и pipenv shell для повторного входа.
Создание проекта и приложения в Django
Создадим новый проект Django под названием insta_project и новое приложение, которое назовем posts.
|
1 2 |
(insta) $ django-admin startproject insta_project . (insta) $ python manage.py startapp posts |
Так как мы добавили новое приложение, мы должны сообщить об этом Django в нижней части конфигурации INSTALLED_APPS в settings.py.
|
1 2 3 4 5 6 7 8 9 10 |
# insta_project/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'posts.apps.PostsConfig', # новое ] |
Теперь запускаем python manage.py migrate для установки базы данных нового проекта.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
(insta) $ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying sessions.0001_initial... OK |
Создаем модели в Django
Лучше всего начинать с модели базы данных. В нашем случае у модели Post будет только два поля: title и cover. Ниже мы также добавим метод __str__(), чтобы title отобразился в интерфейсе администратора Django.
|
1 2 3 4 5 6 7 8 9 10 |
# posts/models.py from django.db import models class Post(models.Model): title = models.TextField() cover = models.ImageField(upload_to='images/') def __str__(self): return self.title |
Местоположение загружаемых файлов image будет в MEDIA_ROOT/images. В Django локацией для MEDIA_ROOT по умолчанию является папка, откуда будут загружаться все файлы пользователя.
В случае, когда вместо изображения требуется загрузить другой файл, нужно просто поменять ImageField на FileField.
Настройка MEDIA_ROOT в Django 2
Откройте insta_project/settings.py в вашем текстовом редакторе. Нам потребуется добавить две новые конфигурации. По умолчанию MEDIA_URL и MEDIA_ROOT являются пустыми и не отображаются на экране, поэтому их необходимо настроить:
MEDIA_ROOTявляется путем файловой системы, куда пользователи будут загружать файлы;MEDIA_URLпредставляет собой URL, который мы можем использовать в шаблонах для файлов.
|
1 2 3 |
# insta_project/settings.py MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') |
Название media использовать не обязательно, можно выбрать любое, просто в Django media используется по умолчанию. Мы также создаем папку images внутри для простоты навигации.
|
1 2 |
(insta) $ mkdir media (insta) $ mkdir media/images |
Панель администратора (админка) в Django
Сейчас мы обновим файл posts/admin.py, после чего в Django появится возможность использовать приложение Post от имени администратора.
|
1 2 3 4 5 6 |
# posts/admin.py from django.contrib import admin from .models import Post admin.site.register(Post) |
Все настроено! Генерируем новый файл миграции.
|
1 2 3 4 |
(insta) $ python manage.py makemigrations Migrations for 'posts': posts/migrations/0001_initial.py - Create model Post |
Теперь запускаем migrate для обновления базы данных.
|
1 2 3 4 5 6 |
(insta) $ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, posts, session s Running migrations: Applying posts.0001_initial... OK |
Теперь можно создать аккаунт superuser для доступа к интерфейсу администратора, после чего выполнить runserver для первого запуска локального веб-сервера:
|
1 2 |
(insta) $ python manage.py createsuperuser (insta) $ python manage.py runserver |
Если набрать в адресной строке браузера http://127.0.0.1:8000/admin, появится возможность зайти в админку Django. Вы будете направлены на следующую страницу:

Нажмите на + Add возле Posts. Здесь можно добавить все, что хотите, однако в данном руководстве мы создаем запись с изображением талисмана Django — пони.
Скачать картинку можно тут Django Pony.

После нажатия «Save» вы будете перенаправлены на страницу Posts, где расположены все имеющиеся записи.

Теперь если вы загляните в папку media в вашем проекте, то увидите, что в директории images появилось изображение djangopony.png. Как и было сказано ранее, MEDIA_URL нужен именно для этого.
Итак, с основами мы разобрались. Теперь разберемся с тем, как отображать записи, использовать urls.py, views.py и шаблоны файлов.
Настройка urls.py в Django
Аспектом работы с Django, который может несколько запутать, является тот факт, что зачастую для одной веб-страницы требуется 4 разных, но взаимосвязанных файла: models.py, urls.py, views.py и html-шаблоны. Здесь мы будем разбирать понятия в следующем порядке: модели (models) -> urls -> представления (views) -> шаблоны (templates). С моделью мы уже разобрались, так что перейдем к URL.
Нам понадобятся обновить файл urls.py. Вначале на проектном уровне insta_project/urls.py мы добавим импорты для settings, include и static.
После этого мы определим путь для приложения posts. Стоит отметить, что если настройки в режиме DEBUG, то MEDIA_URL также нужно добавить. В противном случае не получится увидеть загружаемые изображения.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# insta_project/urls.py from django.contrib import admin from django.conf import settings # new from django.urls import path, include # new from django.conf.urls.static import static # new urlpatterns = [ path('admin/', admin.site.urls), path('', include('posts.urls')), # new ] if settings.DEBUG: # new urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
Далее необходимо рассортировать пути URL в пределах приложения posts. Первым делом создается файл через linux команду touch.
|
1 |
(insta) $ touch posts/urls.py |
Затем мы вынесем все записи на главную страницу, для этого используем пустую строку '' в качестве пути.
|
1 2 3 4 5 6 7 8 |
# posts/urls.py from django.urls import path from .views import HomePageView urlpatterns = [ path('', HomePageView.as_view(), name='home'), ] |
Это будет связано с представлением (view) HomePageView, созданием которого мы займемся далее.
Представления views в Django
Здесь можно использовать обычный ListView, основанный на классе, а затем импортировать модель Post. После этого надо создать HomePageView, что использует данную модель, а также шаблон под названием home.html.
|
1 2 3 4 5 6 7 8 |
# posts/views.py from django.views.generic import ListView from .models import Post class HomePageView(ListView): model = Post template_name = 'home.html' |
Теперь переходим к файлу-шаблону под названием home.html.
Шаблоны templates в Django
При выборе локации для шаблона есть два варианта. Мы могли бы поместить его в posts, что расположен в posts/templates/posts/home.html, но тогда структура станет избыточной. Кроме того, если шаблоны расположены глубоко в папках своих приложений, их будет сложнее разбирать. Именно поэтому для урока на проектном уровне мы создадим отдельную директорию templates.
|
1 2 |
$ mkdir templates $ touch templates/home.html |
Далее укажем Django, чтобы он также рассматривал данную директорию при поиске шаблонов, обновив конфигурацию TEMPLATES в insta_project/settings.py.
|
1 2 3 4 5 6 7 8 |
# insta_project/settings.py TEMPLATES = [ { ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], # new ... }, ] |
Файл шаблона home.html показывает title и image всех наших записей. В Instagram все было бы так же.
|
1 2 3 4 5 6 7 8 |
<!-- templates/home.html --> <h1>Django Image Uploading</h1> <ul> {% for post in object_list %} <h2>{{ post.title }}</h2> <img src="{{ post.cover.url}}" alt="{{ post.title }}"> {% endfor %} </ul> |
Вот и все. Запустите сервер командой python manage.py runserver и перейдите на домашнюю страницу http://127.0.0.1:8000. В случае необходимости перезагрузите страницу.

Вуаля! Если вы добавите дополнительные посты с заголовками и картинками от имени администратора, то они появятся на домашней странице.
Форма для добавления записи в Django
Теперь мы можем создать html форму для того, чтобы обычные пользователи без доступа в админку могли также добавлять записи и загружать файлы. Это предполагает создание новой страницы при помощи формы.
Давайте начнем с файла views.py. Назовем новое представление CreatePostView. Оно расширит встроенное в Django CreateView. Также импортируем reverse_lazy, который отвечает за возвращение на домашнюю страницу после отправки формы через POST запрос.
В представлении мы указываем model, form_class, что будет создан далее, template_name и, конечно же, success_url, который будет получен после отправки.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# posts/views.py from django.views.generic import ListView, CreateView # новый from django.urls import reverse_lazy # новый from .forms import PostForm # новый from .models import Post class HomePageView(ListView): model = Post template_name = 'home.html' class CreatePostView(CreateView): # новый model = Post form_class = PostForm template_name = 'post.html' success_url = reverse_lazy('home') |
Займемся формой. Она создается следующим образом:
|
1 |
(insta) $ touch posts/forms.py |
Мы можем расширить встроенный в Django ModelForm. Здесь у базовой формы потребуется уточнить правильную модель Post и названия выводимых на экран полей. В данном случае это title и cover.
|
1 2 3 4 5 6 7 8 9 |
# posts/forms.py from django import forms from .models import Post class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'cover'] |
Для формы создается специальная страницы, URL-путь которой post/.
|
1 2 3 4 5 6 7 8 9 |
# posts/urls.py from django.urls import path from .views import HomePageView, CreatePostView # new urlpatterns = [ path('', HomePageView.as_view(), name='home'), path('post/', CreatePostView.as_view(), name='add_post') # new ] |
Создаем новый шаблон.
|
1 |
(insta) $ touch templates/post.html |
Вносим в него заголовок и форму. Для защиты важно всегда добавляйте csrf_token. Уточняем form.as_p, из-за чего Django выведет каждое поле в виде отдельного параграфа.
|
1 2 3 4 5 6 7 |
<!-- templates/post.html --> <h1>Create Post Page</h1> <form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">Submit New Post</button> </form> |
Вот и оно! Убедитесь, что сервер запущен, и перейдите на страницу http://127.0.0.1:8000/post/.

После подтверждения создания новой записи вы будете перенаправлены на домашнюю страницу, где отображаются все имеющиеся посты.
Следующие шаги
И что теперь? Многим наверняка захочется наложить определенные ограничения на размер картинки. Это можно сделать в файле models.py или при помощи CSS. Также многим наверняка захочется добавить опции редактирования или удаления для записей.
Ввиду важного обновления, не рекомендуется размещать файлы в Django. Лучше настроить выделенную внешнюю службу, например, сеть доставки контента Content Delivery Network (CDN).

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»