Django Multiple Image Upload Using form - django

This can upload single image. But i want to upload multiple image like insta do. In instagram multiple images are stored in a slider. I don't understand files = request.FILES.getlist('image') how can i iterate this this list
Views.py file
#login_required
def index(request):
images = Image.objects.all()
users = User.objects.filter(is_superuser=False)
prof = Profile.objects.get(user=request.user)
actions = Action.objects.exclude(user=request.user)
following_ids = request.user.following.values_list('id', flat=True)
if request.method == "POST":
form = ImageCreateForm(request.POST, request.FILES)
files = request.FILES.getlist('image')
if form.is_valid():
description = form.cleaned_data["description"]
image = form.cleaned_data["image"]
new_item = form.save(commit=False)
new_item.user = request.user
new_item.save()
create_action(request.user, 'Uploaded Image', new_item)
messages.success(request, "Image Added Successfully")
return redirect(new_item.get_absolute_url())
else:
form = ImageCreateForm(data=request.GET)
if following_ids:
# If user is following others, retrieve only their actions
actions = actions.filter(user_id__in=following_ids)
actions = actions.select_related('user', 'user__profile').prefetch_related('target')[:10]
return render(request, "account/index.html", {
'section': 'index',
'images': images,
'prof': prof,
'actions': actions,
'users': users,
'form': form,
})
forms.py file
from django import forms
from urllib import request
from django.core.files.base import ContentFile
from django.utils.text import slugify
from .models import Image
class ImageCreateForm(forms.ModelForm):
image = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta:
model = Image
fields = ('description',)
def clean_url(self):
image = self.cleaned_data['image']
valid_extensions = ['jpg', 'jpeg']
extension = image.rsplit('.', 1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('The Given URL does not match valid image extensions.')
return image
def save(self, force_insert=False, force_update=False, commit=True):
image = super().save(commit=False)
url = self.cleaned_data['image']
name = slugify(image.description)
image_name = f'{name}'
image.image.save(image_name, ContentFile(url.read()), save=False)
if commit:
image.save()
return image
admin.py file
#admin.register(Image)
class ImageAdmin(admin.ModelAdmin):
list_display = ['slug', 'image', 'description', 'created']
list_filter = ['created']

You can just loop throught it:
for afile in request.FILES.getlist('image'):
mymodel = MyModel()
mymodel .pic = afile
mymodel .save()
Of course you need to make sure you can save the images in your model.

Related

Django jQuery-File-Upload upload Adding the user_id to the Model

I am using jQuery-File-Upload in Django based on this tutorial:
https://simpleisbetterthancomplex.com/tutorial/2016/11/22/django-multiple-file-upload-using-ajax.html
I want to add the User_id to the Model.
This View is using JSON data passed from the html jquery.
Do I modify the json or can I add it in the Model?
Thank you.
MODEL:
class Files(models.Model):
file = models.FileField(upload_to="uploads/%Y/%m/%d/")
created = models.DateTimeField ( auto_now_add = True )
VIEW:
class BasicUploadView(View):
def get(self, request):
file_list = Files.objects.all()
content = {
'files': file_list
}
return render(self.request, 'upload/index.html', content )
def post(self, request):
user_id = request.user.id
form = UploadForm(self.request.POST, self.request.FILES)
if form.is_valid():
file = form.save()
data = {'is_valid': True, 'name': file.file.name, 'url': file.file.url}
else:
data = {'is_valid': False}
return JsonResponse(data)
FORM:
class UploadForm ( forms.ModelForm ):
class Meta:
model = Files
fields = ['file']

Key error django - passing additional stuffs with django form

I have my models like this:
class Photo(models.Model):
title = models.CharField(max_length=255, blank=True)
file = models.FileField(default='default.jpg')
page = models.ForeignKey(Page, on_delete=models.CASCADE)
class Page(Group):
name = models.IntegerField()
in my forms.py, to create a form for posting multiple images, I created this: I also override get_form_kwargs for passing the 'page' thing with the form as you can see that the Photo model has a page foreignkey.
class PhotoForm(forms.ModelForm):
def get_form_kwargs(self):
kwargs = super(PhotoForm, self).get_form_kwargs()
kwargs['page'] = Page.objects.get(pk=self.GET['pk'])
return kwargs
class Meta:
model = Photo
fields = ('file', )
In my main urls.py, I say like:
path('page/<int:pk>/photos/', include('photos.urls'))
and in photos apps urls.py, I say:
path('progress-bar-upload/', views.ProgressBarUploadView.as_view(), name='progress_bar_upload')
and in my photos apps views.py I say:
class ProgressBarUploadView(View):
model = Photo
def get(self, request, **kwargs):
photos_list = Photo.objects.all()
page = get_object_or_404(Page, page=self.kwargs['page'])
return render(self.request, 'photos/progress_bar_upload/index.html', {'photos': photos_list, 'page':page})
def post(self, request):
time.sleep(1)
form = PhotoForm(self.request.POST, self.request.FILES)
if form.is_valid():
photo = form.save()
data = {'is_valid': True, 'name': photo.file.name, 'url': photo.file.url}
else:
data = {'is_valid': False}
return JsonResponse(data)
Then when in my html I call the page,
{{page}}
Then when I go to 'localhost:/page/1/photos/progress-bar-upload/' I get this error:
KeyError at /page/7/photos/progress-bar-upload/
'page'
So what can I do? Can someone help me? Any help will be much much appreciated.

How do I upload multiple images and associate with a model

Errors when attempting to upload multiple images
Description of issue:
I have a model, Vehicle which has vehicle information as well as a cover photo. To add images for a gallery, I have a second model VehicleImage with a foreign key to Vehicle. I'm attempting to upload multiple images with a single file picker and save those all to a defined path (/media/vehicles/vehicle#/) I've tried different views to no avail. Right now i'm getting the following error.
Raised by: main.views.ImageFieldView
No vehicle image found matching the query
Thank you, any help would be greatly appreciated. I'm still learning but I work at it every day.
models.py
def vehicle_directory_path(instance, filename):
#! file will be uploaded to media_cdn/vehicle/<id>/<filename>.<ext>
ext = filename.split('.')[-1]
name = filename.split('.')[0]
vehicle = Vehicle.objects.get(id=instance.id)
return 'vehicles/{0}/{1}.{2}'.format(vehicle.id, name, ext)
class VehicleImage(models.Model):
vehicle = models.ForeignKey('Vehicle', on_delete=models.CASCADE, related_name='images')
image = models.ImageField(upload_to=vehicle_directory_path, null=True, blank=True)
forms.py
class ImageFieldForm(forms.ModelForm):
image_field = forms.ImageField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta:
model = VehicleImage
exclude = ('image', 'vehicle')
views.py
class ImageFieldView(CreateView):
model = VehicleImage
form_class = ImageFieldForm
def get(self, request, *args, **kwargs):
context = {'form': ImageFieldForm}
return render(request, 'main/vehicle_upload.html', context)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('image_field')
if form.is_valid():
for file in files:
instance = VehicleImage(
vehicle=Vehicle.objects.get(pk=kwargs['pk']),
image=file)
instance.save()
return self.form_valid(form)
else:
return self.form_invalid(form)
urls.py
urlpatterns = [
path('', views.homepage, name='homepage'),
path('vehicles/', views.vehicles, name='vehicles'),
path('vehicles/detail/<int:pk>/', views.VehicleDetail.as_view(), name='vehicle_detail'),
path('vehicles/edit/<int:pk>/', views.VehicleEdit.as_view(), name='vehicle_edit'),
path('vehicles/images/upload/<int:pk>', views.ImageFieldView.as_view(),name='vehicle_image_upload'),
# path('vehicle/image/add/<int:pk>/', views.VehicleEdit.as_view(), name='vehicle_image'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Suggested Edit: Still getting the same error
vehicles = Vehicle.objects.get(pk=kwargs['pk'])
if form.is_valid():
for f in files:
VehicleImage.objects.create(vehicle=vehicles, image=f)
return self.form_valid(form)

How do I thoroughly delete an old image file when a user updates the form's imagefield?

I have two modelforms--one includes a standard ImageField and the other is an inlineformset of ImageFields.
The normal standard ImageField renders on the page with the option for "Clear[ing]" while the inlineformset ImageFields render with an optional "Delete" tickbox.
Either Clear or Delete will remove the image from the User's profile, but the actual image file will remain in storage, as well as the URL to the image.
I am trying to remove all associations to the image once the User updates his Profile form by "clearing" or "deleting" the image.
I found FieldFile.delete which I believe just requires me to call .delete() on the instance, but I'm not sure how to conditionally check whether the user is updating the form with the "delete" box or "clear" box ticked.
Here are the two models containing the image fields:
class Profile(models.Model):
profile_photo = models.ImageField(
upload_to=profile_photo_upload_loc,
null=True,
blank=True,
verbose_name='Profile Image',
)
class CredentialImage(models.Model):
profile = models.ForeignKey(Profile, default=None,
related_name='credentialimage')
image = models.ImageField(
upload_to=credential_photo_upload_loc,
null=True,
verbose_name='Image Credentials',
)
The ModelForms:
class ProfileUpdateForm(ModelForm):
class Meta:
model = Profile
fields = [
"profile_photo",
]
class CredentialImageForm(ModelForm):
image = ImageField(required=False, widget=FileInput)
class Meta:
model = CredentialImage
fields = ['image', ]
CredentialImageFormSet = inlineformset_factory(Profile,
CredentialImage, fields=('image', ), extra=2)
The view:
class ProfileUpdateView(LoginRequiredMixin, UpdateView):
form_class = ProfileUpdateForm
def get_context_data(self, **kwargs):
data = super(ProfileUpdateView, self).get_context_data(**kwargs)
if self.request.POST:
data['credential_image'] = CredentialImageFormSet(self.request.POST, self.request.FILES, instance=self.object)
else:
data['credential_image'] = CredentialImageFormSet(instance=self.object)
return data
def get_object(self, *args, **kwargs):
user_profile = self.kwargs.get('username')
obj = get_object_or_404(Profile, user__username=user_profile)
return obj
def form_valid(self, form):
data = self.get_context_data()
formset = data['credential_image']
if formset.is_valid():
self.object = form.save()
formset.instance = self.object
formset.save()
return redirect(self.object.get_absolute_url())
else:
print("WTF")
instance = form.save(commit=False)
instance.user = self.request.user
return super(ProfileUpdateView, self).form_valid(form)
My View is all kinds of messed up but it seems to work. Now looking to completely remove the image files from storage upon update.
Use Django-cleanup:
pip install django-cleanup
settings.py
INSTALLED_APPS = (
...
'django_cleanup', # should go after your apps
...
)

Overriding the href img src value in an ImageField in Django admin

I'm uploading certain media to a particular directory to secure it. The images are uploaded using an inlineformset_factory object.
The problem I have is that where viewing the uploaded record in the admin site it appears to prepend my settings.MEDIA_URL (/media/) to the path of the uploaded image.
ie.
http://localhost:8000/media/<relative image path>
What I would like it to use instead is a custom setting, settings.PROTECTED_MEDIA_URL ('src') to return the following path instead:
http://localhost:8000/scr/<relative image path>
Included below are what I believe are the relevant parts of the code.
Any insight is appreciated!
settings.py
...
MEDIA_URL = '/media/'
PROTECTED_MEDIA_URL = '/scr/'
...
model.py
...
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location = '/home/user/nginx_restricted')
def orig_car_id_folder(instance, filename):
return 'uploads/images/orig/{0}/{1}'.format(instance.car_id, filename)
class OwnersCar(models.Model):
brand = models.CharField(max_length=64)
...
class OwnersCarImages(models.Model):
car = models.ForeignKey(OwnersCar)
orig_image = models.ImageField(
upload_to=orig_car_id_folder,
verbose_name='Upload Image',
storage=fs
)
...
...
admin.py
from django.contrib import admin
from vehicle_admin_ac.models import OwnersCar, OwnersCarImages
class CarImageInline(admin.TabularInline):
model = OwnersCarImages
exclude = ('thumbnail',)
class OwnersCarAdmin(admin.ModelAdmin):
list_display = ('owner','brand',)
ordering = ('owner',)
search_fields = ('owner',)
inlines = [
CarImageInline,
]
admin.site.register(OwnersCar, OwnersCarAdmin)
urls.py
...
urlpatterns = patterns('',
url(r'^scr/(?P<protected_image_path>/uploads/images/(thumb|orig)/.*)$',
'vehicle_admin_ac.views.protected_view',
name='protected_view'),
...
)
...
views.py
...
#login_required
def protected_view(request, protected_image_path):
response = HttpResponse()
url = protected_image_path
response['Content-Type']=""
response['X-Accel-Redirect'] = "/protected/{0}".format(url)
return response
#login_required
def add_vehicle(request):
ImageFormSet = inlineformset_factory(OwnersCar, OwnersCarImages, form=InitialCarImageForm, extra=3)
owners_car = OwnersCar()
if request.method == 'POST':
form = forms.OwnersCarForm(request.POST, instance=owners_car)
formset = ImageFormSet(request.POST, request.FILES, instance=owners_car)
if formset.is_valid() and form.is_valid():
new_car = form.save(commit=False)
new_car.owner = request.user
new_car.save()
formset.save() # save() method works fine with 'inlineformset_factory'
return HttpResponseRedirect(new_car.get_absolute_url())
else:
form = forms.OwnersCarForm()
formset = ImageFormSet()
return render_to_response('add_new.html',
{'form': form, 'formset': formset},
context_instance=RequestContext(request))
...
Here's a link the relevant part of the docs that I'd missed, explaining the base_url argument.