Django, xlsxwriter and images - django

I have django site where I am trying to create an excel file with an image in it.
The image is on a AWS: https://unord-tools-django-project-static.s3.eu-central-1.amazonaws.com/media/public/10e8f47bb84901d20ff435071577c58b_TFxmjcV.jpg
I am using: xlsxwriter==1.4.5
and trying to write it with:
worksheet_s.insert_image(5, thisColumn, str('https://unord-tools-django-project-static.s3.eu-central-1.amazonaws.com/media/public/'+image))
My model looks like this:
class Room(models.Model):
# Relationships
location = models.ForeignKey("asset_app.Locations", on_delete=models.SET_NULL, blank=True, null=True)
room_type = models.ForeignKey("asset_app.Room_type", on_delete=models.SET_NULL, blank=True, null=True)
# Fields
name = models.CharField(max_length=30)
image = models.ImageField(storage=PublicMediaStorage(), null=True, blank=True
)
The error I am getting is this:
worksheet_s.insert_image(5, thisColumn, str('https://unord-tools-django-project-static.s3.eu-central-1.amazonaws.com/media/public/'+image))
TypeError: can only concatenate str (not "ImageFieldFile") to str

XlsxWriter doesn't insert images directly from urls like that. You will need to read the data first. Something like this:
from io import BytesIO
from urllib.request import urlopen
import xlsxwriter
# Create the workbook and add a worksheet.
workbook = xlsxwriter.Workbook('image.xlsx')
worksheet = workbook.add_worksheet()
# Read an image from a remote url.
url = 'https://unord-tools-django-project-static.s3.eu-central-1.amazonaws.com/media/public/10e8f47bb84901d20ff435071577c58b_TFxmjcV.jpg'
image_data = BytesIO(urlopen(url).read())
# Write the byte stream image to a cell. Note, a dummy filename
# or description must be specified, or use a blank string.
worksheet.insert_image('B2', 'image name', {'image_data': image_data})
workbook.close()
Output:

Related

Django models for astra datastax db

I have developed a website on Django. Initially, I used Django's default Database which is Sqlite3. Now I want to use Astra Datastax DB which is Cassandra. I am not able to convert Django.dB - models into Cassandra.cqlengine - columns function.
I have searched on the Internet and didn't find appropriate documents which could help me.
from django.db import models
from django.contrib.auth import get_user_model
from datetime import datetime
import uuid
User = get_user_model()
class Profile(models.Model):
"""docstring for Profile."""
usr: str = models.ForeignKey(User, on_delete=models.CASCADE)
id_usr: int = models.IntegerField()
Fname:str = models.TextField(blank=True,null=True)
Mname:str = models.TextField(blank=True,null=True)
Lname:str = models.TextField(blank=True,null=True)
Fhone:int = models.IntegerField(blank=True,null=True)
bio: str = models.TextField(blank=True)
img_profile = models.ImageField(
upload_to='ProfileIMG', default="blankprofile.png")
location: str = models.CharField(max_length=250)
def __str__(self):
return self.usr.username
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, unique=True)
user: str = models.CharField(max_length=100)
image = models.ImageField(upload_to="img_posts")
caption: str = models.TextField(max_length=250)
created_at = models.DateTimeField(default=datetime.now)
Likes: int = models.IntegerField(default=0)
def __str__(self):
return self.user
class LikePost(models.Model):
postid: str = models.CharField(max_length=100)
username: str = models.CharField(max_length=100)
def __str__(self):
return self.username
class Followers(models.Model):
follower: str = models.CharField(max_length=100)
user: str = models.CharField(max_length=100)
def __str__(self):
return self.user
Specially, I want to convert this into Cassandra language.
img_profile = models.ImageField( upload_to='ProfileIMG', default="blankprofile.png")
The documentation you want to consult is here: https://docs.datastax.com/en/developer/python-driver/3.25/api/cassandra/cqlengine/columns/
These are the available columns for DjangoCassandraModel, which is what you would use instead of django.db.models to get a model backed by Cassandra. You can see a basic example of connecting to DataStax Astra with django_cassandra_engine here: https://github.com/DataStax-Examples/django-cassandra-blog
As for the ImageField, I am not sure of the Django internals here, but I believe it stores a path to the file in the database after putting it on disk at the location specified ("img_posts" in your example).
You could do the same for a Cassandra backed model, or use the Blob column type to store the image data itself. There are a number of articles and examples of doing this out there.
To add to the above answer, the django_cassandra_engine package does not offer anything with the same level of automation as the ImageField found in Django's models (i.e. storing the uploaded image on local disk and saving the string path to the database, all from the field definition in the model).
What you would do is to work at a slightly lower abstraction level with an explicit (Django, pure) form. This would allow you to manually handle the file upload as outlined here: https://docs.djangoproject.com/en/4.1/ref/forms/fields/#filefield .
Once you have saved the file and have the string path to it, you can create ann istance of the corresponding Model and manually save it -- all in the appopriate view function.
As a side note, your original (sqlite-backed) code makes use of foreign keys and "on delete cascade" provision for removing related rows from other tables. This cannot be transported as is to a Cassandra storage, since the database, by itself, does not support the concept of relational integrity. You would have to decide how to handle these deletes and act on them explicitly in your code.

Read Image present in Django Model

The code of the model is as follows
class Post(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(null=True,blank=True,upload_to='Files')
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
I want to read the file (image or video).
Let's say its an image. I want to read this image in an array format.
I tried with the following code but i just get the file name and not a image matrix
img = Post.objects.all()[0].file
print(img)
OR
print(np.array(img))
Output is : car-1.jpg
Expected output : 2d Array
by default django store file or image path.. not a file
so you should get your file path + your url and use for example wget lib to get it after that you can use it
example:
import cv2, wget
image_url = 'server_url + link_from_query'
filename = wget.download(image_url)
np_image = cv2.imread(filename)

Change saved filepath in a django celery task

I have a model named Flights
class Flights(models.Model):
field = models.ForeignKey(Field, on_delete=models.CASCADE)
datetime = models.DateTimeField(blank=True, null=True, default=timezone.now())
nir = models.FileField(upload_to = user_directory_path_flights, null=True, blank=True)
red = models.FileField(upload_to = user_directory_path_flights, null=True, blank=True)
rededge = models.FileField(upload_to = user_directory_path_flights, null=True, blank=True)
green = models.FileField(upload_to = user_directory_path_flights, null=True, blank=True)
User uploads some files and through a celery task i get those files and edit them into new ones. After that though they are saved at src folder when i want to save them at src/media/flights/username
How do i do that ? Should i change the Flights model and add a filepath or something? And how so?
celery task :
import sys
import math
from .models import *
import cv2 as cv
import numpy as np
from PIL import Image, ImageOps, ImageChops
import PIL
#shared_task(bind=True)
def get_Flights_Data(self,flight_id):
identifier = Flights.objects.get(pk=flight_id)
redF = identifier.red
nirF = identifier.nir
rededgeF = identifier.rededge
print('Analyzing Flight')
red = Image.open(redF)
nir = Image.open(nirF)
rededge = Image.open(rededgeF)
...............
pil_image=Image.fromarray(ndvi)
img = pil_image
img.save("ndvi_agr.tiff", format="TIFF", save_all=True) #1
Sadly you didn't ask your question correctly so I will try to help you as far as I can.
you can rewrite the previous file saved on the model.
so all you have to do is saving it on the same file path after opening and changing the file.
red= Image.open(redF)
red.save(fp=redF.filepath)
The other option is you can delete the old one and save the new file and give the new file path to your model.
and don't forget to save it.

Django: changing model's schema (replace CharField with ImageField)

I modify project based on Django framework. I have form to add an item. Item has the cover (an image). Current version of model for this item store cover's url like this:
class Item(models.Model):
title = models.CharField(max_length = 255, db_index = True)
slug = models.CharField(max_length = 80, db_index = True)
categories = models.ManyToManyField(Category)
cover_url = models.CharField(max_length = 255, null = True, default = None)
...
Important notice that some images stored on other servers (different file hosting).
I want to replace CharField with ImageField. But how about existing items? I want to change model's schema and save all previously added images. How I can achieve this goal?
Maybe some reasons for this modification can be helpful. The main reason is to provide to users ability to upload images from their computer (not only insert the urls as it was).
TIA!
If cover_url can have existing source - you must have custom storage, that can handle external sources.
Here is example of custom storage usage for ImageField from django documentation:
from django.db import models
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location='/media/photos')
class Car(models.Model):
...
photo = models.ImageField(storage=fs)
Let's jump out of it and we will get code like this:
from django.db import models
from django.core.files.storage import FileSystemStorage
def is_url(name):
return 'http' in name
class MyStorage(FileSystemStorage):
#We should override _save method, instead of save.
def _save(self, name, content=None):
if content is None and is_url(name):
return name
super(MyStorage, self)._save(name, content)
fs = MyStorage()
class Item(models.Model):
title = models.CharField(max_length = 255, db_index = True)
slug = models.CharField(max_length = 80, db_index = True)
categories = models.ManyToManyField(Category)
cover_url = models.ImageField(storage=fs)
It has big room for improvements - here is shown only idea.

Automatically update images

I'd like to implement a functionality in an app of mine, but I don't know how to go about it. What I want is this: I have a model class that uses imagekit to save its images, and I'd like to have the users being able to update the images easily for the vehicles without having to edit each respective vehicle record.
How they'll do this is that there will be a folder named originals and it'll contain folders for each vehicle in the format <stock_number>/PUBLIC If a user moves images into the PUBLIC folder for a vehicle, when the script is executed, it'll compare those images with the current ones and update them if those in the PUBLIC folder are newer. If the record has no images, then they will be added. Also, if the images have been deleted from the site_media directory, then their links should be deleted from the database.
How can I go about this in an efficient way? My models are as below:
class Photo(ImageModel):
name = models.CharField(max_length = 100)
original_image = models.ImageField(upload_to = 'photos')
num_views = models.PositiveIntegerField(editable = False, default=0)
position = models.ForeignKey(PhotoPosition)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class IKOptions:
spec_module = 'vehicles.specs'
cache_dir = 'photos'
image_field = 'original_image'
save_count_as = 'num_views'
class Vehicle(models.Model):
objects = VehicleManager()
stock_number = models.CharField(max_length=6, blank=False, unique=True)
vin = models.CharField(max_length=17, blank=False)
....
images = generic.GenericRelation('Photo', blank=True, null=True)
Progress Update
I've tried out the code, and while it works, I'm missing something as I can get the image, but after that, they aren't transferred into the site_media/photos directory...am I suppossed to do this or imagekit will do this automatically? I'm a bit confused.
I'm saving the photos like so:
Photo.objects.create(content_object = vehicle, object_id = vehicle.id,
original_image = file)
My advice is running django script in a crontab job, lets say, 5 in 5 minutes.
The script would dive into the image folders and compare the images with the records.
A simplified example:
# Set up the Django Enviroment
from django.core.management import setup_environ
import settings
setup_environ(settings)
import os
from your_project.your_app.models import *
from datetime import datetime
vehicles_root = '/home/vehicles'
for stock_number in os.listdir(vehicles_root):
cur_path = vehicles_root+'/'+stock_number
if not os.path.isdir(cur_path):
continue # skip non dirs
for file in os.listdir(cur_path):
if not isfile(cur_path+'/'+file):
continue # skip non file
ext = file.split('.')[-1]
if ext.lower() not in ('png','gif','jpg',):
continue # skip non image
last_mod = os.stat(cur_path+'/'+file).st_mtime
v = Vehicle.objects.get(stock_number=stock_number)
if v.last_upd < datetime.fromtimestamp(last_mod):
# do your magic here, move image, etc.
v.last_upd = datetime.now()
v.save()