django imagekit: set ProcessedImageField from image url - django

I have got an image url and I want to set a ProcessedImageField attribute from it during object saving. So far I have got this:
class Video(Media):
url = models.URLField('url', max_length=256, default='')
embed_url = models.URLField('embed url', max_length=256, default='')
thumbnail = ProcessedImageField(upload_to='uploads',
processors=[ResizeToFit(width=1024, height=1024, upscale=False)],
format='JPEG',
options={'quality': 75})
def save(self, *args, **kwargs):
from django.core.files.temp import NamedTemporaryFile
import shutil
import requests
import re
params = {
'url': self.url,
'autoplay': 1,
'format': 'json',
}
try:
data = requests.get('http://www.youtube.com/oembed', params=params).json()
embed_url = re.search('src=[\'"]([^\'"]*)[\'"]', data['html']).group(1)
thumbnail_url = data['thumbnail_url']
except:
pass
response = requests.get(thumbnail_url, stream=True)
img_temp = NamedTemporaryFile(delete=True)
shutil.copyfileobj(response.raw, img_temp)
# now image data are in img_temp, how to pass that to ProcessedImageField?
super(Video, self).save(*args, **kwargs)

You should be able to save directly to that property at that point.
self.thumbnail.save("filename.ext", img_temp)

This is the resulting code (without error handling) of mine. In the end, I did in in a simpler manner by avoiding a temporary file and using ContentFile instead.
class Video(Media):
url = models.URLField('url', max_length=256, default='')
embed_url = models.URLField('embed url', max_length=256, default='')
author = models.CharField('author', max_length=64, default='', blank=True)
thumbnail = ProcessedImageField(upload_to='uploads',
processors=[ResizeToFit(width=1024, height=1024, upscale=False)],
format='JPEG',
options={'quality': 75})
def save(self, *args, **kwargs):
from django.core.files.base import ContentFile
import requests
import re
params = {
'url': self.url,
'format': 'json',
}
data = requests.get('http://www.youtube.com/oembed', params=params).json()
embed_url = re.search('src=[\'"]([^\'"]*)[\'"]', data['html']).group(1)
thumbnail_url = data['thumbnail_url']
author = data['author_name']
title = data['title']
image_data = requests.get(thumbnail_url, stream=True).raw.data
self.thumbnail.save(title, ContentFile(image_data), save=False)
self.embed_url = embed_url
self.author = author
self.title = title
super(Video, self).save(*args, **kwargs)

Ok, i've ended with this code for Python 3 :)
it has built-in retries with timeouts between them and support for downloading large files
def save_image_from_url(self, image_url):
s = requests.Session()
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[500, 502, 503, 504])
s.mount('https://', HTTPAdapter(max_retries=retries))
response = s.get(image_url, stream=True, timeout=9)
# here just use whatever name you want, I've just retrieve the path from my custom field
folder_name = Artist.image.field.upload_to.sub_path
random_name = uuid.uuid4().hex + ".png"
# creating folder if it doen't exist
try:
os.makedirs(os.path.join(settings.MEDIA_ROOT, folder_name))
except OSError as e:
if e.errno != errno.EEXIST:
raise
# loading image to tmp location and saving it, it's for large files because we can't handle them in memory
tmp = tempfile.NamedTemporaryFile(delete=True)
try:
tmp.write(response.raw.read())
with open(tmp.name, 'rb') as f:
self.image.save(random_name, f)
finally:
tmp.close()
Where self.image is ProcessedImageField

Related

How to write test for Django image url

I'm writing my first test as a Django developer.
How do I write a test for the image property of this model shown below
class Project(models.Model):
engineer = models.ForeignKey(Engineer, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
tech_used = models.CharField(max_length=200)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
image = models.ImageField(default="project.png")
description = models.TextField(null=True, blank=True)
repo_url = models.URLField(null=True, blank=True)
live_url = models.URLField(null=True, blank=True)
make_public = models.BooleanField(default=False)
def __str__(self):
return self.name
#property
def image_url(self):
try:
url = self.image.url
except:
url = ""
return url
class Meta:
ordering = ["-created"]
I have tried to conjure some patches from here and there although I don't fully understand what my test.py code I just thought to include it to my question to show my efforts
class TestModels(TestCase):
def setUp(self):
new_image = BytesIO()
self.image = Project.objects.create(
image=ImageFile(new_image)
)
def test_image_url(self):
self.assertEquals(self.image.image_url, '')
Please a help on the above question and an explanation of whatever code given as help will be highly appreciated.
Following this answer, one possible way is:
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.utils import timezone
from .models import Engineer, Project
class ProjectImageUploadTest(TestCase):
def setUp(self):
self.engineer = Engineer.objects.create(name='Engineer')
self.project = {
'engineer': self.engineer,
'name': 'Test project',
'tech_used': 'Test tech',
'updated': timezone.now(),
'created': timezone.now(),
'image': None,
'description': 'Test description',
'repo_url': 'https://www.repo.example.com',
'live_url': 'https://www.live.example.com',
'make_public': False
}
self.obj = Project.objects.create(**self.project)
def tearDown(self):
self.obj.image.delete()
def test_upload_image(self):
img_url = r'X:\Path\to\your\image.png'
self.obj.image= SimpleUploadedFile(
name='test_image.jpg',
content=open(img_url, 'rb').read(),
content_type='image/png')
self.obj.save()
self.obj.refresh_from_db()
self.assertNotEqual(self.obj.image, None)
I would like to complement saying that is also possible to implement the test using Python's tempfile.

how to write File Download with django Rest framework?

I have a model with filefield with xls and xlsx and person who uploaded it i need to write api view in DRF that returns download on front end how can my view be?
models.py
class FileuploaderView(BaseModel):
file = models.FileField(
upload_to='',
validators=[FileExtensionValidator(['xls', 'xlsx'])],
)
created_by = models.ForeignKey(
'other model',
related_name= '',
null=True,
on_delete=models.SET_NULL,
)
views.py:
def DownloadView(APIView):
def get(self, request, id, format=None):
queryset = Model.objects.get(id=id)
file_handle = queryset.file.path
document = open(file_handle, 'rb')
response = HttpResponse(FileWrapper(document), content_type='')
response['Content-Disposition'] = 'attachment; filename="%s"' % queryset.file.name
return response
Is it the
You might want this:
file_path = file_url
FileData = open(file_path,"r")
response = HttpResponse(FileData,content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'
return response
also checkout this

Django uploading a file deletes the "default" image

I have an Ourteam App that allows you to upload an image, name, title, and social media information for employees. Whenever I create an object the "default.jpg" file is deleted from the media_root.
This is my model:
from django.db import models
from cms.models.pluginmodel import CMSPlugin
from django.utils.translation import ugettext_lazy as _
from smartfields import fields
from smartfields.dependencies import FileDependency
from smartfields.processors import ImageProcessor
from django.template.defaultfilters import slugify
class Employee(CMSPlugin):
# Set Name
name = models.CharField(_('name'), max_length=48)
# Define Slug
slug = models.SlugField(max_length=40, null = False, blank = True)
# Set Title
title = models.CharField(_('title'), max_length=48)
# Set Image upload path and image properties
image_upload_path = 'ourteam/%Y/%m/%d'
image = fields.ImageField(upload_to=image_upload_path,
blank=True, default='ourteam/default.jpg',
dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 150, 'max_height': 150}))
])
created = models.DateTimeField(_('created'), auto_now_add=True)
email = models.EmailField(_('email'), max_length=254)
# Social Media
twitter = models.CharField(_('twitter'), max_length=24, blank=True, default='https://www.twitter.com')
linkedin = models.CharField(_('linkedin'), max_length=24,blank=True, default='https://www.linkedin.com')
facebook = models.CharField(_('facebook'), max_length=24,blank=True, default='https://www.facebook.com')
class Meta:
verbose_name = _('employee')
verbose_name_plural = _('employee')
db_table = 'employee'
ordering = ('-created',)
get_latest_by = 'created'
def __unicode__(self):
return u'%s' % self.title
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Employee, self).save(*args, **kwargs)
def get_all_employees():
all_entries = Employee.objects.all().order_by('created')
return all_entries
def slug(sluggy):
sluggy = sluggy.replace(' ', '-').lower()
return slugify(sluggy)
You should try with that :
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class MyModel(models.Model):
upload = models.FileField(upload_to=user_directory_path)

upload an images using django and tastypie (python version : 2.7)

I am having a hard time figuring out a way of doing multipart/formencoded image upload using django and tastypie. I went through all the possible answers on stackoverflow but cant seem to find a solution that would work. Also, i am a beginner in python so cant seem to understand a lot of stuff. I have written some code and would like someone to point me as to what am i doing wrong.
Models.py
import random
from django.db import models
from django.template.loader import get_template
from django.template import Context
import suuq.settings
from usermanagement import utils
from django.contrib.auth.models import UserManager
from django.db.models import ImageField
class adManager(models.Manager):
def create_ad(self, category, title, email, tag, location, address, description, phone, img):
if not category:
raise ValueError('add must have a category')
if not title:
raise ValueError('add must have a title')
if not email:
raise ValueError('ad must have a email')
if not tag:
raise ValueError('ad must have a tag')
if not location:
raise ValueError('ad must have a location')
if not address:
raise ValueError('ad must have a address')
if not description:
raise ValueError('ad must have a description')
if not phone:
raise ValueError('ad must have a phone number')
if not img:
raise ValueError('ad must have a image')
ad = self.create(category = category, title = title, email = UserManager.normalize_email(email).strip().lower(),
tag = tag, location = location, address = address, description = description, phone = phone, img=img)
ad.save()
return ad
class Ad(models.Model):
objects = adManager()
category = models.CharField(max_length=100)
title = models.CharField(max_length=200)
email = models.EmailField(
max_length=255,
unique=True,
)
tag = models.CharField(max_length=200)
location = models.CharField(max_length=50)
address = models.CharField(max_length=200)
description = models.CharField(max_length=140)
phone = models.CharField(max_length=10, null=True)
img = models.ImageField(upload_to="img", null=True, blank=True)
api.py
import json
from django.conf.urls import url
from django import forms
from tastypie.authentication import SessionAuthentication
from tastypie.authorization import Authorization
from tastypie.exceptions import Unauthorized
from tastypie.resources import ModelResource
from tastypie.throttle import CacheThrottle
from tastypie.utils import trailing_slash
from tastypie.validation import FormValidation
from django.db.models import FileField
from tastypie import http, fields
from PIL import Image
from ad.models import Ad
class MultipartResource(object):
def deserialize(self, request, data, format=None):
if not format:
format = request.META.get('CONTENT_TYPE', 'application/json')
if format == 'application/x-www-form-urlencoded':
return request.POST
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
return data
return super(MultipartResource, self).deserialize(request, data, format)
class AdResource(ModelResource, MultipartResource):
img = fields.FileField(attribute="img", null=True, blank=True)
class Meta:
queryset = Ad.objects.all()
resource_name = 'ad'
fields = ['id', 'category', 'title','email','tag','location', 'address', 'description', 'phone', 'img']
allowed_methods = ['post','get','delete']
include_resource_uri = False
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/add%s$" %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('add_ad'), name="add_ad"),
]
def add_ad(self, request, **kwargs):
self.method_check(request, allowed=['post'])
data = json.loads(request.body)
category = data.get('category', '')
title = data.get('title', '')
email = data.get('email', '')
tag = data.get('tag', '')
location = data.get('location', '')
address = data.get('address', '')
description = data.get('description', '')
phone = data.get('phone', '')
if(request.method == 'POST'):
if "multipart/form-data" not in str(request.META['CONTENT_TYPE']):
return
else:
if('img' in request.FILES):
upload = request.FILES['img']
img = Image.open(upload)
return
else:
return
else:
return
ad = Ad.objects.create_ad(category=category, title=title, email=email, tag=tag,
location=location, address=address, description=description, phone=phone, img=img)
return self.create_response(request, {
'success': True,
'ad_id': ad.id,
'message': 'ad address successfully added'
})
I know my code is not indented properly but i have it properly indented on my dev end. Please help me fix my logic, i am really stuck.
I found the problem and here is my updated solution using multipart form data
class AdResource(ModelResource):
img = fields.FileField(attribute="img", null=True, blank=True)
class Meta:
queryset = Ad.objects.all()
resource_name = 'ad'
fields = ['id', 'category', 'title','email','tag','location', 'address', 'description', 'phone', 'img']
allowed_methods = ['post','get','delete']
include_resource_uri = False
always_return_data = True
limit = 0
authentication = SessionAuthentication()
authorization = AdAuthorization()
throttle = CacheThrottle(throttle_at=200)
def prepend_urls(self):
return [
url(r"^(?P<resource_name>%s)/add%s$" %
(self._meta.resource_name, trailing_slash()),
self.wrap_view('add_ad'), name="add_ad"),
]
def add_ad(self, request, **kwargs):
self.is_authenticated(request)
self.method_check(request, allowed=['post'])
format = request.META.get('CONTENT_TYPE')
if format.startswith('multipart'):
data = request.POST.copy()
data.update(request.FILES)
category = data.get('category', '')
title = data.get('title', '')
email = data.get('email', '')
tag = data.get('tag', '')
location = data.get('location', '')
address = data.get('address', '')
description = data.get('description', '')
phone = data.get('phone', '')
img = data.get('img','')
ad = Ad.objects.create_ad(user=request.user, category=category, title=title, email=email, tag=tag,
location=location, address=address, description=description, phone=phone, img=img)
return self.create_response(request, {
'success': True,
'message': 'Ad address successfully added',
'id': ad.id
})
else:
return self.create_response(request, {
'success': False,
'message': 'Invalid format'
})

Django Error (13, 'Permission denied')

I'm been working on this Photo Organizer and Sharing App Part I at http://lightbird.net/dbe/photo.html. I'm trying to generate a thumbnail and when I do . I get this error.
I have Windows Vista.
IOError at /admin/photo/image/add/
(13, 'Permission denied')
Request Method: POST
Request URL: http://127.0.0.1:8000/admin/photo/image/add/
Django Version: 1.4.3
Exception Type: IOError
Exception Value: (13, 'Permission denied')
Exception Location:C:\Python26\lib\site-packages\PIL\Image.py in save, line 1399
Python Executable:C:\Python26\python.exe
Python Version: 2.6.0
Python Path:
['C:\\djcode\\mysite',
'C:\\Python26\\python26.zip',
'C:\\Python26\\DLLs',
'C:\\Python26\\lib',
'C:\\Python26\\lib\\plat-win',
'C:\\Python26\\lib\\lib-tk',
'C:\\Python26',
'C:\\Python26\\lib\\site-packages',
'C:\\Python26\\lib\\site-packages\\PIL']
Server time: Sun, 10 Feb 2013 23:49:34 +1100
My models.py is
from django.db import models
from django.contrib.auth.models import User
from django.contrib import admin
from string import join
from django.core.files import File
from os.path import join as pjoin
from tempfile import *
import os
from PIL import Image as PImage
from mysite.settings import MEDIA_ROOT
class Album(models.Model):
title = models.CharField(max_length=60)
public = models.BooleanField(default=False)
def __unicode__(self):
return self.title
class Tag(models.Model):
tag = models.CharField(max_length=50)
def __unicode__(self):
return self.tag
class Image(models.Model):
title = models.CharField(max_length=60, blank=True, null=True)
image = models.FileField(upload_to="images/")
tags = models.ManyToManyField(Tag, blank=True)
albums = models.ManyToManyField(Album, blank=True)
created = models.DateTimeField(auto_now_add=True)
rating = models.IntegerField(default=50)
width = models.IntegerField(blank=True, null=True)
height = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, null=True, blank=True)
thumbnail2 = models.ImageField(upload_to="images/", blank=True, null=True)
def __unicode__(self):
return self.image.name
def save(self, *args, **kwargs):
"""Save image dimensions."""
super(Image, self).save(*args, **kwargs)
im = PImage.open(pjoin(MEDIA_ROOT, self.image.name))
self.width, self.height = im.size
# large thumbnail
fn, ext = os.path.splitext(self.image.name)
im.thumbnail((128,128), PImage.ANTIALIAS)
thumb_fn = fn + "-thumb2" + ext
tf2 = NamedTemporaryFile()
im.save(tf2.name, "JPEG")
self.thumbnail2.save(thumb_fn, File(open(tf2.name)), save=False)
tf2.close()
# small thumbnail
im.thumbnail((40,40), PImage.ANTIALIAS)
thumb_fn = fn + "-thumb" + ext
tf = NamedTemporaryFile()
im.save(tf.name, "JPEG")
self.thumbnail.save(thumb_fn, File(open(tf.name)), save=False)
tf.close()
super(Image, self).save(*args, ** kwargs)
def size(self):
"""Image size."""
return "%s x %s" % (self.width, self.height)
def __unicode__(self):
return self.image.name
def tags_(self):
lst = [x[1] for x in self.tags.values_list()]
return str(join(lst, ', '))
def albums_(self):
lst = [x[1] for x in self.albums.values_list()]
return str(join(lst, ', '))
def thumbnail(self):
return """<img border="0" alt="" src="/media/%s" height="40" />""" % (
(self.image.name, self.image.name))
thumbnail.allow_tags = True
class AlbumAdmin(admin.ModelAdmin):
search_fields = ["title"]
list_display = ["title"]
class TagAdmin(admin.ModelAdmin):
list_display = ["tag"]
class ImageAdmin(admin.ModelAdmin):
search_fields = ["title"]
list_display = ["__unicode__", "title", "user", "rating", "size", "tags_", "albums_","thumbnail", "created"]
list_filter = ["tags", "albums"]
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
The problem is here:
from django.core.files import File
from os.path import join as pjoin
from tempfile import *
class Image(models.Model):
# ...
thumbnail2 = models.ImageField(upload_to="images/", blank=True, null=True)
def save(self, *args, **kwargs):
"""Save image dimensions."""
super(Image, self).save(*args, **kwargs)
im = PImage.open(pjoin(MEDIA_ROOT, self.image.name))
self.width, self.height = im.size
# large thumbnail
fn, ext = os.path.splitext(self.image.name)
im.thumbnail((128,128), PImage.ANTIALIAS)
thumb_fn = fn + "-thumb2" + ext
tf2 = NamedTemporaryFile()
im.save(tf2.name, "JPEG")
self.thumbnail2.save(thumb_fn, File(open(tf2.name)), save=False)
tf2.close()
# small thumbnail
im.thumbnail((40,40), PImage.ANTIALIAS)
thumb_fn = fn + "-thumb" + ext
tf = NamedTemporaryFile()
im.save(tf.name, "JPEG")
self.thumbnail.save(thumb_fn, File(open(tf.name)), save=False)
tf.close()
super(Image, self).save(*args, ** kwargs)
How do I fix this error?
It looks to me like django doesn't have the permissions it needs to access your MEDIA_ROOT folder.
Have a look at your MEDIA_ROOT settings in your settings.py file. Then check the permissions on the folder (something like ls -lsa /path/to/media_root from a bash shell). Make sure the user running django as write permission to the folder.
Also, as asermax points out, make sure you have created an images directory within your MEDIA_ROOT.
Have a look at the documentation for serving static files particularly the section on serving other directories
UPDATE
Perhaps it's this issue. Try replacing im.save(tf2.name, "JPEG") with im.save(tf2, "JPEG")
set SELinux permisions
http://wiki.apache.org/httpd/13PermissionDenied
take a look to this, it may be there the solution