Django ImageField के लिए प्रोग्रामेटिक रूप से सेविंग इमेज


203

ठीक है, मैं सब कुछ के पास के बारे में कोशिश की है और मैं यह काम करने के लिए नहीं मिल सकता है।

  • मैं इस पर एक ImageField के साथ एक Django मॉडल है
  • मेरे पास एक कोड है जो HTTP के माध्यम से एक छवि डाउनलोड करता है (परीक्षण और काम करता है)
  • छवि को सीधे 'upload_to' फ़ोल्डर में अपलोड किया गया है (upload_to वह है जो ImageField पर सेट है)
  • मुझे केवल छविफ़िल्ड के साथ पहले से मौजूद छवि फ़ाइल पथ के सहयोगी होने की आवश्यकता है

मैंने इस कोड को 6 अलग-अलग तरीकों से लिखा है।

मैं जिस समस्या में चल रहा हूं, वह सभी कोड है जो मैं निम्नलिखित व्यवहार में परिणाम लिख रहा हूं: (1) Django 2 फ़ाइल बनाएगा, (2) नई फ़ाइल का नाम बदलें, फ़ाइल के अंत में _ जोड़कर नाम, तब (3) मूल रूप से खाली नाम वाली फ़ाइल को छोड़ने पर किसी भी डेटा को स्थानांतरित नहीं करता है। 'Upload_to' पथ में जो बचा है, वह 2 फाइलें हैं, एक वह जो वास्तविक छवि है, और एक वह जो छवि का नाम है, लेकिन खाली है, और निश्चित रूप से ImageField पथ खाली फाइल पर सेट है जिसे Django बनाने की कोशिश करता है ।

स्पष्ट नहीं होने की स्थिति में, मैं यह स्पष्ट करने की कोशिश करूंगा:

## 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

Django फ़ाइल को फिर से स्टोर करने की कोशिश किए बिना मैं यह कैसे कर सकता हूं? मैं वास्तव में इस प्रभाव के लिए कुछ करना चाहता हूँ ...

model.ImageField.path = generated_image_path

... लेकिन निश्चित रूप से यह काम नहीं करता है।

और हाँ मैं यहाँ अन्य प्रश्नों के माध्यम से गया हूँ जैसे कि यह एक और साथ ही फ़ाइल पर django doc

अद्यतन आगे के परीक्षण के बाद, यह केवल विंडोज सर्वर पर अपाचे के तहत चलने पर यह व्यवहार करता है। एक्सपी पर 'रनसेवर' के तहत चलने के दौरान यह इस व्यवहार को निष्पादित नहीं करता है।

मैं स्तब्ध हूं।

यहाँ कोड है जो XP पर सफलतापूर्वक चलता है ...

f = open(thumb_path, 'r')
model.thumbnail = File(f)
model.save()

एक और शानदार Django सवाल। मैंने बिना किसी भाग्य के इस समस्या को हल करने के लिए कई प्रयास किए हैं। अपलोड निर्देशिका में बनाई गई फ़ाइलें टूट गई हैं और मूल (कहीं और संग्रहीत) की तुलना में आकार में केवल एक अंश है।
पश्चिमोत्तर अष्टक west

आपका UPDATE काम नहीं करता है
AmiNadimi

जवाबों:


166

मेरे पास कुछ कोड हैं जो वेब से एक छवि प्राप्त करते हैं और इसे एक मॉडल में संग्रहीत करते हैं। महत्वपूर्ण बिट्स हैं:

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

यह थोड़ा भ्रमित करने वाला है क्योंकि यह मेरे मॉडल और संदर्भ से थोड़ा हटकर है, लेकिन महत्वपूर्ण भाग हैं:

  • वेब से खींची गई छवि upload_to फ़ोल्डर में संग्रहीत नहीं है , इसे बजाय urlib.urlretrieve () द्वारा एक अस्थायी के रूप में संग्रहीत किया जाता है और बाद में छोड़ दिया जाता है।
  • ImageField.save () विधि एक फ़ाइल नाम (os.path.basename bit) और एक django.core.files.ile ऑब्जेक्ट लेता है।

यदि आपके पास प्रश्न हैं या स्पष्टीकरण की आवश्यकता है, तो मुझे बताएं।

संपादित करें: स्पष्टता के लिए, यहाँ मॉडल (किसी भी आवश्यक आयात विवरण को घटाया गया है):

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

2
tvon - मैंने इस आशय के लिए कुछ करने की कोशिश की थी, लेकिन शायद मैं इसे एक और जाने दूंगा, वास्तव में, मेरे पास कोड था जो इस के समान दिखता था। (यहां तक ​​कि अगर यह संदर्भ से बाहर है, तो मैं देख सकता हूं कि यह कैसे काम करता है)।
टी। स्टोन

2
मैं सुझाव देता हूं कि url पार्स का उपयोग करने के साथ-साथ छवि से जुड़ी url paramatar gunk से बचने के लिए भी। import urlparseos.path.basename(urlparse.urlparse(self.url).path)। पोस्ट के लिए धन्यवाद, मददगार था।
dennmat

1
मुझे django.core.exception.SuspiciousOperation मिलता है: '/images/10.jpg' तक पहुँच से इनकार किया गया।
14

2
@DataGreed आपको मॉडल में upload_to परिभाषा से आगे स्लैश '/' को निकालना चाहिए। इसे यहां संबोधित किया गया था ।
tsikov

मुझे इस तरह की त्रुटि हो रही है:prohibited to prevent data loss due to unsaved related object 'stream'.
दिपक

95

सुपर आसान अगर मॉडल अभी तक नहीं बनाया गया है:

सबसे पहले , अपनी छवि फ़ाइल को अपलोड पथ (मान लिया गया = 'पथ /' को निम्नलिखित स्निपेट में कॉपी करें )।

दूसरा , जैसे कुछ का उपयोग करें:

class Layout(models.Model):
    image = models.ImageField('img', upload_to='path/')

layout = Layout()
layout.image = "path/image.png"
layout.save()

django 1.4 में परीक्षण और काम करना, यह मौजूदा मॉडल के लिए भी काम कर सकता है।


10
यह सही जवाब है, अधिक वोटों की जरूरत है !!! यह समाधान यहाँ भी मिला ।
एंड्रयू स्विहार्ट

नमस्ते। मेरा एक सवाल है। मैं अमेज़ॅन S3 बैकएंड के साथ django-storages का उपयोग कर रहा हूं। क्या यह एक नया अपलोड ट्रिगर करेगा?
साल्वातोर Iovene

ओपी पूछता है "बिना Django के फ़ाइल को फिर से स्टोर करने की कोशिश करें", और यह उसी का उत्तर है!
फर्नहर

2
Django के पास डिस्क पर डुप्लिकेट फ़ाइलनाम के लिए कुछ मौजूदा तर्क हैं। यह विधि उस तर्क को स्पष्ट करती है क्योंकि उपयोगकर्ता फ़ाइल नाम दोहराव की जाँच करने के लिए छोड़ दिया जाता है।
क्रिस कॉनन

1
@Conlan: फ़ाइल के नाम के लिए एक गाइड संलग्न करें।
रबीह कोदिह

41

बस थोड़ी सी टिप्पणी। tvon जवाब काम करता है लेकिन, अगर आप खिड़कियों पर काम कर रहे हैं, तो आप शायद open()फ़ाइल के साथ चाहते हैं 'rb'। ऐशे ही:

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

या आप अपनी फाइल को पहले 0x1Aबाइट में काट देंगे ।


1
धन्यवाद, मैं इस तरह के निम्न-स्तरीय विवरणों को भूल जाता हूं।
mike_k

fml ... क्या होता है जब उस पैरामीटर को एक लिनक्स मशीन पर पारित किया जाता है?
डेमैक डिस्ट्रॉयर

1
मेरे अपने सवाल का जवाब दिया ... स्पैम के लिए खेद है। इसके लिए कुछ दस्तावेज यहां मिले । "यूनिक्स पर, यह मोड में एक 'बी' को जोड़ने के लिए चोट नहीं करता है, इसलिए आप इसे सभी स्वतंत्र फ़ाइलों के लिए प्लेटफ़ॉर्म-स्वतंत्र रूप से उपयोग कर सकते हैं।"
डीएमएसी डिस्ट्रॉयर

16

यहां एक विधि है जो अच्छी तरह से काम करती है और आपको फ़ाइल को एक निश्चित प्रारूप में बदलने की अनुमति देती है (से बचने के लिए "जेपीईजी के रूप में मोड पी लिख नहीं सकता" त्रुटि):

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)

जहाँ छवि django ImageField या your_model_instance.image है, इसका उपयोग उदाहरण है:

p = ProfilePhoto(user=user)
download_image(str(user.id), p.image, image_url)
p.save()

उम्मीद है की यह मदद करेगा


12

ठीक है, अगर आपको बस इतना करना है कि पहले से मौजूद छवि फ़ाइल पथ को ImageField के साथ जोड़ दें, तो यह समाधान सहायक हो सकता है:

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))

ठीक है, अगर बयाना हो, तो पहले से मौजूद छवि फ़ाइल ImageField के साथ संबद्ध नहीं होगी, लेकिन इस फ़ाइल की प्रतिलिपि upload_to dir में 'imgfilename.jpg' के रूप में बनाई जाएगी और Imageield के साथ संबद्ध होगी।


2
क्या आपने इसे बाइनरी फ़ाइल के रूप में नहीं खोला है?
मारियस जमरो

ठीक @MariuszJamro ने कहा, यह इस तरह होना चाहिए:with open('/path/to/already/existing/file', 'rb') as f:
rahmatns

वस्तु को बचाने के लिए भी मत भूलना:obj.save()
rahmatns

11

मैंने जो किया वह मेरा अपना स्टोरेज बनाना था जो फाइल को डिस्क में सेव नहीं करेगा:

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

फिर, मेरे मॉडल में, मेरी इमेजफिल्ड के लिए, मैंने नए कस्टम स्टोरेज का उपयोग किया है:

from custom_storage import CustomStorage

custom_store = CustomStorage()

class Image(models.Model):
    thumb = models.ImageField(storage=custom_store, upload_to='/some/path')

7

यदि आप वास्तविक फ़ाइल नाम को केवल "सेट" करना चाहते हैं, तो फ़ाइल को लोड करने और फिर से सहेजे बिना ओवरहेड किए बिना (!!), या एक charfield (!!!) का उपयोग करने का सहारा लेते हुए, आप कुछ इस तरह की कोशिश करना चाह सकते हैं - !!! -

model_instance.myfile = model_instance.myfile.field.attr_class(model_instance, model_instance.myfile.field, 'my-filename.jpg')

यह आपके model_instance.myfile.url और बाकी सभी को ठीक वैसे ही रोशन करेगा जैसे कि आपने वास्तव में फ़ाइल अपलोड की है।

जैसे @ टी-स्टोन कहता है, जो हम वास्तव में चाहते हैं, वह inst.myfile.path = 'my-filename.jpg' को सेट करने में सक्षम है, लेकिन Django वर्तमान में इसका समर्थन नहीं करता है।


अगर model_instance उस मॉडल का उदाहरण है जिसमें फ़ाइल शामिल है .. तो दूसरे "उदाहरण" के लिए क्या है ??
एच ३।

7

मेरी राय में सबसे सरल समाधान:

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)

3

इनमें से बहुत से उत्तर पुराने थे, और मैंने कई घंटे हताशा में बिताए (मैं सामान्य रूप से Django और वेब देव के लिए काफी नया हूं)। हालाँकि, मुझे @iambibhas: https://gist.github.com/iambibhas/5051911 द्वारा यह उत्कृष्ट गीत मिला।

import requests

from django.core.files import File
from django.core.files.temp import NamedTemporaryFile


def save_image_from_url(model, url):
    r = requests.get(url)

    img_temp = NamedTemporaryFile(delete=True)
    img_temp.write(r.content)
    img_temp.flush()

    model.image.save("image.jpg", File(img_temp), save=True)

2

यह वह उत्तर नहीं हो सकता है जिसकी आप तलाश कर रहे हैं। लेकिन आप ImageFile के बजाय फ़ाइल के पथ को संग्रहीत करने के लिए charfield का उपयोग कर सकते हैं। इस तरह से आप प्रोग्राम को अपलोड की गई छवि को फ़ाइल को फिर से बनाए बिना फ़ील्ड में जोड़ सकते हैं।


हाँ, मुझे इस पर ध्यान देने का मोह था, और या तो सीधे MySQL को लिख दूं, या बस एक CharField () का उपयोग करूं।
टी। स्टोन

1

तुम कोशिश कर सकते हो:

model.ImageField.path = os.path.join('/Upload', generated_image_path)

1
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
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

काम कर रहे! आप FileSystemStorage का उपयोग करके छवि को बचा सकते हैं। नीचे दिए गए उदाहरण की जाँच करें

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)

शुक्रिया Nids, बिल्कुल इस समाधान काम! आपने मेरा बहुत समय बचाया :)
मेहमत बुरक इबिस

0

आप Django REST फ्रेमवर्क और अजगर अनुरोधों का उपयोग कर सकते हैं लाइब्रेरी का

यहाँ एक उदाहरण है:

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

Django 3 के साथ, इस तरह के एक मॉडल के साथ:

class Item(models.Model):
   name = models.CharField(max_length=255, unique=True)
   photo= models.ImageField(upload_to='image_folder/', blank=True)

यदि छवि पहले ही अपलोड की जा चुकी है, तो हम सीधे कर सकते हैं:

Item.objects.filter(...).update(photo='image_folder/sample_photo.png')

या

my_item = Item.objects.get(id=5)
my_item.photo='image_folder/sample_photo.png'
my_item.save()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.