Ok, j'ai essayé à peu près tout et je n'arrive pas à faire fonctionner ça.
J'ai écrit ce code de 6 manières différentes.
Le problème que je rencontre est que tout le code que j'écris a pour résultat le comportement suivant: (1) Django créera un deuxième fichier, (2) renommera le nouveau fichier en ajoutant un _ à la fin. (3) ne transférez aucune des données sur elle en la laissant essentiellement un fichier re-nommé vide. Ce qui reste dans le chemin "upload_to" est constitué de 2 fichiers, un qui est l'image réelle et un qui est le nom de l'image, mais qui est vide et bien sûr, le chemin de ImageField est défini sur le fichier vide que Django essaye de créer. .
Au cas où cela ne serait pas clair, je vais essayer d'illustrer:
## 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
Comment puis-je faire cela sans que Django essaye de re-stocker le fichier? Ce que j'aimerais vraiment, c'est quelque chose à cet effet ...
model.ImageField.path = generated_image_path
... mais bien sûr ça ne marche pas.
Et oui, je suis passé par les autres questions ici comme celle-ci ainsi que le doc Django sur Fichier
UPDATE Après d'autres tests, ce comportement ne se produit que lors de l'exécution sous Apache sur Windows Server. Lorsqu'il est exécuté sous le serveur d'exécution sur XP, il n'exécute pas ce comportement.
Je suis perplexe.
Voici le code qui tourne avec succès sur XP ...
f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()
J'ai un code qui récupère une image sur le Web et la stocke dans un modèle. Les bits importants sont:
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], 'rb'))
)
self.save()
C'est un peu déroutant parce que cela est extrait de mon modèle et un peu hors contexte, mais les parties importantes sont:
Faites-moi savoir si vous avez des questions ou besoin de clarification.
Edit: par souci de clarté, voici le modèle (moins les instructions d’importation requises):
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()
Super facile si le modèle n'a pas encore été créé:
Tout d’abord , copiez votre fichier image sur le chemin de téléchargement (supposé = 'chemin /' dans l’extrait suivant).
Deuxièmement , utilisez quelque chose comme:
class Layout(models.Model):
image = models.ImageField('img', upload_to='path/')
layout = Layout()
layout.image = "path/image.png"
layout.save()
testé et fonctionnant dans Django 1.4, il pourrait également fonctionner pour un modèle existant.
Juste une petite remarque. tvon answer fonctionne, mais si vous travaillez sur Windows, vous voudrez probablement open()
le fichier avec 'rb'
. Comme ça:
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()
ou votre fichier sera tronqué au premier octet 0x1A
.
Voici une méthode qui fonctionne bien et vous permet de convertir le fichier dans un certain format également (pour éviter l'erreur "ne peut pas écrire en mode P en tant que JPEG"):
import urllib2
from Django.core.files.base import ContentFile
from PIL import Image
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)
où image est le Django ImageField ou votre_instance_modèle.image. Voici un exemple d'utilisation:
p = ProfilePhoto(user=user)
download_image(str(user.id), p.image, image_url)
p.save()
J'espère que cela t'aides
Ok, si tout ce que vous avez à faire est d’associer le chemin de fichier d’image existant à ImageField, cette solution peut être utile:
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))
Eh bien, s’il est sérieux, le fichier image existant ne sera pas associé à ImageField, mais la copie de ce fichier sera créée dans le répertoire upload_to sous la forme 'imgfilename.jpg' et sera associée à ImageField.
Ce que j'ai fait était de créer mon propre stockage qui ne sauvegardera simplement pas le fichier sur le disque:
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
Ensuite, dans mes modèles, pour mon ImageField, j'ai utilisé le nouveau stockage personnalisé:
from custom_storage import CustomStorage
custom_store = CustomStorage()
class Image(models.Model):
thumb = models.ImageField(storage=custom_store, upload_to='/some/path')
Si vous voulez simplement "définir" le nom du fichier réel, sans encourir la surcharge du chargement et de la ré-enregistrement du fichier (!!), ni le recours à un champ de caractères (!!!), vous voudrez peut-être essayer quelque chose comme ceci - -
model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
Cela éclairera votre model_instance.myfile.url et tous les autres comme si vous aviez réellement téléchargé le fichier.
Comme @ t-stone le dit, ce que nous voulons vraiment, c'est pouvoir définir instance.myfile.path = 'mon-nom de fichier.jpg', mais Django ne le supporte pas pour le moment.
La solution la plus simple à mon avis:
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)
Ce n'est peut-être pas la réponse que vous recherchez. mais vous pouvez utiliser charfield pour stocker le chemin du fichier au lieu de ImageFile. De cette manière, vous pouvez associer par programme l’image téléchargée au champ sans recréer le fichier.
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()
Tu peux essayer:
model.ImageField.path = os.path.join('/Upload', generated_image_path)
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()
Vous pouvez utiliser le framework Django REST et python Requests library pour enregistrer par programme une image dans Django ImageField
Voici un exemple:
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)
Travailler! Vous pouvez enregistrer une image à l’aide de FileSystemStorage . Consultez l’exemple ci-dessous
def upload_pic(request):
if request.method == 'POST' and request.FILES['photo']:
photo = request.FILES['photo']
name = request.FILES['photo'].name
fs = FileSystemStorage()
##### you can update file saving location too by adding line below #####
fs.base_location = fs.base_location+'/company_coverphotos'
##################
filename = fs.save(name, photo)
uploaded_file_url = fs.url(filename)+'/company_coverphotos'
Profile.objects.filter(user=request.user).update(photo=photo)