django delete s3 image uploaded using custom field - amazon-s3

I am using a custom field to upload image on s3 using django 1.9. I want to delete image from s3 whenever model instance is deleted. I have tried post_delete signal with ImageField's delete() method but since I'm using custom field cannot achieve the result. Any suggestion on how to achieve this?

from django.db.models.signals import pre_delete
.....
pre_delete.connect(delete_image, dispatch_uid="delete_image")
.....
def delete_image(sender, instance, **kwargs):
for field_name in instance._meta.get_fields():
try:
field = getattr(instance, field_name)
except:
field = None
if isinstance(field, your_custom_field):
your_app_utils.clean_images(field.get_images())

Related

Scrapy - Dynamic file naming form parsed item

I'm working on scraping program for an art museum.
I'm new to the Scrapy framework and intermediate in python at best
I need to download images from the website and name them accordingly with the value form the parsed data.
I've been going through Scrapy documentation and Google searches but no luck so far. I'm stuck at the pipeline.
I know how I could fix file names after running the Scrapy with wrapper program, but that seem counter productive and sloppy.
Each item yielded from the spider looks like this:
{'Artist': 'SomeArtist',
...
'Image Url': 'https://www.nationalgallery.org.uk/media/33219/n-1171-00-000049-hd.jpg',
'Inventory number': 'NG1171'}
I need to name the image by 'Inventory number'
I managed to make a custom pipeline, but no luck making it work the way I want to.
The closest I got was this, but it failed miserably by assigning same self.file_name value to many images
class DownloadPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
# The only point, that I've found, for accessing item dict before downloading
self.file_name = item['Inventory number']
yield Request(item["Image Url"])
def file_path(self, request, response=None, info=None):
return f"Images/{self.file_name}.jpg"
Something like this would be great:
class DownloadPipeline(ImagesPipeline):
def file_path(self, request, item, response=None, info=None):
file_name = item['Inventory number']
return f"Images/{file_name}.jpg"
Is there any way to make that work?
When you yield the request in get_media_requests you can pass arbitrary data inside the meta param, so you can access as an attribute of request in your file_path method.
class DownloadPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
yield Request(
url=item["Image Url"],
meta={'inventory_number': item.get('Inventory number')}
)
def file_path(self, request, response=None, info=None):
file_name = request.meta.get('inventory_number)
return f"Images/{file_name}.jpg"
Read more here

Odoo: extends the import function for a specify model

I want to change the Import function of Odoo, for a specify model (in this case, it is mrp_production.
Import Function Image
For example, my csv file has 2 columns only: product_id and product_qty.
I want the Bill of Material to be loaded automatically after importing (currently it is empty). I want to customize the Import function for this model only.
Is there anyone do this before? Or please provide some solutions/links on how to do it.
Thank you very much.
For this, you simply override the create method for the mrp model and try creating one record from form view. If you have written correct logic to get the BOM automatically it will automatically work while importing.
In, import function odoo basically calls the create method for the model.
Thanks

How do I get dimensions from a CloudinaryPreloadedFile

I need to save the dimensions of my images in my database to help me render images in a pinterest style gallery format.
I use to have this method:
def update_asset_attributes
if image.present? && image_changed?
ap image.file
self.image_content_type = image.file.content_type
self.image_file_size = image.file.size
self.image_width, self.image_height = `identify -format "%wx%h" #{image.file.path}`.split(/x/)
end
end
But now it says: NoMethodError - undefined method content_type for #<Cloudinary::CarrierWave::PreloadedCloudinaryFile:0x007f9834d81840>:
CloudinaryPreloadedFile doesn't have this information at the moment. You can either -
Pass the information by yourself from the javascript code to the server (you can use the cloudinarydone callback data.result object).
Use the attachinary gem.
If the number of images uploaded per hour are small, you can use the Admin API to get the resource's information given it's public_id.

Scrapy: How to change the image name

I'm using scrapy to do a project.
I got the image name and image url in html, how can I name this image with that name instead of the hash name?
I got this url: http://a3.mzstatic.com/us/r1000/104/Purple/v4/55/35/20/55352022-0aba-260b-76ed-314eacd8c1fc/mzm.zqqzrdix.175x175-75.jpg
and it's name: iBook
I want my scrapy to download this picture and rename it with iBook.
You have to use the Images pipeline and something like this
class MyImagesPipeline(ImagesPipeline):
def image_key(self, url):
image_guid = url.split('/')[-1]
return 'full/%s' % (image_guid)
It will use the original image name. For custom filename use something like
return 'ibook.jpg' But it will overwrite all the images with same file. be careful
get some more ideas from this Scrapy image download how to use custom filename

Load template from a string instead of from a file

I have decided to save templates of all system emails in the DB.
The body of these emails are normal django templates (with tags).
This means I need the template engine to load the template from a string and not from a file. Is there a way to accomplish this?
Instantiate a django.template.Template(), passing the string to use as a template.
To complement the answer from Ignacio Vazquez-Abrams, here is the code snippet that I use to get a template object from a string:
from django.template import engines, TemplateSyntaxError
def template_from_string(template_string, using=None):
"""
Convert a string into a template object,
using a given template engine or using the default backends
from settings.TEMPLATES if no engine was specified.
"""
# This function is based on django.template.loader.get_template,
# but uses Engine.from_string instead of Engine.get_template.
chain = []
engine_list = engines.all() if using is None else [engines[using]]
for engine in engine_list:
try:
return engine.from_string(template_string)
except TemplateSyntaxError as e:
chain.append(e)
raise TemplateSyntaxError(template_string, chain=chain)
The engine.from_string method will instantiate a django.template.Template object with template_string as its first argument, using the first backend from settings.TEMPLATES that does not result in an error.
Using django Template together with Context worked for me on >= Django 3.
from django.template import Template, Context
template = Template('Hello {{name}}.')
context = Context(dict(name='World'))
rendered: str = template.render(context)