Django: छवि url से एक ImageField में छवि जोड़ें


85

कृपया मेरे बदसूरत अंग्रेजी के लिए क्षमा करें;;

इस बहुत ही सरल मॉडल की कल्पना करें:

class Photo(models.Model):
    image = models.ImageField('Label', upload_to='path/')

मैं एक छवि URL (अर्थात, django व्यवस्थापक साइट में हाथ से नहीं) से एक फोटो बनाना चाहूंगा।

मुझे लगता है कि मुझे ऐसा कुछ करने की आवश्यकता है:

from myapp.models import Photo
import urllib

img_url = 'http://www.site.com/image.jpg'
img = urllib.urlopen(img_url)
# Here I need to retrieve the image (as the same way that if I put it in an input from admin site)
photo = Photo.objects.create(image=image)

मुझे आशा है कि मैंने समस्या को अच्छी तरह से समझाया है, अगर मुझे नहीं बताया।

धन्यवाद :)

संपादित करें:

यह काम कर सकता है लेकिन मुझे नहीं पता कि contentdjango फ़ाइल में कैसे परिवर्तित किया जाए:

from urlparse import urlparse
import urllib2
from django.core.files import File

photo = Photo()
img_url = 'http://i.ytimg.com/vi/GPpN5YUNDeI/default.jpg'
name = urlparse(img_url).path.split('/')[-1]
content = urllib2.urlopen(img_url).read()

# problem: content must be an instance of File
photo.image.save(name, content, save=True)

जवाबों:


96

मैंने बस इसी समस्या के लिए http://www.djangosnippets.org/snippets/1890/ बनाया है। कोड ऊपर pithyless के उत्तर के समान है, सिवाय इसके कि यह urllib2.urlopen का उपयोग करता है क्योंकि urllib.urlretrieve डिफ़ॉल्ट रूप से किसी भी त्रुटि से निपटने के लिए प्रदर्शन नहीं करता है, इसलिए यह 404/500 पेज की सामग्री को प्राप्त करने के लिए आसान है जो आपको चाहिए। आप कॉलबैक फ़ंक्शन और कस्टम URLOpener सबक्लास बना सकते हैं, लेकिन मैंने इस तरह से अपनी खुद की अस्थायी फ़ाइल बनाना आसान पाया:

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

img_temp = NamedTemporaryFile(delete=True)
img_temp.write(urllib2.urlopen(url).read())
img_temp.flush()

im.file.save(img_filename, File(img_temp))

3
अंतिम पंक्ति क्या कर रही है? क्या imवस्तु आ रही है?
पुजारी

1
@priestc: imथोड़ा सा उदाहरण imथा - उस उदाहरण में, मॉडल उदाहरण fileथा और उस उदाहरण पर एक FileField / ImageField का अकल्पनीय नाम था। वास्तविक API डॉक्स यहां दिए गए हैं कि क्या बात है - वह तकनीक कहीं भी काम करनी चाहिए आपके पास एक Django फ़ाइल ऑब्जेक्ट है जो किसी ऑब्जेक्ट से बंधा हुआ है: docs.djangoproject.com/en/1.5/ref/files/file/…
क्रिस एडम्स

26
एक अस्थायी फ़ाइल अनावश्यक है। requestsइसके बजाय urllib2आप का उपयोग कर सकते हैं: image_content = ContentFile(requests.get(url_image).content)और फिर obj.my_image.save("foo.jpg", image_content)
स्टेन

स्टेन: अनुरोधों को सरल करता है लेकिन IIRC कि एक लाइनर एक समस्या होगी जब तक कि आप त्रुटियों या अधूरी प्रतिक्रियाओं के साथ भ्रम से बचने के लिए पहले up_for_status () कहते हैं
क्रिस एडम्स

यह संभवतः इसे आधुनिक बनाने के लिए एक अच्छा विचार होगा क्योंकि यह मूल रूप से Django 1.1 / 1.2-युग में लिखा गया था। उस ने कहा, मेरा मानना ​​है कि ContentFile में अभी भी यह समस्या है कि यह पूरी फ़ाइल को मेमोरी में लोड कर देगी इसलिए एक अच्छा अनुकूलन iter_content का उपयोग एक उचित चंक आकार के साथ करेगा।
क्रिस एडम्स

32

from myapp.models import Photo
import urllib
from urlparse import urlparse
from django.core.files import File

img_url = 'http://www.site.com/image.jpg'

photo = Photo()    # set any other fields, but don't commit to DB (ie. don't save())
name = urlparse(img_url).path.split('/')[-1]
content = urllib.urlretrieve(img_url)

# See also: http://docs.djangoproject.com/en/dev/ref/files/file/
photo.image.save(name, File(open(content[0])), save=True)


नमस्ते, मेरी मदद करने के लिए धन्यवाद;) समस्या यह है (मैं डॉक्टर को उद्धृत करता हूं): "ध्यान दें कि सामग्री तर्क में फ़ाइल का उदाहरण या फ़ाइल का उप-वर्ग होना चाहिए।" तो क्या आपके पास अपनी सामग्री के साथ फ़ाइल उदाहरण बनाने के लिए कोई समाधान है?

नया संपादन जांचें; यह अब एक काम करने वाला उदाहरण होना चाहिए (हालाँकि मैंने इसका परीक्षण नहीं किया है)
pithyless

मेरे मॉडल के बारे में क्या, जहां मेरे पास अन्य क्षेत्र हैं। जैसे url, etc, आदि अगर id do model.image.save (...)। मैं अन्य क्षेत्रों को कैसे बचा सकता हूं? वे ईडीआईटी को शून्य नहीं कर सकते: यह कुछ इस तरह से हो सकता है? >>> car.photo.save ('myphoto.jpg', सामग्री, सहेजें = गलत) >>> car.save ()
हैरी

self.url ?? ... यहाँ self.url क्या है ??
DeadDjangoDjoker

@DeadDjangoDjoker कोई विचार नहीं है, आपको उस व्यक्ति से पूछना होगा जिसने मेरा उत्तर संपादित किया है। इस बिंदु पर यह उत्तर 5 साल पुराना है; मैं पिछली "कार्य" समाधान के लिए पोस्टीरिटी के लिए वापस आ गया हूं, लेकिन ईमानदारी से आप क्रिस एडम के जवाब के साथ बेहतर हैं।
पीथलेस

13

क्रिस एडम्स और स्टेन ने जो कहा उसे जोड़कर और पायथन 3 पर काम करने के लिए चीजों को अपडेट करना, अगर आप अनुरोध स्थापित करते हैं तो आप कुछ इस तरह कर सकते हैं:

from urllib.parse import urlparse
import requests
from django.core.files.base import ContentFile
from myapp.models import Photo

img_url = 'http://www.example.com/image.jpg'
name = urlparse(img_url).path.split('/')[-1]

photo = Photo() # set any other fields, but don't commit to DB (ie. don't save())

response = requests.get(img_url)
if response.status_code == 200:
    photo.image.save(name, ContentFile(response.content), save=True)

Django के ContentFile प्रलेखन और अनुरोधों के फ़ाइल डाउनलोड उदाहरण में अधिक प्रासंगिक डॉक्स ।


5

ImageField सिर्फ एक स्ट्रिंग है, आपके लिए एक रास्ता है MEDIA_ROOT सेटिंग के । बस फ़ाइल को सहेजें (आप पीआईएल का उपयोग कर सकते हैं यह जांचने के लिए कि यह एक छवि है) और इसके फ़ाइल नाम के साथ फ़ील्ड को पॉप्युलेट करें।

तो यह आपके कोड से अलग है जिसमें आपको urllib.urlopenफ़ाइल (अपने मीडिया स्थान के अंदर) के आउटपुट को सहेजने की जरूरत है , पथ का काम करें, उसे अपने मॉडल पर सहेजें।


5

मैं इसे पायथन 3 पर इस तरह से करता हूं, जिसे पायथन 2 पर सरल अनुकूलन के साथ काम करना चाहिए। यह मेरे ज्ञान पर आधारित है कि मैं जिन फाइलों को प्राप्त कर रहा हूं, वे छोटे हैं। यदि आपका नहीं है, तो मैं शायद स्मृति में बफरिंग के बजाय फ़ाइल पर प्रतिक्रिया लिखने की सलाह दूंगा।

बाइट्सियो की जरूरत है क्योंकि फ़ाइल ऑब्जेक्ट पर Django कॉल () और urlopen प्रतिक्रियाएं मांगने का समर्थन नहीं करती हैं। आप इसके बजाय Django के ContentFile द्वारा पढ़े गए () द्वारा दिए गए बाइट ऑब्जेक्ट को पास कर सकते हैं।

from io import BytesIO
from urllib.request import urlopen

from django.core.files import File


# url, filename, model_instance assumed to be provided
response = urlopen(url)
io = BytesIO(response.read())
model_instance.image_field.save(filename, File(io))

फ़ाइल (io) रिटर्न <फ़ाइल: कोई नहीं>
सुसज एस नायर

@SusajSNair ऐसा इसलिए है क्योंकि फ़ाइल में नाम नहीं है, और नाम लिखने की __repr__विधि है File। यदि आप पसंद करते हैं, तो आप इसे बनाने के बाद ऑब्जेक्ट nameपर विशेषता सेट कर सकते हैं , लेकिन मेरे अनुभव में यह कोई फर्क नहीं पड़ता (इसके अलावा यदि आप इसे प्रिंट करते हैं तो इसे अच्छा बनाने के अलावा)। YMMV। FileFile(io)
14

3

हाल ही में मैं अजगर 3 और Django 3 के भीतर निम्नलिखित दृष्टिकोण का उपयोग करता हूं, हो सकता है कि यह दूसरों के लिए भी दिलचस्प हो। यह क्रिस एडम्स के समाधान के समान है, लेकिन मेरे लिए यह अब काम नहीं करता था।

# -*- coding: utf-8 -*-
import urllib.request
from django.core.files.uploadedfile import SimpleUploadedFile
from urllib.parse import urlparse

from demoapp import models


img_url = 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Stack_Overflow_logo.png'
basename = urlparse(img_url).path.split('/')[-1]
tmpfile, _ = urllib.request.urlretrieve(img_url)

new_image = models.ModelWithImageOrFileField()
new_image.attribute_a = True
new_image.attribute_b = 'False'
new_image.file = SimpleUploadedFile(basename, open(tmpfile, "rb").read())
new_image.save()

यह एकमात्र समाधान है जिसने मेरे लिए काम किया (अजगर 3 + Django 2)। केवल कुछ तुच्छ टिप्पणी है कि URL के आधार पर बेसन का हर मामले में सही विस्तार नहीं हो सकता है।
PhysAIAI

1

बस पता चला है कि आपको एक अस्थायी फ़ाइल नहीं बनानी है:

Django से minio में सीधे url कंटेंट स्ट्रीम करें

मुझे अपनी फ़ाइलों को मिनियो में स्टोर करना होगा और बहुत डिस्क स्थान के बिना डोजो डॉकटर कंटेनर रखना होगा और बड़ी वीडियो फ़ाइलों को डाउनलोड करने की आवश्यकता होगी, इसलिए यह वास्तव में मेरे लिए उपयोगी था।


-5

यह सही और काम करने का तरीका है

class Product(models.Model):
    upload_path = 'media/product'
    image = models.ImageField(upload_to=upload_path, null=True, blank=True)
    image_url = models.URLField(null=True, blank=True)

    def save(self, *args, **kwargs):
        if self.image_url:
            import urllib, os
            from urlparse import urlparse
            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(upload_path, filename)
            self.image_url = ''
            super(Product, self).save()

14
यह सही तरीका नहीं हो सकता है, आप FielField के पूरे फाइल स्टोरेज मेकेनिज्म को दरकिनार करें और स्टोरेज एप को कोई सम्मान न दें।
आंद्रे बोसार्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.