wake-up-neo.com

Programmgesteuertes Speichern von Bildern in Django ImageField

Ok, ich habe fast alles ausprobiert und kann das nicht zum Laufen bringen.

  • Ich habe ein Django-Modell mit einem ImageField darauf
  • Ich habe Code, der ein Bild über HTTP herunterlädt (getestet und funktioniert)
  • Das Bild wird direkt im Ordner 'upload_to' gespeichert (der Upload_to ist derjenige, der im ImageField festgelegt ist).
  • Ich muss nur den bereits vorhandenen Image-Dateipfad mit ImageField verknüpfen

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()
176
T. Stone

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:

  • Das aus dem Web abgerufene Bild wird nicht im Ordner upload_to gespeichert. Es wird stattdessen als temporäre Datei von urllib.urlretrieve () gespeichert und später verworfen.
  • Die ImageField.save () - Methode benötigt einen Dateinamen (das os.path.basename-Bit) und ein Django.core.files.File-Objekt.

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()
151
tvon

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.

80
Rabih Kodeih

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. 

38
Tiago Almeida

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

14
michalk

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.

10
rmnff

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')
10
Nicu Surdu

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.

7
s29

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)
6
Ivan Semochkin

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.

2
Mohamed
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()
1
sawan gupta

Du kannst es versuchen:

model.ImageField.path = os.path.join('/Upload', generated_image_path)
1
panda
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()
1
Nishant

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) 
0
Rajiv Sharma

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)
0
Nids Barthwal