Téléchargez une image distante et enregistrez la dans un modèle Django

J'écris une application Django qui va récupérer toutes les images d'une URL particulière et les enregistrer dans la base de données.

Mais je ne comprends pas comment utiliser ImageField dans Django.

Settings.py

MEDIA_ROOT = os.path.join(PWD, "../downloads/")

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://example.com/media/", "htp://media.example.com/"
MEDIA_URL = '/downloads/'

Models.py

class images_data(models.Model):
        image_id =models.IntegerField()
        source_id = models.IntegerField()
        image=models.ImageField(upload_to='images',null=True, blank=True)
        text_ind=models.NullBooleanField()
        prob=models.FloatField()

Download_img.py

def spider(site):
        PWD = os.path.dirname(os.path.realpath(__file__ ))
        #site="http://en.wikipedia.org/wiki/Pune"
        hdr= {'User-Agent': 'Mozilla/5.0'}
        outfolder=os.path.join(PWD, "../downloads")
        #outfolder="/home/mayank/Desktop/dreamport/downloads"
        print "MAYANK:"+outfolder
        req = urllib2.Request(site,headers=hdr)
        page = urllib2.urlopen(req)
        soup =bs(page)
        tag_image=soup.findAll("img")
        count=1;
        for image in tag_image:
                print "Image: %(src)s" % image
                filename = image["src"].split("/")[-1]
                outpath = os.path.join(outfolder, filename)
                urlretrieve('http:'+image["src"], outpath)
                im = img(image_id=count,source_id=1,image=outpath,text_ind=None,prob=0)
                im.save()
                count=count+1

J'appelle download_imgs.py à l'intérieur d'une vue comme

        if form.is_valid():
                url = form.cleaned_data['url']
                spider(url)
21
demandé sur Serjik 2013-04-23 19:59:03

6 réponses

La Documentation de Django est toujours un bon point de départ

class ModelWithImage(models.Model):
    image = models.ImageField(
        upload_to='images',
    )

Mise à jour

Donc ce script fonctionne.

  • boucle sur les images à télécharger
  • Télécharger l'image
  • enregistrer dans le fichier temporaire
  • Appliquer au modèle
  • Enregistrer le modèle

.

import requests
import tempfile

from django.core import files

# List of images to download
image_urls = [
    'http://i.thegrindstone.com/wp-content/uploads/2013/01/how-to-get-awesome-back.jpg',
]

for image_url in image_urls:
    # Steam the image from the url
    request = requests.get(image_url, stream=True)

    # Was the request OK?
    if request.status_code != requests.codes.ok:
        # Nope, error handling, skip file etc etc etc
        continue

    # Get the filename from the url, used for saving later
    file_name = image_url.split('/')[-1]

    # Create a temporary file
    lf = tempfile.NamedTemporaryFile()

    # Read the streamed image in sections
    for block in request.iter_content(1024 * 8):

        # If no more file then stop
        if not block:
            break

        # Write image block to temporary file
        lf.write(block)

    # Create the model you want to save the image to
    image = Image()

    # Save the temporary image to the model#
    # This saves the model so be sure that is it valid
    image.image.save(file_name, files.File(lf))

Quelques liens de référence:

  1. requêtes - "HTTP pour les humains", je préfère cela à urllib2
  2. tempfile - Enregistrer le fichier temporaire et pas sur le disque
  3. Django filefield enregistrer
34
répondu rockingskier 2018-01-02 16:43:51

Si vous souhaitez enregistrer les images téléchargées sans les enregistrer sur le disque en premier (sans utiliser NamedTemporaryFile etc), il existe un moyen facile de le faire.

Ce sera légèrement plus rapide que de télécharger le fichier et de l'écrire sur le disque car tout se fait en mémoire. Notez que cet exemple est écrit pour Python 3 - le processus est similaire dans Python 2 mais légèrement différent.

from django.core import files
from io import BytesIO
import requests

url = "https://example.com/image.jpg"
resp = requests.get(url)
if resp.status_code != requests.codes.ok:
    #  Error handling here

fp = BytesIO()
fp.write(resp.content)
file_name = url.split("/")[-1]  # There's probably a better way of doing this but this is just a quick example
your_model.image_field.save(file_name, files.File(fp))

your_model est une instance du modèle que vous souhaitez enregistrer et .image_field est le nom de la ImageField.

Voir la documentation de io pour plus d'info.

14
répondu Michael Bates 2017-10-26 12:24:24

Comme un exemple de ce que je pense que vous demandez:

Dans forms.py:

imgfile = forms.ImageField(label = 'Choose your image', help_text = 'The image should be cool.')

Dans models.py:

imgfile =   models.ImageField(upload_to='images/%m/%d')

Il y aura donc une requête POST de l'utilisateur (lorsque l'utilisateur remplira le formulaire). Cette demande contiendra essentiellement un dictionnaire de données. Le dictionnaire contient les fichiers soumis. Pour concentrer la requête sur le fichier à partir du champ (dans notre cas, un ImageField), vous utiliseriez:

request.FILES['imgfield']

Vous utiliseriez cela lorsque vous construisez le modèle objet (instanciation de votre classe de modèle):

newPic = ImageModel(imgfile = request.FILES['imgfile'])

Pour enregistrer cela de manière simple, vous utiliseriez simplement la méthode save () accordée à votre objet (parce que Django est génial):

if form.is_valid():
    newPic = Pic(imgfile = request.FILES['imgfile'])
    newPic.save()

Votre image sera stockée, par défaut, dans le répertoire que vous indiquez pour MEDIA_ROOT in settings.py.

Accéder à l'image dans le modèle:

<img src="{{ MEDIA_URL }}{{ image.imgfile.name }}"></img>

Les URL peuvent être difficiles, mais voici un exemple de base d'un modèle d'url simple pour appeler les images stockées:

urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT,
        }),
   )

Je espérons que cela aide.

1
répondu Mr_Spock 2013-04-23 18:47:53

Essayez de le faire de cette façon au lieu d'attribuer un chemin à l'image...

    import urllib2
    from django.core.files.temp import NamedTemporaryFile
    def handle_upload_url_file(url):
        img_temp = NamedTemporaryFile()
        opener = urllib2.build_opener()
        opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1')]
        img_temp.write(opener.open(url).read())
        img_temp.flush()
        return img_temp

Utilisez la fonction ci-dessus comme ceci..

    new_image = images_data()
    #rest of the data in new_image and then do this.
    new_image.image.save(slug_filename,File(handle_upload_url_file(url)))
    #here slug_filename is just filename that you want to save the file with.
0
répondu boltsfrombluesky 2013-04-23 19:48:12

Similaire à la réponse de @boltsfrombluesky ci-dessus, vous pouvez le faire en Python 3 sans aucune dépendance externe comme ceci:

from os.path import basename
import urllib.request
from urllib.parse import urlparse
import tempfile

from django.core.files.base import File

def handle_upload_url_file(url, obj):
    img_temp = tempfile.NamedTemporaryFile(delete=True)
    req = urllib.request.Request(
        url, data=None,
        headers={
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
        }
    )
    with urllib.request.urlopen(req) as response:
        img_temp.write(response.read())
    img_temp.flush()
    filename = basename(urlparse(url).path)
    result = obj.image.save(filename, File(img_temp))
    img_temp.close()
    return result
0
répondu Hairy Chris 2017-12-09 04:52:03
def qrcodesave(request): 
    import urllib2;   
    url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0"; 
    opener = urllib2.urlopen(url);  
    mimetype = "application/octet-stream"
    response = HttpResponse(opener.read(), mimetype=mimetype)
    response["Content-Disposition"]= "attachment; filename=aktel.png"
    return response 
-1
répondu Saurabh Chandra Patel 2013-12-16 11:25:32