I am trying to create a simple post sharing form like this one.
I'm using formset for image upload. But this gives me multiple input as you can see. Also each input can choose single image. But I'm trying to upload multiple image with single input.
views.py
def share(request):
ImageFormSet = modelformset_factory(Images,
form=ImageForm, extra=3)
# 'extra' means the number of photos that you can upload ^
if request.method == 'POST':
postForm = PostForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if postForm.is_valid() and formset.is_valid():
post = postForm.save(commit=False)
post.author = request.user
post.save()
for form in formset.cleaned_data:
# this helps to not crash if the user
# do not upload all the photos
if form:
image = form['image']
photo = Images(post=post, image=image)
photo.save()
return redirect("index")
else:
print(postForm.errors, formset.errors)
else:
postForm = PostForm()
formset = ImageFormSet(queryset=Images.objects.none())
return render(request, "share.html", {"postForm": postForm, 'formset': formset})
share.html
<form method="POST" id="post-form" class="post-form js-post-form" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
</form>
if you need, forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ["title", "content"]
def __init__(self, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.fields['title'].widget.attrs.update({'class': 'input'})
self.fields['content'].widget.attrs.update({'class': 'textarea'})
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Images
fields = ('image', )
def __init__(self, *args, **kwargs):
self.fields['image'].widget.attrs.update(
{'class': 'fileinput', 'multiple': True})
models.py
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
class Post(models.Model):
# on_delete ile, bu kullanıcı silindiğinde bu kullanıcıya ait tüm postlar da silinecek.
author = models.ForeignKey(
"auth.User", on_delete=models.CASCADE, verbose_name="Yazar")
title = models.CharField(max_length=150, verbose_name="Başlık")
content = models.TextField(verbose_name="İçerik")
# auto_now_add = True ile veritabanına eklendiği tarihi otomatik alacak
created_date = models.DateTimeField(auto_now_add=True)
# admin panelinde Post Object 1 yazması yerine başlığı yazsın istersek...
def __str__(self):
return self.title
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(
Post, on_delete=models.DO_NOTHING, default=None)
image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image', default="images/default_game_img.png")
If you need one filed for multiple image upload, try this:
views.py
from .forms import PostForm
from .models import Post, Images
def share(request):
form = PostForm()
if request.method == 'POST':
post = Post()
post.title = request.POST['title']
post.content = request.POST['content']
post.author = request.user
post.save()
for image in request.FILES.getlist('images'):
image_obj = Image()
image_obj.post_id = post.id
image_obj.image = image
image_obj.save()
return render(request, 'share.html', {'form': form})
forms.py
from django import forms
class PostForm(forms.Form):
title = forms.CharField(label='',
widget=forms.TextInput(attrs={
'class': 'input',
}
))
content = forms.CharField(label='',
widget=forms.Textarea(attrs={
'class': 'textarea',
}
))
images = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
share.html
<form method="POST" id="post-form" class="post-form js-post-form" enctype="multipart/form-data">
{% csrf_token %}
{% for elem in form %}
{{ elem }}
{% endfor %}
</form>
I think you are over thinking the implementation you should try lib like django-multiupload
And can find valid implementation for multiple image upload through this link
https://stackoverflow.com/a/44075555/10798048
Hope this will ease your implementation and solve your problem. Correct me if it doesn't work out for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With