How to save or upload an image from LOCAL directory to ImageField of database object in DJANGO - django

I was trying to create some products in ecommerce project in django and i had the data file ready and just wanted to loop throw the data and save to the database with Product.objects.create(image='', ...) but i couldnt upload the images from local directory to database!
I tried these ways:
1
with open('IMAGE_PATH', 'rb') as f:
image = f.read()
Product.objects.create(image=image)
2
image = open('IMAGE_PATH', 'rb')
Product.objects.create(image=image)
3
module_dir = dir_path = os.path.dirname(os.path.realpath(__file__))
for p in products:
file_path = os.path.join(module_dir, p['image'])
Product.objects.create()
product.image.save(
file_path,
File(open(file_path, 'rb'))
)
product.save()
none worked for me.

After some searching, I got the answer.
the code to use would be like this:
from django.core.files import File
for p in products:
product = Product.objects.create()
FILE_PATH = p['image']
local_file = open(f'./APP_NAME/{FILE_PATH}', "rb")
djangofile = File(local_file)
product.image.save('FILE_NAME.jpg', djangofile)
local_file.close()

from django.core.files import File
import urllib
result = urllib.urlretrieve(image_url) # image_url is a URL to an image
model_instance.photo.save(
os.path.basename(self.url),
File(open(result[0], 'rb'))
)
self.save()
Got the answer from here

Related

django, creating qrcode.png file for a new instance in signals.py

I will like to create a qrcode.png file and store it in my S3 bucket once a instance gets created in models.Model (using signals.py). With my code below I managed to create the qrcode__png file in my local base directory but it does not upload to my external S3 bucket or save in my models.Model class. HELP! Thanks.
Signals.py
#receiver(post_save,sender=inventory)
def create__url_qr(sender, instance, created, **kwargs):
if created == True:
qr = qrcode.QRCode(
version=1,
box_size=10,
border=5)
qr.add_data('/MyProperty/item/'+str(instance.id))
qr.make(fit=True)
im=qr.make_image(fill_color="black", back_color="white")
im.save('qrcode___'+str(instance.id)+'.png', format="png")
print('XXXX')
print(im)
print('XXXX')
inst1 = inventory.objects.get(pk=instance.pk)
inst1.qr_code = im
inst1.save()
You can read the file you wrote into a django.core.files.File object and then save that object to your model
import qrcode
from django.core.files import File
qr = qrcode.QRCode(
version=1,
box_size=10,
border=5,
)
qr.add_data('/MyProperty/item/'+str(instance.id))
qr.make(fit=True)
im = qr.make_image(fill_color="black", back_color="white")
im.save('qrcode___'+str(instance.id)+'.png', format="png")
qr_file = File(open('qrcode___'+str(instance.id)+'.png'))
inst1 = inventory.objects.get(pk=instance.pk)
inst1.qr_code.save('qrcode___'+str(instance.id)+'.png', qr_file)
But you don't have to save it locally first, you could just write it to BytesIO and then save it
import qrcode
from io import BytesIO
from django.core.files import File
qr = qrcode.QRCode(
version=1,
box_size=10,
border=5,
)
qr.add_data('/MyProperty/item/'+str(instance.id))
qr.make(fit=True)
im = qr.make_image(fill_color="black", back_color="white")
stream = BytesIO()
im.save(stream, format="png")
qr_file = File(stream)
inst1 = inventory.objects.get(pk=instance.pk)
inst1.qr_code.save('qrcode___'+str(instance.id)+'.png', qr_file)

Django - Converting a Binary stream to an Image

I am trying to obtain an image from a url and return it to the ModelAdmin to display it in a new column of the table.
I tried the following code in admin.py file:
def new_field(self, obj):
r = requests.get('https://abcd.com/image')
return r.content
The code is not giving me any error but it's returning a long binary string instead of the image itself.
How can I pass the image itself, or convert the binary content to an image?
You do not need download image if you wont only show it.
def new_field(self, obj):
url = 'https://abcd.com/image'
return '<img src="{}" />'.format(url)
new_field.allow_tags = True # it is important!!!
You can make use of a NamedTemporaryFile [GitHub] here. For example:
from django.core.files import File
from django.core.files.temp import NamedTemporaryFile
def store_image_from_source(self, obj):
img = NamedTemporaryFile()
r = requests.get('https://abcd.com/image')
img.write(r.content)
img.flush()
file = File(img)
obj.my_img_attr.save('filename.jpeg', file, save=True)
Here 'filename.jpeg' is thus te name of the file, as if you would have uploaded a file with that name with a ModelForm.

how to load csv file data into pandas using request.FILES(django 1.11) without saving file on server

i just want to upload .csv file via form, directly in to pandas dataframe in django without saving physically file on to server.
def post(self, request, format=None):
try:
from io import StringIO, BytesIO
import io
print("data===",request.FILES['file'].read().decode("utf-8"))
# print("file upload FILES data=====",pd.read_csv(request.FILES['file'].read(), sep=','))
#print(request.FILES)
print("file upload data df=====11")
mm = pd.read_csv( BytesIO(request.FILES['file'].read().decode("utf-8")))
print("dataframe data=====",mm)
# import io, csv
# urlData = request.FILES['file']
# data = [row for row in (csv.reader(urlData))]
# print("file upload data df=====222",data)
# mm = pd.read_csv()
#excel_file = request.FILES['file']
# movies = pd.read_excel(request.FILES['file'])
except Exception as e:
print(e)
log.debug("Error in CheckThreadStatus api key required "+str(e))
return Response(responsejson('api key required', status=404))
the ans is straight forward: that is
pd.read_csv(request.FILES['file'])
works perfectly fine, the mistake i was doing is that.. my csv file was not in correct format.
Check With
pd.read_csv('data.csv') # doctest: +SKIP
If using post method you can try
getFile = request.FILE['file_name']
pd.read_csv(getFile) # doctest: +SKIP
You can use StringIO for reading and decoding your csv :
import csv
from io import StringIO
csv_file = request.FILES["csv_file"]
content = StringIO(csv_file.read().decode('utf-8'))
reader = csv.reader(content)
After reading you can populate your database like this :
csv_rows = [row for row in reader]
field_names = csv_rows[0] # Get the header row
del csv_rows[0] # Deleting header after storing it's values in field_names
for index, row in enumerate(csv_rows):
data_dict = dict(zip(field_names, row))
Model.objects.update_or_create(id=row[0],
defaults=data_dict
)
Make sure to validate data before inserting, if the data is critical.
HINT: use django forms to validate for you.
from django import forms

Shopify API upload a local image via python

import shopify
from base64 import b64encode
#omitted the shopify key
shopify.ShopifyResource.set_site(shop_url)
path = "product.jpg"
new_product = shopify.Product()
new_product.title = "title"
new_product.body_html = "This is a test"
image = shopify.Image()
with open(path, "rb") as f:
filename = path.split("/")[-1:][0]
#encoded = b64encode(f.read()) (I tried this one as well)
encoded = f.read()
image.attach_image(encoded, filename=filename)
new_product.images = image
new_product.save()
I tested both methods:
encoded = b64encode(f.read())
encoded = f.read()
In both tests, the output was the same:
The product was successfully created, however, with no image.
I also noticed that the image returns image(None) and new_products.images returns image(None) as well.
You were so close- the new_product.images attribute must be a list of Image instances, not an Image instance. Also, if you look at the source of attach_image(), you can see they do the base64 encoding for you.
import shopify
#omitted the shopify key
shopify.ShopifyResource.set_site(shop_url)
path = "product.jpg"
new_product = shopify.Product()
new_product.title = "title"
new_product.body_html = "This is a test"
image = shopify.Image()
with open(path, "rb") as f:
filename = path.split("/")[-1:][0]
encoded = f.read()
image.attach_image(encoded, filename=filename)
new_product.images = [image] # Here's the change
new_product.save()
self.fake("products/632910392/images", method='POST', body=self.load_fixture('image'), headers={'Content-type': 'application/json'})
image = shopify.Image({'product_id':632910392})
image.position = 1
binary_in=base64.b64decode("R0lGODlhbgCMAPf/APbr48VySrxTO7IgKt2qmKQdJeK8lsFjROG5p/nz7Zg3MNmnd7Q1MLNVS9GId71hSJMZIuzTu4UtKbeEeakhKMl8U8WYjfr18YQaIbAf==")
image.attach_image(data=binary_in, filename='ipod-nano.png')
image.save()

copy file from one model to another

I have 2 simple models:
class UploadImage(models.Model):
Image = models.ImageField(upload_to="temp/")
class RealImage(models.Model):
Image = models.ImageField(upload_to="real/")
And one form
class RealImageForm(ModelForm):
class Meta:
model = RealImage
I need to save file from UploadImage into RealImage. How could i do this.
Below code doesn't work
realform.Image=UploadImage.objects.get(id=image_id).Image
realform.save()
Tnx for help.
Inspired by Gerard's solution I came up with the following code:
from django.core.files.base import ContentFile
#...
class Example(models.Model):
file = models.FileField()
def duplicate(self):
"""
Duplicating this object including copying the file
"""
new_example = Example()
new_file = ContentFile(self.file.read())
new_file.name = self.file.name
new_example.file = new_file
new_example.save()
This will actually go as far as renaming the file by adding a "_1" to the filename so that both the original file and this new copy of the file can exist on disk at the same time.
Although this is late, but I would tackle this problem thus,
class UploadImage(models.Model):
Image = models.ImageField(upload_to="temp/")
# i need to delete the temp uploaded file from the file system when i delete this model
# from the database
def delete(self, using=None):
name = self.Image.name
# i ensure that the database record is deleted first before deleting the uploaded
# file from the filesystem.
super(UploadImage, self).delete(using)
self.Image.storage.delete(name)
class RealImage(models.Model):
Image = models.ImageField(upload_to="real/")
# in my view or where ever I want to do the copying i'll do this
import os
from django.core.files import File
uploaded_image = UploadImage.objects.get(id=image_id).Image
real_image = RealImage()
real_image.Image = File(uploaded_image, uploaded_image.name)
real_image.save()
uploaded_image.close()
uploaded_image.delete()
If I were using a model form to handle the process, i'll just do
# django model forms provides a reference to the associated model via the instance property
form.instance.Image = File(uploaded_image, os.path.basename(uploaded_image.path))
form.save()
uploaded_image.close()
uploaded_image.delete()
note that I ensure the uploaded_image file is closed because calling real_image.save() will open the file and read its content. That is handled by what ever storage system is used by the ImageField instance
Try doing that without using a form. Without knowing the exact error that you are getting, I can only speculate that the form's clean() method is raising an error because of a mismatch in the upload_to parameter.
Which brings me to my next point, if you are trying to copy the image from 'temp/' to 'real/', you will have to do a some file handling to move the file yourself (easier if you have PIL):
import Image
from django.conf import settings
u = UploadImage.objects.get(id=image_id)
im = Image.open(settings.MEDIA_ROOT + str(u.Image))
newpath = 'real/' + str(u.Image).split('/', 1)[1]
im.save(settings.MEDIA_ROOT + newpath)
r = RealImage.objects.create(Image=newpath)
Hope that helped...
I had the same problem and solved it like this, hope it helps anybody:
# models.py
class A(models.Model):
# other fields...
attachment = FileField(upload_to='a')
class B(models.Model):
# other fields...
attachment = FileField(upload_to='b')
# views.py or any file you need the code in
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from django.core.files.base import ContentFile
from main.models import A, B
obj1 = A.objects.get(pk=1)
# You and either copy the file to an existent object
obj2 = B.objects.get(pk=2)
# or create a new instance
obj2 = B(**some_params)
tmp_file = StringIO(obj1.attachment.read())
tmp_file = ContentFile(tmp_file.getvalue())
url = obj1.attachment.url.split('.')
ext = url.pop(-1)
name = url.pop(-1).split('/')[-1] # I have my files in a remote Storage, you can omit the split if it doesn't help you
tmp_file.name = '.'.join([name, ext])
obj2.attachment = tmp_file
# Remember to save you instance
obj2.save()
Update Gerard's Solution to handle it in a generic way:
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from django.core.files.base import ContentFile
init_str = "src_obj." + src_field_name + ".read()"
file_name_str = "src_obj." + src_field_name + ".name"
try:
tmp_file = StringIO(eval(str(init_str)))
tmp_file = ContentFile(tmp_file.getvalue())
tmp_file.name = os.path.basename(eval(file_name_str))
except AttributeError:
tmp_file = None
if tmp_file:
try:
dest_obj.__dict__[dest_field_name] = tmp_file
dest_obj.save()
except KeyError:
pass
Variable's Used:
src_obj = source attachment object.
src_field_name = source attachment object's FileField Name.
dest_obj = destination attachment object.
dest_field_name = destination attachment object's FileField Name.