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

8218

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

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

В данном руководстве показано, как реализовать загрузку файлов с Django. Для этого создадим простой клон Instagram, который будет работать с изображениями.

Установка Django в Python 3

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

Откройте командную строку и создайте директорию insta для хранения файлов. Для установки как Django, так и Pillow мы будем использовать Pipenv . Pillow является библиотекой для обработки изображений. Для загрузки других типов файлов Pillow не понадобится.

Активируем новую виртуальную среду:

$ 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.

(insta) $ django-admin startproject insta_project .
(insta) $ python manage.py startapp posts

Так как мы добавили новое приложение, мы должны сообщить об этом Django в нижней части конфигурации INSTALLED_APPS в settings.py.

# 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 для установки базы данных нового проекта.

(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.

# 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, который мы можем использовать в шаблонах для файлов.
# insta_project/settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Название media использовать не обязательно, можно выбрать любое, просто в Django media используется по умолчанию. Мы также создаем папку images внутри для простоты навигации.

(insta) $ mkdir media
(insta) $ mkdir media/images

Панель администратора (админка) в Django

Сейчас мы обновим файл posts/admin.py, после чего в Django появится возможность использовать приложение Post от имени администратора.

# posts/admin.py
from django.contrib import admin

from .models import Post

admin.site.register(Post)

Все настроено! Генерируем новый файл миграции.

(insta) $ python manage.py makemigrations
Migrations for 'posts':
  posts/migrations/0001_initial.py
    - Create model Post

Теперь запускаем migrate для обновления базы данных.

(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 для первого запуска локального веб-сервера:

(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.pyviews.py и шаблоны файлов.

Настройка urls.py в Django

Аспектом работы с Django, который может несколько запутать, является тот факт, что зачастую для одной веб-страницы требуется 4 разных, но взаимосвязанных файла: models.pyurls.pyviews.py и html-шаблоны. Здесь мы будем разбирать понятия в следующем порядке: модели (models) -> urls -> представления (views) -> шаблоны  (templates). С моделью мы уже разобрались, так что перейдем к URL.

Нам понадобятся обновить файл urls.py. Вначале на проектном уровне insta_project/urls.py мы добавим импорты для settingsinclude и static.

После этого мы определим путь для приложения posts. Стоит отметить, что если настройки в режиме DEBUG, то MEDIA_URL также нужно добавить. В противном случае не получится увидеть загружаемые изображения.

# 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.

(insta) $ touch posts/urls.py

Затем мы вынесем все записи на главную страницу, для этого используем пустую строку '' в качестве пути.

# 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.

# 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.

$ mkdir templates
$ touch templates/home.html

Далее укажем Django, чтобы он также рассматривал данную директорию при поиске шаблонов, обновив конфигурацию TEMPLATES в insta_project/settings.py.

# insta_project/settings.py
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')], # new
        ...
    },
]

Файл шаблона home.html показывает title и image всех наших записей. В Instagram все было бы так же.

<!-- 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. В случае необходимости перезагрузите страницу.

# posts/forms.py
from django import forms
from .models import Post

class PostForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = ['title', 'cover']

Для формы создается специальная страницы, URL-путь которой post/.

# 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
]

Создаем новый шаблон.

(insta) $ touch templates/post.html

Вносим в него заголовок и форму. Для защиты важно всегда добавляйте csrf_token. Уточняем form.as_p, из-за чего Django выведет каждое поле в виде отдельного  параграфа.

<!-- 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).

источник