Как я могу реализовать возможность загрузки нескольких изображений одновременно в административной панели?

Я хотел бы реализовать функционал в админской панели, который позволит загружать несколько изображений одновременно. В данный момент я использую inline поле, но оно позволяет добавлять только по одному объекту. Я перешел на использование формы, и, похоже, это работает, но есть один нюанс: мне нужно, чтобы по нажатию кнопки добавлялась еще одна форма, позволяющая загружать еще набор изображений и также удалять уже добавленные. Можете подсказать, как это можно реализовать? Вот мой код: <br/> <pre><code class="python">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 ProductForm(forms.ModelForm):
    images = MultipleFileField(required=False)  # Поле для загрузки нескольких изображений

    class Meta:
        model = Product
        fields = [
                  'name', 
                  'category', 
                  'price', 
                  'stock_quantity', 
                  'is_new', 
                  'is_on_sale',
                  'colors',
                  'sizes',
                  'description',
                  'compositions',
                  'images',
                  ]  

    def clean_images(self):
        images = self.cleaned_data.get('images')
        if isinstance(images, list):
            return images
        #  <...>
  • 20 ноября 2024 г. 0:53
Ответы на вопрос 1
Для того чтобы реализовать возможность загрузки нескольких изображений одновременно с динамическим добавлением форм в админской панели, вам нужно будет немного модифицировать как форму, так и JavaScript, который отвечает за добавление и удаление форм на клиентской стороне. Ниже приведены шаги и пример кода, который поможет вам это сделать.

1. **Создайте форму для изображения**:
   Вам нужно создать модель для изображений и соответствующую форму. Например, у вас может быть модель `Image`, которая связана с `Product`:

   ```python
   from django.db import models

   class Image(models.Model):
       product = models.ForeignKey(Product, related_name='images', on_delete=models.CASCADE)
       image = models.ImageField(upload_to='product_images/')
   ```

   Затем создайте форму для изображения:

   ```python
   class ImageForm(forms.ModelForm):
       class Meta:
           model = Image
           fields = ['image']
   ```

2. **Измените основную форму продукта**:
   Измените вашу форму `ProductForm`, чтобы использовать `InlineFormSet` для обработки нескольких изображений, но динамически добавляя их в интерфейсе:

   ```python
   from django.forms import modelformset_factory

   class ProductForm(forms.ModelForm):
       class Meta:
           model = Product
           fields = [
               'name', 
               'category', 
               'price', 
               'stock_quantity', 
               'is_new', 
               'is_on_sale',
               'colors',
               'sizes',
               'description',
               'compositions',
           ]

   ImageFormSet = modelformset_factory(Image, form=ImageForm, extra=1, can_delete=True)
   ```

3. **Создание представления**:
   Теперь создайте представление, которое будет обрабатывать отправку формы и формы изображений:

   ```python
   from django.shortcuts import render, redirect

   def product_create_view(request):
       if request.method == "POST":
           product_form = ProductForm(request.POST)
           formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.none())
           if product_form.is_valid() and formset.is_valid():
               product = product_form.save()
               images = formset.save(commit=False)
               for image in images:
                   image.product = product
                   image.save()
               return redirect('product_list')  # Замените на ваш путь
       else:
           product_form = ProductForm()
           formset = ImageFormSet(queryset=Image.objects.none())

       return render(request, 'product_form.html', {
           'product_form': product_form,
           'formset': formset,
       })
   ```

4. **Создание шаблона**:
   В вашем шаблоне (`product_form.html`) добавьте JavaScript для динамического добавления и удаления форм:

   ```html
   <form method="post" enctype="multipart/form-data">
       {% csrf_token %}
       {{ product_form.as_p }}
       <div id="image-formset">
           {{ formset.management_form }}
           {% for form in formset %}
               <div class="form-row">
                   {{ form.as_p }}
                   <button type="button" class="remove-form">Удалить</button>
               </div>
           {% endfor %}
       </div>
       <button type="button" id="add-image">Добавить изображение</button>
       <button type="submit">Сохранить</button>
   </form>

   <script>
   document.getElementById('add-image').addEventListener('click', function() {
       var formset = document.getElementById('image-formset');
       var currentFormCount = formset.querySelectorAll('.form-row').length;

       var newForm = document.createElement('div');
       newForm.classList.add('form-row');
       newForm.innerHTML = 
           `<div>
               <input type="file" name="form-${currentFormCount}-image" required>
               <button type="button" class="remove-form">Удалить</button>
           </div>`;
       formset.appendChild(newForm);

       // Обновляем количество форм в management_form
       var totalForms = document.getElementById('id_form-TOTAL_FORMS');
       totalForms.value = currentFormCount + 1;
   });

   document.getElementById('image-formset').addEventListener('click', function(e) {
       if (e.target.classList.contains('remove-form')) {
           e.target.closest('.form-row').remove();
       }
   });
   </script>
   ```

5. **Изменение стилей или логики**:
   Вы можете настроить CSS для улучшения внешнего вида и взаимодействия с формами.

Э
Похожие вопросы