Переопределение метода "save()" ModelForm

Как вы знаете, ModelForm предоставляет метод save() для сохранения текущего экземпляра модели в базе данных и возврата объекта. Этот метод получает логический boolean commit параметр, который позволяет указать, должен ли объект сохраняться в базе данных. Если commit имеет значение False, метод save() вернет экземпляр модели, но не сохранит его в базе данных. Мы собираемся переопределить метод save() нашей формы, чтобы извлечь заданное изображение и сохранить его.

Добавьте следующие импортируемые компоненты в верхнюю часть файла forms.py:

from urllib import request
from django.core.files.base import ContentFile
from django.utils.text import slugify

Затем добавьте метод save() в ImageCreateForm:

def save(self, force_insert=False, force_update=False, commit=True):
    image = super(ImageCreateForm, self).save(commit=False)
    image_url = self.cleaned_data['url']
    image_name = '{}.{}'.format(slugify(image.title), image_url.rsplit('.', 1)[1].lower())

    # download image from the given URL
    response = request.urlopen(image_url)
    image.image.save(image_name, ContentFile(response.read()), save=False)
    if commit:
        image.save()
    return image

Мы переопределяем метод save(), сохраняя параметры, необходимые для ModelForm. Этот код выглядит следующим образом:

Мы создаем новый экземпляр image, вызвав метод save() формы с commit=False.

Мы получим URL-адрес из cleaned_data словаря формы.

Имя изображения создается путем объединения служебного заголовка изображения с исходным расширением файла.

Мы используем модуль Python urllib для загрузки изображения, а затем вызываем метод save() поля image, передав ему объект ContentFile, который создается с помощью загружаемого содержимого файла. Таким образом мы сохраняем файл в каталог мультимедиа нашего проекта. Мы также перейдем к параметру save=False, чтобы избежать сохранения объекта в базе данных.

Чтобы сохранить то же поведение, что и метод save(), который мы переопределяем, мы сохраняем форму в базу данных только в том случае, если параметр commit True.

Теперь нам нужен view для обработки формы. Отредактируйте файл views.py приложения images и добавьте в него следующий код:

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .forms import ImageCreateForm

@login_required
def image_create(request):
    if request.method == 'POST':
        # form is sent
        form = ImageCreateForm(data=request.POST)
        if form.is_valid():
            # form data is valid
            cd = form.cleaned_data
            new_item = form.save(commit=False)

            # assign current user to the item
            new_item.user = request.user
            new_item.save()
            messages.success(request, 'Image added successfully')

            # redirect to new created item detail view
            return redirect(new_item.get_absolute_url())
    else:
        # build form with data provided by the bookmarklet via GET
        form = ImageCreateForm(data=request.GET)
    return render(request, 'images/image/create.html', {'section': 'images', 'form': form})

Мы добавляем декоратор login_required в представление image_create, чтобы запретить доступ для неавторизованых пользователей. Вот как это представление работает:

  1. Мы ожидаем, что исходные данные с помощью GET будут созданы в порядке создания экземпляра формы. Эти данные будут состоять из атрибутов url и title изображения с внешнего веб-сайта и будут предоставлены через GET с помощью средств JavaScript, которое будет создано позже
  2. Если форма отправлена, мы проверяем ее валидность. Если форма валидна, мы создаем новый экземпляр Image, но мы не можем сохранить объект в базе данных, передав commit=False
  3. Мы присваиваем текущему пользователю новый объект image. Таким образом мы знаем, какой именно пользователь загрузил изображение
  4. Мы сохраняем объект изображения в базу данных
  5. Наконец, мы создаем сообщение об успехе с помощью системы «Джанго» и перенаправляем пользователя к URL-адресу нового изображения. Мы еще не реализовали метод get_absolute_url() модели Image, мы сделаем это позже.

Создайте новый файл urls.py в приложении images и добавьте в него следующий код:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^create/$', views.image_create, name='create'),
]

Измените основной файл urls.py проекта, включив в него шаблоны, которые были только что созданы для приложения images:

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^account/', include('account.urls')),
    url(r'^images/', include('images.urls', namespace='images')),
]

Наконец, необходимо создать шаблон для визуализации формы. Создайте следующую структуру каталогов в каталоге приложения images:

templates/
    images/
        image/
            create.html

Отредактируйте новый шаблон create.html и добавьте в него следующий код:

{% extends "base.html" %}

{% block title %}Bookmark an image{% endblock %}

{% block content %}
    <h1>Bookmark an image</h1>
    <img src="{{ request.GET.url }}" class="image-preview">
    <form action="." method="post">
        {{ form.as_p }}
        {% csrf_token %}
        <input type="submit" value="Bookmark it!">
    </form>
{% endblock %}

Теперь откройте в браузере http://127.0.0.1:8000/images/create/?title=%20Django%20and%20Duke&url=http://upload.wikimedia.org/wikipedia/commons/8/85/Django\_Reinhardt\_and\_Duke\_Ellington\_%28Gottlieb%29.jpg .

Форма отобразится с предварительным просмотром изображения, как в следующем примере:

Добавьте описание и нажмите кнопку Bookmark it!. Новый объект Image будет сохранен в базе данных. Появится сообщение об ошибке, показывающее, что модель изображения не имеет get_absolute_url(). Не волнуйтесь об этом сейчас, мы собираемся добавить этот метод позже. Откройте в браузере http://127.0.0.1:8000/admin/images/image/ и убедитесь, что новый объект изображения сохранен.

results matching ""

    No results matching ""