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)
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:
- requêtes - "HTTP pour les humains", je préfère cela à urllib2
- tempfile - Enregistrer le fichier temporaire et pas sur le disque
- Django filefield enregistrer
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))
Où 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.
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.
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.
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
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