0

I'm wanting to create a form that allows multiple image uploads. I've got a Listing model that looks like this:

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

I'm using django-crispy-forms to create the form on the page but I cannot figure out how to get the listing field onto the page.

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__"

And this is my view:

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)
2
  • Have you attempted to display the form field on the page? If yes, please add that code to your post. Commented Jun 17, 2022 at 0:17
  • Can check the answer to see if that's what you're looking for. Commented Jun 17, 2022 at 1:16

1 Answer 1

1

If I'm understanding correctly, you want to have a field where you'll be able to add multiple images and then save them all. If I'm correct, then here's an approach you could take.

Add an extra field on the form that you'll set to accept multiple images... for example:

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

You can now access the field in the form: {{ form.listing_images }}, adding multiple images...

Now within the function's post request you have handling that form... You can do:

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

Assuming that your image field on the ListingImage have a path to upload the images and have configured your MEDIA_URL and MEDIA_ROOT settings...

UPDATES

Posted an answer before knowing you were using the 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...')
          

So you could just use one of the methods highlighted above on the class-based view.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.