Добавление поля для нескольких файлов в Django ModelForm

Я хочу создать форму, которая позволяет загружать несколько изображений. У меня есть модель Listing, которая выглядит следующим образом:

class Listing(models.Model):
    location = models.CharField("Address/Neighborhood", max_length=250)


class ListingImage(models.Model):
    listing = models.ForeignKey(
        Listing,
        related_name="images",
        on_delete=models.SET_NULL,
        null=True,
    )
    image = models.ImageField()

Я использую django-crispy-forms для создания формы на странице, но не могу понять, как вывести поле listing на страницу.

class ListingModelForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.helper = FormHelper()
        self.helper.layout = Layout(
            Fieldset(
                "Location",
                Div("location", css_class="col-md-12 col-lg-6")
            )
        )

        class Meta:
            model = Listing
            fields = "__all__"

А вот мое мнение:

class ListingCreateView(LoginRequiredMixin, CreateView):
    model = Listing
    form_class = ListingModelForm

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super().form_valid(form)

Если я правильно понимаю, вы хотите иметь поле, в которое можно добавить несколько изображений, а затем сохранить их все. Если я прав, то вот подход, который вы можете использовать.

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

class ListingModelForm(forms.ModelForm):
     # Extra field to collect multiple images
     listing_images = forms.ImageField(
          required=False,
          widget=forms.ClearableFileInput(attrs={'name': 'listing_images', 'id': 'listing_images', 'multiple': True})
     )

     # other portion of your form below...

Теперь вы можете получить доступ к полю в форме: {{ form.listing_images }}, добавление нескольких изображений...

Теперь внутри функции post request у вас есть обработка этой формы... Вы можете сделать:

if request.method == 'POST':
     form = ListingModelForm(data=request.POST, files=request.FILES)

     if form.is_valid():
          # listing = form.save(commit=False)
          # listing.location = 'blah blah'
          # listing.save()

          # or just use
          listing = form.save()

          # Looping over the list of images and create for each iteration
          for file in request.FILES.getlist('listing_images'):
              ListingImage.objects.create(listing=listing, image=file)

          # Also note that you could override the save method on the form to include the above forloop
          # if you don't want it out here...

Предполагая, что на image field на ListingImage указан путь для загрузки изображений и настроены параметры MEDIA_URL и MEDIA_ROOT...

UPDATES

Опубликовал ответ, не зная, что вы используете class-based view.

class ListingCreateView(LoginRequiredMixin, CreateView):
     model = Listing
     form_class = ListingModelForm

     def form_valid(self, form):
          # form.instance.user = self.request.user

          listing = form.save()  # Listing must be created first to use as the image reference

          for file in self.request.FILES.getlist('listing_images'):
               ListingImage.objects.create(listing=listing, image=file)

          return super(ListingCreateView, self).form_valid(form)
     
     # or using the post method
     def post(self, *args, *kwargs):
          form = ListingModelForm(data=request.POST, files=request.FILES)
          
          if form.is_valid():
               for file in self.request.FILES.getlist('listing_images'):
                    ListingImage.objects.create(listing=listing, image=file)
          
          return redirect('to a path...')
          

Так что вы можете просто использовать один из методов, выделенных выше на class-based view.

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