Как реализовать страницу предварительного просмотра с файлами Django?

У меня есть модель News:

class News(models.Model):
    subject = models.CharField(max_length=30)
    text = models.TextField()
    created = models.DateTimeField(auto_now_add=True)

У меня также есть модель File для хранения файлов и модель NewsFile для связи моделей друг с другом:

class File(models.Model):
    file = models.FileField(
        'файл'
    )


class NewsFile(models.Model):
    file = models.ForeignKey(
        File,
        on_delete=models.CASCADE,
        verbose_name='файл',
        related_name='news_files'
    )
    news = models.ForeignKey(
        News,
        on_delete=models.CASCADE,
        verbose_name='новость',
        related_name='files'
    )

Вот моя новостная форма:

class MultipleFileInput(forms.ClearableFileInput):
    allow_multiple_selected = True


class MultipleFileField(forms.FileField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault("widget", MultipleFileInput())
        super().__init__(*args, **kwargs)

    def clean(self, data, initial=None):
        single_file_clean = super().clean
        if isinstance(data, (list, tuple)):
            result = [single_file_clean(d, initial) for d in data]
        else:
            result = single_file_clean(data, initial)
        return result


class NewsForm(forms.ModelForm):
    files = MultipleFileField(required=False)

    class Meta:
        model = News
        fields = ('subject', 'text')

Хочу сделать страницу с предпросмотром новостей и кнопками для публикации или редактирования новостей. Я начал реализовывать кнопку публикации, но не могу передать файлы через форму. Мой взгляд:

    def form_valid(self, form):
        files = form.cleaned_data.get('files')

        if self.request.GET.get('save') == 'true':
            res = super().form_valid(form)

            for file in files:
                file_obj = File.objects.create(file=file)
                NewsFile.objects.create(news=self.object, file=file_obj)

            return res

        img_files = []
        non_img_files = []
        for file in files:
            if file.name.split('.')[-1] in settings.IMAGE_FORMATS:
                img_files.append(file)
            else:
                non_img_files.append(file)

        images = []
        for file in img_files:
            encoded = b64encode(file.read())
            b64str = encoded.decode('utf-8')
            mime = 'image/jpeg'
            mime = mime + ";" if mime else ";"
            images.append('data:%sbase64,%s' % (mime, b64str))

        context = {
            'form': form,
            'images': images,
            'non_img_files': non_img_files,
            'date': datetime.datetime.now()
        }

        return render(
            self.request,
            'news/news_preview.html',
            context=context
        )

Форма отображается в HTML без файлов.

<nav class="navbar">
    <div class="container">
      <a class="btn btn-secondary grey-btn" href="#">edit</a>
      <form method="post" enctype="multipart/form-data" action="{% url 'news:news_create' %}?save=true">
        {% csrf_token %}
        {% for field in form %}
        {{ field|hidden }}
        {% endfor %}
        <button type="submit" class="btn btn-secondary grey-btn">publish</button>
      </form>
    </div>
  </nav>

Надеюсь, я достаточно ясно объяснил суть проблемы. Прошу прощения за языковые ошибки.

Я думаю о сохранении новостей без их публикации или кэшировании файлов, но я не думаю, что это хороший подход.

Вернуться на верх