How to resize images before uploading them in Flask? - python-2.7

I have four images i want to upload them, but their sizes are very big it takes long time to upload them into the site.
I want to resize each one of them, i wrote a small route that handle the request:
#team_route.route('/team/dashboard/add/product', methods=['GET', 'POST'])
#requires_auth
#master_login_required(role='master')
def team_add_product():
form = AddProduct()
imagesList = []
size = 1024, 764
if request.method == 'POST' and form.is_submitted():
product = Goods()
file = request.files.getlist("image[]")
if file:
for zipfile in file:
fi = Image.open(BytesIO(zipfile.stream.read()))
im.thumbnail(size)
img2 = im.rotate(-90, expand=True)
img2.seek(0)
img2.save(UPLOAD_FOLDER + '/crops/' + zipfile)
When i hit upload it gives me this error:
AttributeError: 'JpegImageFile' object has no attribute 'read'
Please any help solving this ?

You have to remove .stream
zipfile.read() its the only you need.

Related

DRF test multiple image upload

I'm trying to test multiple image upload to my server. Here is the serializer:
class ImageSerializer(serializers.ModelSerializer):
image = serializers.ListField(
child=serializers.ImageField(allow_empty_file=True)
)
ImageFactory:
def get_image():
image = Image.new("RGB", (2000, 2000))
file = tempfile.NamedTemporaryFile(suffix=".jpg")
image.save(file)
return file
Test:
def test_upload_multiple_images(self):
self.image = get_image()
with open(self.image.name, "rb") as file:
payload = {
"image": [file, file]
}
response = self.client.post(
reverse("gallery-list", args=[self.item.pk]),
data=payload,
format="multipart"
)
When testing via Postman, images from the array are saved correctly. However when using the test case, I get the following message from the response:
{'image': [{'message': 'The submitted file is empty.', 'code': 'empty'}]}
Before adding allow_empty_file=True, there were two of those messages being returned.
Has anyone got any idea why that would happen?
The problem here is that you're sending the same Image object to the database to be saved twice. Once the first Image object has been decoded to a file to be saved in the database, the Image object will become unreadable, and since its the same object as the second, an error will be thrown.
So if you send the same Image object as two different items, only the first one will be readable. To avoid this you'll have to send two different image objects.
Your ImageFactory can be refactored to:
def get_image(count=1):
images = []
for i in list(range(count)):
file = io.BytesIO()
image = Image.new('RGBA', size=(100, 100), color=(155, 0, 0))
image.save(file, 'png')
file.name = 'test.png'
file.seek(0)
images.append(file)
return images[0] if count == 1 else images
and your Test:
def test_upload_multiple_images(self):
self.images = get_image(2)
payload = {
"image": self.images
}
response = self.client.post(
reverse("gallery-list", args=[self.item.pk]),
data=payload,
format="multipart"
)

Can I do some preprocessing on image and use it without save changes?

Recently I wrote a code that reads an image from an object storage. Then I do some simple image processing on the image. but I don't want to save changes on the main image, also I don't want to copy image because of performance reasons. I just want to send manipulated image to a vies function in django in order to open it as a data file.
is it any way to do this job?
this is my function's schema.
def watermark_image(image_name):
# do some image processing on input image
# cv2.imwrite(image_name, image)
return image
and this is a part of my function view:
if request.method == 'GET':
new_image = watermark_image(local_path + object_name)
# image_data = open(??? , "rb").read()
image_data = open(new_image , "rb").read()
return HttpResponse(image_data, content_type="image/png")
i don't know what should to wirte insetead of this line :
image_data = open(new_image , "rb").read()

How to convert an uploaded file (InMemoryUploadedFile) from pdf to jpeg in Django using wand?

I'm trying to convert a pdf file uploaded in Django to a jpg file. I would like to use the file directly in the InMemoryUploadedFile state.
I tried to use wand but without any success.
Here is the code I wrote:
from django.shortcuts import render
from wand.image import Image as wi
# Create your views here.
def readPDF(request):
context = {}
if request.method == 'POST':
uploaded_file = request.FILES['document']
if uploaded_file.content_type == 'application/pdf':
pdf = wi(filename=uploaded_file.name, resolution=300)
pdfImage = pdf.convert("jpeg")
return render(request, 'readPDF.html', {"pdf": pdfImage})
I tried different things like using uploaded_file.file or uploaded_file.name as the first argument for the wand image but without any success.`
I thank you in advance for your help!
Should be able to pass InMemoryUploadedFile directly to Wand's constructor.
uploaded_file = request.FILES['document']
if uploaded_file.content_type == 'application/pdf':
with wi(file=uploaded_file, resolution=300) as pdf:
# ...
However, I wouldn't recommend attempting to convert PDF pages to JPEGs in a HTTP request. Best to write the document to storage, and have a background worker manage the slow / unsafe tasks.

Read user uploaded csv file and store data in Django modele live on heroku

This is my firts question here. so I would like to thank you for your help.
I have a Django School management app. and i would like the user to be able to read csv file and store in database with specific header.
My code runs locally very well. but I recently push it on heroku so that I can test it. I may note that all static assets are stored on Amazon s3. and it works.
but when I try to read a csv file, I get an Internal server error.
here is my code to store Pupils.
def convert_header(csvHeader):
cols = [ x.replace(' ', '_').lower() for x in csvHeader ]
return cols
def import_data(request):
if request.method == 'GET':
return render(request, 'school/import.html')
if request.method == 'POST' and request.FILES['myfile']:
if request.POST.get("object") == '':
message = 'You may chose an object'
return render(request, 'school/import.html', {'message': message })
if request.POST.get("object") == 'Pupil':
myfile = request.FILES['myfile']
fs = FileSystemStorage(location='eSchool/media/documents')
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.path(filename)
data = csv.reader(open(uploaded_file_url), delimiter=',')
header = next(data)
header_cols = convert_header(header)
i = 0
k = 0
for row in data:
pupil = Pupil()
for k in range(len(header_cols)):
row_item = row[k].split(',')
for item in row_item:
key = header_cols[k]
if key == 'responsible':
item = Responsible.objects.get(pk= int(item))
print(item.first_name)
setattr(pupil, key, item)
else:
setattr(pupil, key, item)
k +=1
pupil.save()
i = i + 1
detailed = 'Sucessfully created '+ str(i) + ' Pupils '
return render(request, 'school/import_success.html', {'detailed' : detailed })
I would like to store data in a modele called Document. I create it. and try it I still get the error. Please help.
I find the solution of that problem. I first create a Django model to store the url of the uploaded file. like that:
class Document(models.Model):
uploaded_at = models.DateTimeField(auto_now_add=True)
upload = models.FileField(upload_to='documents')
Obvously I had to configure MEDIA_ROOT and MEDIA_URL
I configure the settings file to store the reference of all media assets and all static file on Amazon s3.
So instead of using the class FileSystemStorage. I install with pip a package named "requests"
pip install requests
and I import requests,csv and codecs.
import requests
import codecs
After that my view I just make litle modification tm my function.
def import_data(request):
if request.method == 'GET':
return render(request, 'school/import.html')
if request.method == 'POST' and request.FILES['myfile']:
if request.POST.get("object") == '':
message = 'You may chose an object'
return render(request, 'school/import.html', {'message': message })
if request.POST.get("object") == 'Pupil':
myfile = request.FILES['myfile']
doc = Document()
doc.upload = myfile
doc.save()
print(doc.upload.url)
if settings.DEBUG == True: # execute that block locally
data = csv.reader(open(doc.upload.path), delimiter=',') # locally the file is red frm the path so i us doc.upload.path
else: #this block is executed in production. So the file is red from the url. so I use doc.upload.url
rep = requests.get(doc.upload.url)
text = codecs.iterdecode(rep.iter_lines(), 'latin_1') #codecs is use to decode the lines. I don't really master how it works.
data = csv.reader(text, delimiter = ',')
header = next(data)
header_cols = convert_header(header)
i = 0
k = 0
for row in data:
pupil = Pupil()
for k in range(len(header_cols)):
row_item = row[k].split(',')
for item in row_item:
key = header_cols[k]
if key == 'responsible':
item = Responsible.objects.get(pk= int(item))
#print(item.first_name)
setattr(pupil, key, item)
else:
setattr(pupil, key, item)
k +=1
pupil.save()
i = i + 1
detailed = 'Sucessfully created '+ str(i) + ' Pupils '
return render(request, 'school/import_success.html', {'detailed' : detailed })
So right now. everything work well. If you see something that i can improve about this code, I Already thank you for your help!

Django update template image after save it on server storage

I have a question about file upload and refresh it on template.
I have a custom variation of file saving system in my view:
sp = os.path.join(os.path.dirname(__file__), '../media/avatars')
av_name = os.path.join(sp, u.username + "_avatar.jpg")
dataUrlPattern = re.compile('data:image/(png|jpeg);base64,(.*)$')
ImageData = request.POST.get('u_avatar')
ImageData = dataUrlPattern.match(ImageData).group(2)
ImageData = base64.b64decode(ImageData)
ava = open(av_name, 'wb')
ava.write(ImageData)
ava.close()
And it works fine. I can upload and update avatars and save it with a custom name in media folder. But when I try to save a new file, it doesn't refresh on template! I mean that file saved correctly, I see a new image in server folder, but template render old version of them. When I try to open a image link, I still see an old file.
I think the reason is some kind of cache, but I can't understand, how it works.
Could you, please, help me, how I can refresh image after each upload?
EDIT:
This is my complete view:
def edit(request):
u = request.user
p = get_object_or_404 (Profile, user=request.user)
if request.method == 'POST':
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
if request.POST.get('u_avatar'):
sp = os.path.join(os.path.dirname(__file__), '../media/avatars')
av_name = os.path.join(sp, u.username + "_avatar.jpg")
os.remove(av_name)
dataUrlPattern = re.compile('data:image/(png|jpeg);base64,(.*)$')
ImageData = request.POST.get('u_avatar')
ImageData = dataUrlPattern.match(ImageData).group(2)
ImageData = base64.b64decode(ImageData)
ava = open(av_name, 'wb')
ava.write(ImageData)
ava.close()
profile = profile_form.save(commit=False)
profile.user = u
profile.avatar = str("/media/avatars/" + u.username + "_avatar.jpg")
profile.filled = True
if p.rate < 0.5:
profile.rate = 0.5
else:
profile.rate = p.rate
profile.save()
return HttpResponseRedirect('profile')
else:
profile_form = ProfileForm()
return render(request, 'profile_edit.html', {'profile_form': profile_form})
And this is my avatar on template:
<div class="lavatar"><img src="{{ user.profile.avatar }}" class="img-circle"></div>
BTW, I use CharField for avatar instead of ImageField or FileField. Maybe problem with that.
EDIT2
Now I found a new interesting fact: the image is updated after some time. I uploaded a new image and didn't touch site about 1,5 - 2 hours. And avatar had refreshed.
Finally I found a problem!
Cloudflare! I set "Bypass cache" on a page rule and it seems to work well.