python - imagenes - imagefield en django
Ahorro de imágenes mediante programación en Django ImageField (13)
Ok, he intentado casi todo y no puedo hacer que esto funcione.
- Tengo un modelo de Django con un ImageField en él
- Tengo un código que descarga una imagen a través de HTTP (probado y funciona)
- La imagen se guarda directamente en la carpeta ''upload_to'' (el upload_to es el que se establece en el ImageField)
- Todo lo que necesito hacer es asociar la ruta del archivo de imagen ya existente con ImageField
He escrito este código de 6 maneras diferentes.
El problema al que me estoy enfrentando es que todo el código que estoy escribiendo da como resultado el siguiente comportamiento: (1) Django creará un segundo archivo, (2) cambiará el nombre del nuevo archivo y agregará un _ al final del archivo nombre, luego (3) no transfiere ninguno de los datos dejando básicamente un archivo vacío renombrado. Lo que queda en la ruta ''upload_to'' es 2 archivos, uno que es la imagen real, y otro que es el nombre de la imagen, pero está vacío, y por supuesto, la ruta de ImageField está configurada en el archivo vacío que Django intenta crear .
En caso de que no esté claro, intentaré ilustrar:
## Image generation code runs....
/Upload
generated_image.jpg 4kb
## Attempt to set the ImageField path...
/Upload
generated_image.jpg 4kb
generated_image_.jpg 0kb
ImageField.Path = /Upload/generated_image_.jpg
¿Cómo puedo hacer esto sin que Django intente volver a almacenar el archivo? Lo que realmente me gustaría es algo en este sentido ...
model.ImageField.path = generated_image_path
... pero, por supuesto, eso no funciona.
Y sí, he revisado las otras preguntas aquí como esta , así como el documento de django en el File
ACTUALIZACIÓN Después de realizar más pruebas, solo realiza este comportamiento cuando se ejecuta en Apache en Windows Server. Mientras se ejecuta bajo el ''runserver'' en XP, no ejecuta este comportamiento.
Estoy perplejo.
Aquí está el código que se ejecuta con éxito en XP ...
f = open(thumb_path, ''r'')
model.thumbnail = File(f)
model.save()
De acuerdo, si todo lo que necesita hacer es asociar la ruta del archivo de imagen ya existente con ImageField, entonces esta solución puede ser útil:
from django.core.files.base import ContentFile
with open(''/path/to/already/existing/file'') as f:
data = f.read()
# obj.image is the ImageField
obj.image.save(''imgfilename.jpg'', ContentFile(data))
Bueno, si es serio, el archivo de imagen ya existente no se asociará con ImageField, pero la copia de este archivo se creará en upload_to dir como ''imgfilename.jpg'' y se asociará con ImageField.
Esta podría no ser la respuesta que estás buscando. pero puede usar charfield para almacenar la ruta del archivo en lugar de ImageFile. De esa forma, puede asociar de forma programática la imagen cargada al campo sin volver a crear el archivo.
Este es un método que funciona bien y le permite convertir el archivo a un formato determinado también (para evitar el error "no se puede escribir el modo P como JPEG"):
import urllib2
from django.core.files.base import ContentFile
from StringIO import StringIO
def download_image(name, image, url):
input_file = StringIO(urllib2.urlopen(url).read())
output_file = StringIO()
img = Image.open(input_file)
if img.mode != "RGB":
img = img.convert("RGB")
img.save(output_file, "JPEG")
image.save(name+".jpg", ContentFile(output_file.getvalue()), save=False)
donde imagen es django ImageField o your_model_instance.image aquí hay un ejemplo de uso:
p = ProfilePhoto(user=user)
download_image(str(user.id), p.image, image_url)
p.save()
Espero que esto ayude
La solución más simple en mi opinión:
from django.core.files import File
with open(''path_to_file'', ''r'') as f: # use ''rb'' mode for python3
data = File(f)
model.image.save(''filename'', data, True)
Lo que hice fue crear mi propio almacenamiento que simplemente no guardará el archivo en el disco:
from django.core.files.storage import FileSystemStorage
class CustomStorage(FileSystemStorage):
def _open(self, name, mode=''rb''):
return File(open(self.path(name), mode))
def _save(self, name, content):
# here, you should implement how the file is to be saved
# like on other machines or something, and return the name of the file.
# In our case, we just return the name, and disable any kind of save
return name
def get_available_name(self, name):
return name
Luego, en mis modelos, para mi ImageField, he usado el nuevo almacenamiento personalizado:
from custom_storage import CustomStorage
custom_store = CustomStorage()
class Image(models.Model):
thumb = models.ImageField(storage=custom_store, upload_to=''/some/path'')
Puede usar el marco REST de Django y la biblioteca de Requests Python para guardar la imagen mediante programación en Django ImageField
Aquí hay un ejemplo:
import requests
def upload_image():
# PATH TO DJANGO REST API
url = "http://127.0.0.1:8080/api/gallery/"
# MODEL FIELDS DATA
data = {''first_name'': "Rajiv", ''last_name'': "Sharma"}
# UPLOAD FILES THROUGH REST API
photo = open(''/path/to/photo''), ''rb'')
resume = open(''/path/to/resume''), ''rb'')
files = {''photo'': photo, ''resume'': resume}
request = requests.post(url, data=data, files=files)
print(request.status_code, request.reason)
Puedes probar:
model.ImageField.path = os.path.join(''/Upload'', generated_image_path)
Súper fácil si el modelo aún no se ha creado:
Primero , copie su archivo de imagen a la ruta de carga (asumida = ''ruta /'' en el siguiente fragmento).
En segundo lugar , use algo como:
class Layout(models.Model):
image = models.ImageField(''img'', upload_to=''path/'')
layout = Layout()
layout.image = "path/image.png"
layout.save()
probado y trabajando en django 1.4, podría funcionar también para un modelo existente.
Si solo quiere "configurar" el nombre de archivo real, sin incurrir en los gastos generales de cargar y volver a guardar el archivo (!!), o recurrir al uso de un charfield (!!!), es posible que desee probar algo como esto: -
model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, ''my-filename.jpg'')
Esto iluminará su model_instance.myfile.url y todos los demás como si realmente hubiera subido el archivo.
Como dice @ t-stone, lo que realmente queremos es poder establecer instance.myfile.path = ''my-filename.jpg'', pero actualmente Django no lo admite.
Solo un pequeño comentario. La respuesta de tvon funciona pero, si está trabajando en Windows, probablemente quiera open()
el archivo con ''rb''
. Me gusta esto:
class CachedImage(models.Model):
url = models.CharField(max_length=255, unique=True)
photo = models.ImageField(upload_to=photo_path, blank=True)
def cache(self):
"""Store image locally if we have a URL"""
if self.url and not self.photo:
result = urllib.urlretrieve(self.url)
self.photo.save(
os.path.basename(self.url),
File(open(result[0], ''rb''))
)
self.save()
o obtendrá su archivo truncado en el primer byte 0x1A
.
Tengo un código que extrae una imagen de la web y la almacena en un modelo. Los bits importantes son:
from django.core.files import File # you need this somewhere
import urllib
# The following actually resides in a method of my model
result = urllib.urlretrieve(image_url) # image_url is a URL to an image
# self.photo is the ImageField
self.photo.save(
os.path.basename(self.url),
File(open(result[0]))
)
self.save()
Eso es un poco confuso porque está sacado de mi modelo y un poco fuera de contexto, pero las partes importantes son:
- La imagen extraída de la web no se almacena en la carpeta upload_to, sino que se almacena como un archivo temporal mediante urllib.urlretrieve () y luego se descarta.
- El método ImageField.save () toma un nombre de archivo (el bit os.path.basename) y un objeto django.core.files.File.
Avíseme si tiene preguntas o necesita una aclaración.
Editar: en aras de la claridad, aquí está el modelo (menos las declaraciones de importación requeridas):
class CachedImage(models.Model):
url = models.CharField(max_length=255, unique=True)
photo = models.ImageField(upload_to=photo_path, blank=True)
def cache(self):
"""Store image locally if we have a URL"""
if self.url and not self.photo:
result = urllib.urlretrieve(self.url)
self.photo.save(
os.path.basename(self.url),
File(open(result[0]))
)
self.save()
class Pin(models.Model):
"""Pin Class"""
image_link = models.CharField(max_length=255, null=True, blank=True)
image = models.ImageField(upload_to=''images/'', blank=True)
title = models.CharField(max_length=255, null=True, blank=True)
source_name = models.CharField(max_length=255, null=True, blank=True)
source_link = models.CharField(max_length=255, null=True, blank=True)
description = models.TextField(null=True, blank=True)
tags = models.ForeignKey(Tag, blank=True, null=True)
def __unicode__(self):
"""Unicode class."""
return unicode(self.image_link)
def save(self, *args, **kwargs):
"""Store image locally if we have a URL"""
if self.image_link and not self.image:
result = urllib.urlretrieve(self.image_link)
self.image.save(os.path.basename(self.image_link), File(open(result[0], ''r'')))
self.save()
super(Pin, self).save()
class tweet_photos(models.Model):
upload_path=''absolute path''
image=models.ImageField(upload_to=upload_path)
image_url = models.URLField(null=True, blank=True)
def save(self, *args, **kwargs):
if self.image_url:
import urllib, os
from urlparse import urlparse
file_save_dir = self.upload_path
filename = urlparse(self.image_url).path.split(''/'')[-1]
urllib.urlretrieve(self.image_url, os.path.join(file_save_dir, filename))
self.image = os.path.join(file_save_dir, filename)
self.image_url = ''''
super(tweet_photos, self).save()