Создаем форму загрузки файлов в Django

GuDron

dumpz.ws
Admin
Регистрация
28 Янв 2020
Сообщения
7,794
Реакции
1,451
Credits
25,448
6HyxK-min.png
В данном руководстве показано, как реализовать загрузку файлов с Django. Для этого создадим простой клон Instagram, который будет работать с изображениями.

Установка 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
 

GuDron

dumpz.ws
Admin
Регистрация
28 Янв 2020
Сообщения
7,794
Реакции
1,451
Credits
25,448

Создаем модели в 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
 

GuDron

dumpz.ws
Admin
Регистрация
28 Янв 2020
Сообщения
7,794
Реакции
1,451
Credits
25,448

Панель администратора (админка) в 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

Если набрать в адресной строке браузера Для просмотра ссылки Войди или Зарегистрируйся, появится возможность зайти в админку Django. Вы будете направлены на следующую страницу:
Создаем форму загрузки файлов в Django


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

Скачать картинку можно тут Для просмотра ссылки Войди или Зарегистрируйся.

Создаем форму загрузки файлов в Django


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

Создаем форму загрузки файлов в Django


Теперь если вы загляните в папку media в вашем проекте, то увидите, что в директории images появилось изображение djangopony.png. Как и было сказано ранее, MEDIA_URL нужен именно для этого.

Итак, с основами мы разобрались. Теперь разберемся с тем, как отображать записи, использовать urls.py, views.py и шаблоны файлов.
 

GuDron

dumpz.ws
Admin
Регистрация
28 Янв 2020
Сообщения
7,794
Реакции
1,451
Credits
25,448

Настройка 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 команду Для просмотра ссылки Войди или Зарегистрируйся.
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.
 

GuDron

dumpz.ws
Admin
Регистрация
28 Янв 2020
Сообщения
7,794
Реакции
1,451
Credits
25,448

Шаблоны 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 и перейдите на домашнюю страницу Для просмотра ссылки Войди или Зарегистрируйся. В случае необходимости перезагрузите страницу.
Создаем форму загрузки файлов в Django

Вуаля! Если вы добавите дополнительные посты с заголовками и картинками от имени администратора, то они появятся на домашней странице.
 

GuDron

dumpz.ws
Admin
Регистрация
28 Янв 2020
Сообщения
7,794
Реакции
1,451
Credits
25,448

Форма для добавления записи в Django​

Теперь мы можем создать html форму для того, чтобы обычные пользователи без доступа в админку могли также добавлять записи и загружать файлы. Это предполагает создание новой страницы при помощи формы.
Давайте начнем с файла views.py. Назовем новое представление CreatePostView. Оно расширит встроенное в Django Для просмотра ссылки Войди или Зарегистрируйся. Также импортируем 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 Для просмотра ссылки Войди или Зарегистрируйся. Здесь у базовой формы потребуется уточнить правильную модель 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>

Вот и оно! Убедитесь, что сервер запущен, и перейдите на страницу Для просмотра ссылки Войди или Зарегистрируйся.
Создаем форму загрузки файлов в Django

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

Следующие шаги​

И что теперь? Многим наверняка захочется наложить определенные ограничения на размер картинки. Это можно сделать в файле models.py или при помощи CSS. Также многим наверняка захочется добавить опции редактирования или удаления для записей.

Ввиду важного обновления, не рекомендуется размещать файлы в Django. Лучше настроить выделенную внешнюю службу, например, сеть доставки контента Content Delivery Network (CDN).