Change saved filepath in a django celery task - django

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.

Related

Django, xlsxwriter and images

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:

Image.thumbnail - can't change size properly

I am trying to create model for news. My model contains ImageField where i wont to store thumbnail:
class News(models.Model):
title = models.CharField(verbose_name=u'tytuł', max_length=40)
lead = models.TextField(verbose_name=u'zajawka', blank= False)
body = models.TextField(verbose_name=u'treść ogłosznia', blank=False)
author = models.ForeignKey(User)
active = models.BooleanField(verbose_name=u'aktywność ogłoszenia')
pub_date = models.DateTimeField(verbose_name=u'data publikacji')
slug = models.SlugField(unique=True)
lead_photo= models.ImageField(upload_to="lead_photo/")
objects= NewsManager()
I found on the other site code and i modified it to my needs:
def save(self, force_update=False, force_insert=False, thumb_size=(120,120)):
from PIL import Image
from cStringIO import StringIO
from django.core.files.uploadedfile import SimpleUploadedFile
image = Image.open(self.lead_photo)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
image.thumbnail(thumb_size, Image.ANTIALIAS)
# save the thumbnail to memory
temp_handle = StringIO()
image.save(temp_handle, 'JPEG')
temp_handle.seek(0) # rewind the file
# save to the thumbnail field
suf = SimpleUploadedFile(os.path.split(self.lead_photo.name)[-1],
temp_handle.read(),
content_type='image/jpeg')
self.lead_photo.save(suf.name+'.png', suf, save=False)
# save the image object
super(News, self).save(force_update, force_insert)
the problem is that i cant create thumbnail with different width and height proportion. When for instance a set thumb_size(240,320) i'll get the same proportion as in oryginal but picture is smaller. Thanks for advices.
Edit:
On PIL documentation i found very interesting sentence about that method:
"This method modifies the image to contain a thumbnail version of itself, no larger than the given size." So is there any option to make it exact that size?
You can try resize method.
And as a variant you can create new background image (doc):
newImage = Image.new(resized.mode, resized.size, "black")
and place your main image on it keeping aspect ratio resized by image.thumbnail(thumb_size, Image.ANTIALIAS).
You can use:
http://djangothumbnails.com/
from django.db import models
from thumbs import ImageWithThumbsField
class Person(models.Model):
photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(200,200)))
Do not forget intall pillow
pip install pillow

Select field for all models within a Django app

I am pretty new to Django.
I wanted to create a form for some user information. Depending on type of user informations, the fields should change... For example the users private address needs the fields name, street, zip and city. But if he wants something send to the company, there might be more fields like department or company name.
I want to implement something like this and create for each kind of input an extra model compact in a separate app.
Is there a way to get a select field with a list of all available models in this app.
Edit
Since I have some further problems, I add an example here
file: experiment/models.py
from django.db import models
from django.apps import apps
class BasicExperiment(models.Model):
date_created = models.DateTimeField(editable=False)
date_modified = models.DateTimeField(blank=True)
label_app = apps.get_app('labels')
label_types = apps.get_models(label_app)
file: labels/models.py
from django.db import models
class SILAC(models.Model):
lys0 = models.BooleanField('Lys-0', default=True)
lys4 = models.BooleanField('Lys-4', default=None)
lys8 = models.BooleanField('Lys-8', default=None)
arg0 = models.BooleanField('Arg-0', default=True)
arg6 = models.BooleanField('Arg-6', default=None)
arg10 = models.BooleanField('Arg-10', default=None)
class Meta:
verbose_name = 'SILAC Labeling'
In the shell it works as expected:
>>> from django.apps import apps
>>> app = apps.get_app('labels')
>>> for model in apps.get_models(app):
... model._meta.verbose_name
...
'SILAC Labeling'
Within my models.py I get the following error:
...
File "/Users/madejung/Documents/django_dev/cfproteomics/experiments/models.py", line 5, in <module>
class BasicExperiment(models.Model):
File "/Users/madejung/Documents/django_dev/cfproteomics/experiments/models.py", line 10, in BasicExperiment
label_app = apps.get_app('labels')
File "/Library/Python/2.7/site-packages/django/apps/registry.py", line 370, in get_app
"App '%s' doesn't have a models module." % app_label)
django.core.exceptions.ImproperlyConfigured: App 'labels' doesn't have a models module.
You could try this:
from django.db.models import get_app, get_models
app = get_app('my_application_name')
for model in get_models(app):
# do something with the model
Here there is more information Django get list of models in application

Foreign Keys on Scrapy

im doing an scrap with scrapy and my model on django is:
class Creative(models.Model):
name = models.CharField(max_length=200)
picture = models.CharField(max_length=200, null = True)
class Project(models.Model):
title = models.CharField(max_length=200)
description = models.CharField(max_length=500, null = True)
creative = models.ForeignKey(Creative)
class Image(models.Model):
url = models.CharField(max_length=500)
project = models.ForeignKey(Project)
And my scrapy model:
from scrapy.contrib.djangoitem import DjangoItem
from app.models import Project, Creative
class ProjectItems(DjangoItem):
django_model = Project
class CreativeItems(DjangoItem):
django_model = Creative
So when i save:
creative["name"] = hxs.select('//*[#id="owner"]/text()').extract()[0]
picture = hxs.select('//*[#id="owner-icon"]/a/img/#src').extract()
if len(picture)>0:
creative["picture"] = picture[0]
creative.save()
# Extract title and description of the project
project["title"] = hxs.select('//*[#id="project-title"]/text()').extract()[0]
description = hxs.select('//*[#class="project-description"]/text()').extract()
if len(description)>0:
project["description"] = description[0]
project["creative"] = creative
project.save()
I got the error:
Project.creative" must be a "Creative" instance.
So, how can i add a foreing key value on scrapy?
This can be done by assigning the return value of the creative.save() to the value at project['creative'] So for instance in the following example we use the djangoCreativeItem variable to pass this information to the project:
creative["name"] = hxs.select('//*[#id="owner"]/text()').extract()[0]
picture = hxs.select('//*[#id="owner-icon"]/a/img/#src').extract()
if len(picture)>0:
creative["picture"] = picture[0]
djangoCreativeItem = creative.save()
# Extract title and description of the project
project["title"] = hxs.select('//*[#id="project-title"]/text()').extract()[0]
description = hxs.select('//*[#class="project-description"]/text()').extract()
if len(description)>0:
project["description"] = description[0]
project["creative"] = djangoCreativeItem
project.save()
Like it's been done here, put the ID of your creative directly in creative_id, it should work I think:
project["creative_id"] = creative.id
It will specify the foreign key, without bother you with the object missing (because you're in a Scrapy environment where you don't directly touch the model objects...).

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()