Ok, ich habe fast alles ausprobiert und kann das nicht zum Laufen bringen.
Ich habe diesen Code auf 6 verschiedene Arten geschrieben.
Das Problem, auf das ich laufe, ist der gesamte Code, für den ich Ergebnisse schreibe, in folgendem Verhalten: (1) Django erstellt eine zweite Datei, (2) benennt die neue Datei um und fügt am Ende ein _ hinzu des Dateinamens, dann (3) keine der Daten zu übertragen, da im Wesentlichen eine leere umbenannte Datei verbleibt. Was im Pfad 'upload_to' übrig bleibt, sind 2 Dateien, eine, die das eigentliche Bild ist, und eine, die den Namen des Bildes darstellt, aber leer ist. Natürlich ist der ImageField-Pfad auf die leere Datei gesetzt, die Django zu erstellen versucht .
Falls das nicht klar war, versuche ich zu veranschaulichen:
## 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
Wie kann ich dies tun, ohne dass Django versucht, die Datei erneut zu speichern? Was mir wirklich gefällt, ist etwas zu diesem Effekt ...
model.ImageField.path = generated_image_path
... aber das geht natürlich nicht.
Und ja, ich habe die anderen Fragen hier durchgegangen wie diese sowie den Django-Doc auf File
UPDATE Nach weiteren Tests führt dieses Verhalten nur aus, wenn es unter Apache unter Windows Server ausgeführt wird. Bei Ausführung unter "runserver" unter XP wird dieses Verhalten nicht ausgeführt.
Ich bin überrascht.
Hier ist der Code, der unter XP erfolgreich läuft ...
f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()
Ich habe einen Code, der ein Bild aus dem Web abruft und in einem Modell speichert. Die wichtigen Bits sind:
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()
Das ist etwas verwirrend, weil es aus meinem Modell herausgezogen wurde und etwas aus dem Kontext gerissen ist, aber die wichtigen Teile sind:
Lassen Sie mich wissen, wenn Sie Fragen haben oder eine Klarstellung benötigen.
Bearbeiten: Der Übersichtlichkeit halber ist hier das Modell (abzüglich aller erforderlichen Importanweisungen):
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 einfach, wenn das Modell noch nicht erstellt wurde:
Zuerst , kopiere deine Image-Datei in den Upload-Pfad (angenommen = 'path /' im folgenden Snippet).
Zweitens , etwas wie:
class Layout(models.Model):
image = models.ImageField('img', upload_to='path/')
layout = Layout()
layout.image = "path/image.png"
layout.save()
getestet und funktioniert in Django 1.4, könnte es auch für ein vorhandenes Modell funktionieren.
Nur eine kleine Bemerkung. tvon answer funktioniert, aber wenn Sie unter Windows arbeiten, möchten Sie wahrscheinlich die Datei mit 'rb'
open()
So was:
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()
oder Sie bekommen Ihre Datei im ersten 0x1A
-Byte abgeschnitten.
Hier ist eine Methode, die gut funktioniert und die Konvertierung der Datei in ein bestimmtes Format ermöglicht.
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)
wobei image das Django ImageField oder your_model_instance.image .__ ist. Hier ein Verwendungsbeispiel:
p = ProfilePhoto(user=user)
download_image(str(user.id), p.image, image_url)
p.save()
Hoffe das hilft
Ok, wenn Sie nur den bereits vorhandenen Image-Dateipfad mit ImageField verknüpfen möchten, kann diese Lösung hilfreich sein:
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))
Im Ernst, die bereits vorhandene Image-Datei wird nicht mit ImageField verknüpft, aber die Kopie dieser Datei wird im upload_to-Verzeichnis als 'imgfilename.jpg' erstellt und mit ImageField verknüpft.
Was ich getan habe, war, meinen eigenen Speicher zu erstellen, der die Datei einfach nicht auf der Festplatte speichert:
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
In meinen Modellen habe ich dann für mein ImageField den neuen benutzerdefinierten Speicher verwendet:
from custom_storage import CustomStorage
custom_store = CustomStorage()
class Image(models.Model):
thumb = models.ImageField(storage=custom_store, upload_to='/some/path')
Wenn Sie nur den tatsächlichen Dateinamen "einstellen" möchten, ohne den Aufwand für das Laden und erneutes Speichern der Datei (!!) oder die Verwendung eines Charfield (!!!) aufzuwenden, möchten Sie möglicherweise Folgendes versuchen -
model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')
Dadurch werden Ihre model_instance.myfile.url und alle anderen von ihnen so beleuchtet, als ob Sie die Datei tatsächlich hochgeladen hätten.
Wie @ t-stone sagt, wollen wir wirklich instance.myfile.path = 'my-filename.jpg' setzen, aber Django unterstützt das derzeit nicht.
Einfachste Lösung meiner Meinung nach:
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)
Dies ist möglicherweise nicht die Antwort, die Sie suchen. Sie können charfield jedoch verwenden, um den Pfad der Datei anstelle von ImageFile zu speichern. Auf diese Weise können Sie ein hochgeladenes Bild programmgesteuert einem Feld zuordnen, ohne die Datei neu erstellen zu müssen.
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()
Du kannst es versuchen:
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()
Sie können die Bibliothek Django REST (Framework) und Python Requests verwenden, um das Bild programmatisch in Django ImageField zu speichern
Hier ist ein Beispiel:
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)
Arbeiten! Sie können Bilder speichern, indem Sie FileSystemStorage . Verwenden. Überprüfen Sie das folgende Beispiel
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)