django removes image on update save - django

I have the following clean method by which I reduce an image if it is too large:
class CompanyForm(forms.ModelForm):
class Meta:
model = Company
exclude = ('limited')
def clean_image(self):
image_field = self.cleaned_data.get('image')
if image_field:
reduced_image = reduce_image(image_field, 550)
return reduced_image
else:
raise forms.ValidationError('You must upload a square logo image')
return image_field
My reduce image looks like the following:
def reduce_image(image_field, height_max):
if image_field:
try:
image_file2 = BytesIO(image_field.read())
image = Image.open(image_file2).convert('RGB')
print(image)
except:
#raise ValidationError('There was a problem with the image, please try another.')
print('returning from image errror')
return image_field
w, h = image.size
print('image width:'+str(w))
print('image height:'+str(h))
if h > height_max:
print('height toolarge')
ratio = h/float(w)
new_height = ratio * height_max
image = image.resize((int(height_max), int(new_height)), Image.ANTIALIAS)
image_file = BytesIO()
image.save(image_file, 'JPEG', quality=90)
image_field.file = image_file
print(image_file)
return image_field
The first time I save, it saves no problem. When I save a second time to update the model, it removes the image.
Why might this be happening?

In the post method of your update view pass the following arguments to your form
get_object it's a custom method that I use to return the concerned object
If you're using CBV
def post(self, request, *args, **kwargs):
self.form_class(request.POST, request.FILES, instance=self.get_object())
....
For function based views
if request.method == 'POST':
form = CompanyForm(request.POST, request.FILES, instance=get_object())
if form.is_valid():
....

Related

Django Multiple Image Upload Using form

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.

Django modelformset_factory to update the existing images

class ProductImageForm(forms.ModelForm):
class Meta:
model = ProductImage
fields = ['product', 'original', 'caption']
# use ImageInput widget to create HTML displaying the
# actual uploaded image and providing the upload dialog
# when clicking on the actual image.
widgets = {
'original': ImageInput(),
}
def save(self, *args, **kwargs):
# We infer the display order of the image based on the order of the
# image fields within the formset.
kwargs['commit'] = False
obj = super(ProductImageForm, self).save(*args, **kwargs)
obj.display_order = self.get_display_order()
obj.save()
return obj
def get_display_order(self):
if self.prefix:
return self.prefix.split('-').pop()
else:
return 1
I am using django modelformset_factory to insert images into database and also update the images.The problem now is that image is inserted into database instead of updation while using modelformset_factory.Following below are the my code.Please help me to update other than saving
ImageFormSet = modelformset_factory(ProductImage,
form=ProductImageForm, extra=0, can_delete=True)
formset = ImageFormSet(self.request.POST or None, self.request.FILES or None, data)
if formset.is_valid():
try:
instances = formset.save(commit=False)
for instance in instances:
instance.save()
except Exception as e:
pass
else:
err = formset.errors
raise error_message(err)

django custom form validation error

when i am saving the modelform with blank image field, then it shows error, And this error is due to the custom form validation of image field in the modelform. And also the if statement is not working in custom form validation method.
" 'unicode' object has no attribute '_size' ".
models.py
class ImageUpload(models.Model):
image = models.ImageField(upload_to='uploads')
name = models.CharField(max_length='128')
class Meta:
db_table = 'image_upload'
formy.py
class ImageUploadForm(forms.ModelForm):
class Meta:
model = ImageUpload
def clean_image(self):
image = self.cleaned_data.get('image',None)
if image: # this is not working, if image field is blank
if image._size:
if image:
if image._size > 1*1024*1024:
raise ValidationError("Image file too large ( > 4mb )")
return image
else:
raise ValidationError("Couldn't read uploaded image")
else:
raise ValidationError("image format should be .png %s"%(image_format))
views.py
def add_image(request):
response_data = {}
if request.method == 'POST':
form = ImageUploadForm(request.POST,request.FILES)
context = {
'form':form
}
if form.is_valid():
form.save()
response_data['status'] = 'true'
response_data['message'] = 'successfully added'
return HttpResponse(json.dumps(response_data),content_type='application/javascript')
else:
response_data['message'] = form.errors
#return HttpResponse(response_data)
return HttpResponse(json.dumps(response_data),content_type='application/javascript')
else:
form = ImageUploadForm()
context = {
'form':form
}
return render(request,'users/add_image.html',context)
The error is on the form
image = self.cleaned_data.get('image',None)
you should get the image like
if 'image' in request.FILES:
image = request.FILES['image']

How to save an imagefield in Django views? Not a modelform

Im trying to submit a form with some textfields and an imagefield. And save it as a new model object. Cant get it to work so im going over each part from the start now..
How do i handle (just saving it) the imagefield in my views? Do i need to write an extra handler? It's not a modelform but a regular form. Where does PIL/PIllow come into this. Should I import it? Can i clean the imagefield?
I've been trying this:
def UploadThis(request):
if request.method == 'POST':
form = TestForm(request.POST, request.FILES)
response = {}
if form.is_valid():
response["status"] = "OK"
justtesting = Newmodel()
cd = form.cleaned_data
justtesting.name = cd['name']
justtesting.type = cd['type']
justtesting.description = cd['description']
justtesting.picture = request.FILES['picture']
justtesting.save()
Model:
class Newmodel(models.Model):
name = models.CharField(max_length=50)
type = models.CharField(max_length=50)
description = models.CharField(max_length=140, blank=True)
picture = models.ImageField(upload_to='images/testfiles', blank=True)
def __unicode__(self):
return self.name
Form:
class TestForm(forms.Form):
name = forms.CharField(max_length=50)
type = forms.CharField(max_length=50)
description = forms.CharField(max_length=140)
picture = forms.ImageField()
def clean(self):
cleaned_data = self.cleaned_data
name = cleaned_data.get("name")
description = cleaned_data.get("description")
type = cleaned_data.get("type")
return cleaned_data
Your error is that you are trying to assign the image to the model field using request.POST, when you actually need to use form.cleaned_data like so:
justtesting.picture = form.cleaned_data['picture']
Your clean method on the form is not doing anything currently. You could do validation (although that is not neccessary) by using a clean method something like this:
def clean_image(self):
image = self.cleaned_data.get('image', None)
if image:
# do some validation, if it fails
raise forms.ValidationError(u'Form error')
return image
For an example that validates the image size see this question: https://stackoverflow.com/a/16425455/1744645
Using PIL/Pillow is not necessary and only required if you want to some form of image processing. You could have a save method on your model, for example to resize the image:
def save(self,force_insert=False, force_update=False, *args, **kwargs):
# save everything else
super(Newmodel, self).save(force_insert, force_update)
if self.image:
if self.image.width > 300 or self.image.height > 300:
resize_image(self.image)
PIL/Pillow itself has the following basic operations that might be of interest:
img = PIL.open(PATH_TO_IMAGE)
img = img.resize((x, y), PIL.ANTIALIAS)
img = img.crop((0, 0, x, y))
img.save(path,quality=90)
But see http://effbot.org/imagingbook/pil-index.htm for the full docs.

Uploading Profile Image using Django ModelForm

I've looked around at related questions, but none of the answers seem to work. I'm trying to upload a profile image for a user and have it replace (overwrite) the current image. Upon saving the image I want to change the filename to the user id. In it's current form the image will upload, but it won't replace the existing image (e.g. it'll be saved as 2_1.png).
class PhotoForm(forms.ModelForm):
def save(self):
content_type = self.cleaned_data['photo'].content_type.split('/')[-1]
filename = '%d.%s' % (self.instance.user.id, content_type)
instance = super(PhotoForm, self).save(commit=False)
instance.photo = SimpleUploadedFile(filename, self.cleaned_data['photo'].read(), content_type)
instance.save()
return instance
class Meta:
model = UserProfile
fields = ('photo',)
def photo_form(request):
if request.method == 'POST':
form = PhotoForm(data=request.POST, file=request.FILES, instance=request.user.get_profile())
if form.is_valid():
form.save()
else:
form = PhotoForm()
return render(request, 'photo_form.html', {'form': form})
def photo_form(request):
if request.method == 'POST':
form = PhotoForm(data=request.POST, file=request.FILES, instance=request.user.get_profile())
if form.is_valid():
handle_uploaded_file(request.FILES['<name of the FileField in models.py>'])
def handle_uploaded_file(f):
dest = open('/path/to/file', 'wb') # write should overwrite the file
for chunk in f.chunks():
dest.write(chunk)
dest.close()
check here: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/
If that doesn't work, I suppose you could just use os.system to delete the file if the form is accepted. That probably wouldn't be that great of a solution, but it should work.