web-dev-qa-db-fra.com

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

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

Mais je ne comprends pas comment utiliser ImageField dans Django.

Paramètres.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 dans une vue comme

        if form.is_valid():
                url = form.cleaned_data['url']
                spider(url)
22
Mayank Jain

Documentation Django est toujours un bon point de départ

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

MIS À JOUR

Donc, ce script fonctionne.

  • Boucle sur les images à télécharger
  • Télécharger l'image
  • Enregistrer dans un 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 ceci à urllib2
  2. tempfile - Sauvegarde le fichier temporaire et non sur le disque
  3. Django filefield enregistrer
36
rockingskier

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

Cela 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 à 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 ImageField.

Voir la documentation de io pour plus d’informations.

17
Michael Bates

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

Donc, il y aura une demande 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 demande sur le fichier depuis le champ (dans notre cas, un ImageField), vous utiliseriez:

request.FILES['imgfield']

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

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

Pour sauvegarder cela simplement, utilisez simplement la méthode save () conférée à votre objet (car 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 dans settings.py.

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

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

Les URL peuvent être délicates, 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,
        }),
   )

J'espère que ça aide.

1
Mr_Spock

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 ça ..

    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
boltsfrombluesky

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

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
Hairy Chris