excusez-moi pour mon anglais laid ;-)
Imaginez ce modèle très simple:
class Photo(models.Model):
image = models.ImageField('Label', upload_to='path/')
Je voudrais créer une photo à partir d'une URL d'image (c'est-à-dire pas à la main sur le site d'administration de django).
Je pense que je dois faire quelque chose comme ça:
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)
J'espère avoir bien expliqué le problème, sinon dites-moi.
Merci :)
Éditer :
Cela peut fonctionner mais je ne sais pas comment convertir content
un fichier django:
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)
im
objet?im
était un peu laconique - dans cet exemple,im
était l'instance de modèle etfile
était le nom sans imagination d'un FileField / ImageField sur cette instance. La documentation de l'API réelle ici est ce qui compte - cette technique devrait fonctionner partout où vous avez un objet Django File lié à un objet: docs.djangoproject.com/en/1.5/ref/files/filerequests
au lieu deurllib2
vous pouvez faire:image_content = ContentFile(requests.get(url_image).content)
et puisobj.my_image.save("foo.jpg", image_content)
.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)
la source
En combinant ce que Chris Adams et Stan ont dit et en mettant à jour les choses pour fonctionner sur Python 3, si vous installez Requests, vous pouvez faire quelque chose comme ceci:
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)
Des documents plus pertinents dans la documentation ContentFile de Django et l' exemple de téléchargement de fichiers de requêtes .
la source
ImageField
est juste une chaîne, un chemin relatif à votreMEDIA_ROOT
paramètre. Enregistrez simplement le fichier (vous voudrez peut-être utiliser PIL pour vérifier qu'il s'agit d'une image) et remplissez le champ avec son nom de fichier.Il diffère donc de votre code en ce que vous devez enregistrer la sortie de votre
urllib.urlopen
fichier dans (à l'intérieur de votre emplacement multimédia), déterminer le chemin, l'enregistrer dans votre modèle.la source
Je le fais de cette façon sur Python 3, qui devrait fonctionner avec de simples adaptations sur Python 2. Ceci est basé sur ma connaissance que les fichiers que je récupère sont petits. Si ce n'est pas le cas, je recommanderais probablement d'écrire la réponse dans un fichier au lieu de la mettre en mémoire tampon.
BytesIO est nécessaire car Django appelle seek () sur l'objet fichier et les réponses urlopen ne prennent pas en charge la recherche. Vous pouvez passer l'objet bytes renvoyé par read () au ContentFile de Django à la place.
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))
la source
__repr__
méthode d'File
écriture du nom. Si vous préférez, vous pouvez définir l'name
attribut sur l'File
objet après l'avoir créé avecFile(io)
, mais d'après mon expérience, cela n'a pas d'importance (à part le rendre plus joli si vous l'imprimez). ymmv.Récemment, j'utilise l'approche suivante dans python 3 et Django 3, peut-être que cela pourrait être intéressant pour d'autres également. C'est similaire à la solution Chris Adams mais pour moi cela ne fonctionnait plus.
# -*- 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()
la source
Je viens de découvrir que vous n'avez pas à générer de fichier temporaire:
Diffuser du contenu URL directement de django vers minio
Je dois stocker mes fichiers dans minio et avoir des conteneurs django docker sans beaucoup d'espace disque et j'ai besoin de télécharger de gros fichiers vidéo, donc cela m'a vraiment aidé.
la source
c'est la bonne manière de travailler
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()
la source