Django: manually create imagefield in model from existing file on server - python

This is killing me!
I'm using django-filebrowser, and I want to create a gallery app that leverages it's upload capabilities to manage images.
I have a Gallery model that allows the user to select or create a directory on the server, and upload files to that folder to appear in the gallery. I want to automatically trawl the directory that the user has uploaded images to and selected, and then automatically create Image instances for each image in the folder.
class Gallery(model.Models):
gallerydirectory = FileBrowserField(...)
title = ...
description ...
class Image(model.Models):
image_field = models.ImageField()
The problem is that FileBrowser represents images differently to Django, but I want to use DJango ImageFields as I can then use other apps (sorl thumbnails) on the template end.
I have all the data necessary for the file i.e. filename, path etc, I just can't get Django to create an instance of an ImageField, without actually uploading the image again. I simply want to populate it.
I have seen another thread here which suggests the following:
for image in filebrowser_image_objects_list:
f = File(open('path-to-file-on-server','r'))
i = Image()
i.image_field('filename.png',f.read())
but this is giving me a:
SuspiciousOperation error
Attempted access to '/filename.png' denied
which suggests that the path isn't being read correctly. I've printed the attributes of the File Object, and it is opening the correct image, it just isn't getting passed on to the ImageField
Help would be greately appreciated!
UPDATE
I've given up trying to get this work as it's just too messy. The problem I had above was that I had set the upload_field of the ImageField to '/' and it had gone unnoticed meaning that the file was being written to '/something.png'.
I've modified it so that the Image is now using a FileBrowserField as well instead of an ImageField.

I might be missing something, but this worked for me:
from a1.models import Model1
from django.core.files.images import ImageFile
m = Model1.objects.create()
m.f1 = ImageFile(open("1.png", "rb"))
m.save()
for the following model:
class Model1(models.Model):
f1 = models.ImageField()
This way it didn't work:
m.f1('1.png', File.read(open('1.png', 'r')))
It says:
TypeError: 'ImageFieldFile' object is not callable
Checked with Django 1.7, 1.11.

I'm marking this as answered, as this is the correct way to do this:
from django.core.files import File
image_model.image_field('path', File().read())
Programmatically saving image to Django ImageField

This works for me on Python3 with Django 2
from urllib.request import urlopen
from urllib.parse import urlparse
from io import BytesIO
from django.core.files.images import ImageFile
from .models import ModelWithImageField
# Solving for SSL Error
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
url = https://www.someurl.com/image.png?other_params_if_they_exist
image_file_name = urlparse(url).path.split('/')[-1]
image_file_content = BytesIO(urlopen(url).read())
ModelWithImageField().image_field.save(image_file_name, image_file_content)

Related

django do not save thumbnails from imagekit

from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
class Image(models.Model):
image = models.ImageField(upload_to='home/', blank=True)
thumbnail = ImageSpecField(source='image', processors=[ResizeToFill(50, 50)],format='JPEG', options={'quality':60})
when I uploading image. Everything OK with original image. But there is no thumbnail image.
I guess this problem is related with cache. Maybe I am wrong. Can't figure out what to do...
Please help.
In order to "enforce" file generation, your 'IMAGEKIT_DEFAULT_CACHEFILE_STRATEGYshould implementon_source_saved`.
One is provided but the package, and adding:
IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.Optimistic'
to your settings.py will enforce file generation on source save.
Now please pay attention: this will "only" work when using ImageSpecField and you might have an hard time using this strategy with templatetags or ImageSpec without handling correctly source groups
Another way is to write your custom CACHEFILE_STRATEGY``
Insome_app/strategy.py`
class CustomStrategy(object):
"""
A strategy that ensures file creation on save and existence
"""
def on_existence_required(self, file):
file.generate()
def on_content_required(self, file):
file.generate()
def on_source_saved(self, file):
file.generate()
Now, adding
IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'your_app.strategy.CustomStrategy'
to your settings.py should work like a charm.

How can I do a hierarchical validation in Django?

I'm writing a Django app, where users can upload CSV files. Therefore I've created an upload model with three validators:
One that checks the file extension (FileExtensionValidator),
one for the MIME type validation (ValidateFileType),
and a third one for parsing the CSV file and checking for data types, right number of columns and so on (ValidateCsv).
It'd be reasonable to check the upload only with the next validator if the preceding validation didn't raise a ValidationError.
For instance, the user could upload a .py file. This would raise an error in all three validators, but I want to avoid, that Django checks the MIME type or even tries to treat and parse a .py file as a CSV file, although the file extension wasn't correct right from the beginning.
So here is my model for the user's upload:
models.py
from django.db import models
from .utils import unique_file_path
from django.core.validators import FileExtensionValidator
from .validators import ValidateFileType, ValidateCsv
class Upload(models.Model):
date_uploaded = models.DateTimeField(auto_now_add=True)
file = models.FileField(upload_to=unique_file_path, validators=[FileExtensionValidator(['csv']), ValidateFileType, ValidateCsv], max_length=255)
With this validators list all three validations are always performed and I can see all the error messages in upload_form.errors. For example:
File extension 'py' is not allowed. Allowed extensions are: 'csv'.
File type text/x-python not supported.
Some data is invalid. Please check your CSV file.
forms.py
from django import forms
from .models import Upload
class UploadForm(forms.ModelForm):
class Meta:
model = Upload
view.py
from .forms import UploadForm
def someView(request):
upload_form = UploadForm()
...
context = {'upload_form': upload_form}
return render(request, 'someTemplate.html', context)
Do you have an idea, what's the best approach to make such a hierarchical chain of validators? Of course I could write some big all-in-one validator function, but since I use a Django core validator, I dont't want to rewrite this one, but combine existing django validators with my own ones.
You don't need to rewrite the django core validator.
In your validators file:
from django.core.validators import FileExtensionValidator
def ValidateFileType(value):
....your code....
def ValidateCsv(value):
....your code....
def csv_validator(value):
'''Your all in one function'''
extension = FileExtensionValidator(['csv'])
extension(value) #FileExtensionValidator is a callable class. See docs for that.
ValidateFileType(value)
ValidateCsv(value)
Don't know if that's the best way, but it should do the trick.

TypeError when open object of django filefield

I want to make a button named 'count' to count the number of page of the uploaded pdf file. However, there is TypeError invalid file:
How can I improve my code to tackle this error...?
PS. I'm newbie in coding using django 1.10, and just want to make some little tool to make my life easiler :)
Thanks in advance
My Models
from django.db import models
from PyPDF2 import PdfFileReader
class PdfFile(models.Model):
file = models.FileField(upload_to='document/')
num_of_pages = models.IntegerField(null=True)
def page_count(self):
pdf = PdfFileReader(open(self.file, 'rb'))
self.num_of_pages = pdf.getNumPages()
self.save()
My Views
def count(request, pk):
pdf = get_object_or_404(PdfFile, pk=pk)
pdf.page_count()
return redirect('img_preview', pk=pk)
You can't pass a filefield value directly to open. However, as the documentation shows, that object itself has an open method:
pdf = PdfFileReader(self.file.open())
Because of the way that class also defines read and __iter__, you might actually be able to pass the field directly:
pdf = PdfFileReader(self.file)

Convert blob to Django ImageField in python?

I read user image in BLOB file, but i want save it to image format in django model.
How can i convert this file to image file(.jpeg) and save it in django models.ImageField?
I use python 2.7 and django 1.9.
my model is:
class Staff(models.Model):
user = models.ForeignKey(User)
cn = models.CharField(max_length=100)
new_comer = models.NullBooleanField()
change_position = models.NullBooleanField()
change_manager = models.NullBooleanField()
acting = models.NullBooleanField()
expelled = models.NullBooleanField()
active = models.NullBooleanField()
avatar = models.ImageField(upload_to='/images/')
Please help me...
You need to try something like this.
import io
from django.core.files.base import File
# Set values of your model filed.
staff_instance = Staff()
staff_instance.user = user_instance
...
...
with io.BytesIO(blob_file) as stream:
django_file = File(stream)
staff_instance.avatar.save(some_file_name, django_file)
staff_instance.save()
I assume that blob is a byte array of the file.
To make it a file i need to convert it to a stream.
Thus I thought BytesIO would be a good choice.
You can directly save file to disk but if you want django to upload it to your upload_to directory, you need to use django.core.files.base.File class.
When you run django.core.files.base() method file will be saved to desired directory.
I guess you will use this for an data migration process, not in a view.
If this is the case than you could put this code at a django command.
Then you can use any django and project related resources.
Let me know if it helps.

How to use Azure's BlobService object to upload a file associated to a Django model

I have a Django app where users upload photos and descriptions. Here's a typical model which facilitates that user behavior:
class Photo(models.Model):
description = models.TextField(validators=[MaxLengthValidator(500)])
submitted_on = models.DateTimeField(auto_now_add=True)
image_file = models.ImageField(upload_to=upload_to_location, null=True, blank=True )
Notice the image_file attribute has upload_to argument, which is fed the upload directory and file name of the image_file. The upload_to_location method takes care of that; assume it works correctly.
Now I want to upload each image to Azure Cloud Storage. The python snippet to do that is explained here. Using that, I tried to write my own custom storage that saves images to Azure. It's buggy though, and I need help in cleaning it up. Here's what I've done:
Changed the image_file attribute in models.py to:
image_file = models.ImageField("Tasveer dalo:",upload_to=upload_to_location, storage=OverwriteStorage(), null=True, blank=True )
And then created a separate storage.py in my app folder that has:
from django.conf import settings
from django.core.files.storage import Storage
from azure.storage.blob import BlobService
class OverwriteStorage(Storage):
def __init__(self,option=None):
if not option:
pass
def _save(name,content):
blob_service = BlobService(account_name='accname', account_key='key')
PROJECT_ROOT = path.dirname(path.abspath(path.dirname(__file__)))
try:
blob_service.put_block_blob_from_path(
'containername',
name,
path.join(path.join(PROJECT_ROOT,'uploads'),name),
x_ms_blob_content_type='image/jpg'
)
return name
except:
print(sys.exc_info()[1])
return 0
def get_available_name(self,name):
return name
This set up doesn't work, and returns the error: _save() takes exactly 2 arguments (3 given). Exception Location: /home/hassan/.virtualenvs/redditpk/local/lib/python2.7/site-packages/django/core/files/storage.py in save, line 48
How do I make this work? Has anyone used Azure-Storage python SDK with their Django projects in this way? Please advise.
Note: Originally, I was using the django-storages library, which obfuscated storage details from me, reducing everything to just some configuration to be entered in settings.py. But now, I need to remove django-storages from the equation, and solely use the Azure-Storage python SDK for the purpose.
Note: Ask for more information in case you need it
According your error message, you missed parameter in function _save() which should be complete in the format like _save(self,name,content).
And additionally, it seems that you want put the images directly to Azure Storage which are uploaded from client forms. If so, I found a repo in github which builds a custom azure storage class for Django models. We can get leverage it to modify your application. For more details, refer to https://github.com/Rediker-Software/django-azure-storage/blob/master/azure_storage/storage.py
And here are my code snippets,
models.py:
from django.db import models
from django.conf import settings
from django.core.files.storage import Storage
from azure.storage.blob import BlobService
accountName = 'accountName'
accountKey = 'accountKey'
class OverwriteStorage(Storage):
def __init__(self,option=None):
if not option:
pass
def _save(self,name,content):
blob_service = BlobService(account_name=accountName, account_key=accountKey)
import mimetypes
content.open()
content_type = None
if hasattr(content.file, 'content_type'):
content_type = content.file.content_type
else:
content_type = mimetypes.guess_type(name)[0]
content_str = content.read()
blob_service.put_blob(
'mycontainer',
name,
content_str,
x_ms_blob_type='BlockBlob',
x_ms_blob_content_type=content_type
)
content.close()
return name
def get_available_name(self,name):
return name
def upload_path(instance, filename):
return 'uploads-from-custom-storage-{}'.format(filename)
class Photo(models.Model):
image_file = models.ImageField(upload_to=upload_path, storage=OverwriteStorage(), null=True, blank=True )

Categories