101👍
I just created http://www.djangosnippets.org/snippets/1890/ for this same problem. The code is similar to pithyless’ answer above except it uses urllib2.urlopen because urllib.urlretrieve doesn’t perform any error handling by default so it’s easy to get the contents of a 404/500 page instead of what you needed. You can create callback function & custom URLOpener subclass but I found it easier just to create my own temp file like this:
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))
34👍
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)
- [Django]-Django: how save bytes object to models.FileField?
- [Django]-How can i test for an empty queryset in Django?
- [Django]-Jquery template tags conflict with Django template!
25👍
Combining what Chris Adams and Stan said and updating things to work on Python 3, if you install Requests you can do something like this:
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)
More relevant docs in Django’s ContentFile documentation and Requests’ file download example.
- [Django]-What is the difference between {% load staticfiles %} and {% load static %}
- [Django]-Django auto_now and auto_now_add
- [Django]-Aggregate() vs annotate() in Django
7👍
ImageField
is just a string, a path relative to your MEDIA_ROOT
setting. Just save the file (you might want to use PIL to check it is an image) and populate the field with its filename.
So it differs from your code in that you need to save the output of your urllib.urlopen
to file (inside your media location), work out the path, save that to your model.
- [Django]-Access web server on VirtualBox/Vagrant machine from host browser?
- [Django]-Django Model() vs Model.objects.create()
- [Django]-Django filter JSONField list of dicts
5👍
I do it this way on Python 3, which should work with simple adaptations on Python 2. This is based on my knowledge that the files I’m retrieving are small. If yours aren’t, I’d probably recommend writing the response out to a file instead of buffering in memory.
BytesIO is needed because Django calls seek() on the file object, and urlopen responses don’t support seeking. You could pass the bytes object returned by read() to Django’s ContentFile instead.
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))
- [Django]-Django – iterate number in for loop of a template
- [Django]-Select distinct values from a table field
- [Django]-Override default queryset in Django admin
5👍
Recently I use the following approach within python 3 and Django 3, maybe this might be interesting for others aswell. It is similar to Chris Adams solution but for me it did not work anymore.
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.title = 'Foo bar'
new_image.file = SimpleUploadedFile(basename, open(tmpfile, "rb").read())
new_image.save()
- [Django]-How to format time in django-rest-framework's serializer?
- [Django]-What's the difference between `from django.conf import settings` and `import settings` in a Django project
- [Django]-Django limit_choices_to for multiple fields with "or" condition
2👍
Just discovered that you don’t have to generate a temporary file:
Stream url content directly from django to minio
I have to store my files in minio and have django docker containers without much disk space and need to download big video files, so this was really helpful to me.
- [Django]-How to get the currently logged in user's id in Django?
- [Django]-Get the latest record with filter in Django
- [Django]-New url format in Django 1.9
1👍
I used this snippet to set image as avatar of Person from URL.
import os
from apps.core.models import Person
from io import BytesIO
from django.core.files import File
from urllib.request import urlopen
url = 'https://picsum.photos/256/256'
for person in Person.objects.all():
response = urlopen(url)
avatar_content = BytesIO(response.read())
filename = os.path.basename(url)
person.avatar.save(filename, File(avatar_content), save=True)
- [Django]-How to access outermost forloop.counter with nested for loops in Django templates?
- [Django]-Class has no objects member
- [Django]-Do I need Nginx with Gunicorn if I am not serving any static content?
0👍
Its been almost 11 years since the question and the most reputed answer has been posted. Thanks To @chris-adams for the response. I am Just reposting the same answer along with the updated packages and support.
#! /usr/bin/python3
# lib/utils.py
import urllib3 # http Request Package.
from typing import Optional
from django.core.files import File # Handle Files in Django
from django.core.files.temp import NamedTemporaryFile # handling temporary files.
def fetch_image(url: str, instance: models.Model, field: str, name: Optional[str]=None):
"""
fetch_image Fetches an image URL and adds it to the model field.
the parameter instance does not need to be a saved instance.
:url: str = A valid image URL.
:instance: django.db.models.Model = Expecting a model with image field or file field.
:field: str = image / file field name as string;
[name:str] = Preferred file name, such as product slug or something.
:return: updated instance as django.db.models.Model, status of updation as bool.
"""
conn = urllib3.PoolManager()
response = conn.request('GET', url)
if response.status <> 200:
print("[X] 404! IMAGE NOT FOUND")
print(f"TraceBack: {url}")
return instance, False
file_obj = NamedTemporaryFile(delete=True)
file_obj.write( response.data )
file_obj.flush()
img_format = url.split('.')[-1]
if name is None:
name = url.split('/')[-1]
if not name.endswith(img_format):
name += f'.{img_format}'
django_file_obj = File(file_obj)
(getattr(instance, field)).save(name, django_file_obj)
return instance, True
Tested with Django==2.2.12 in Python 3.7.5
if __name__ == '__main__':
instance = ProductImage()
url = "https://www.publicdomainpictures.net/pictures/320000/velka/background-image.png"
instance, saved = fetch_image(url, instance, field='banner_image', name='intented-image-slug')
status = ["FAILED! ", "SUCCESS! "][saved]
print(status, instance.banner_image and instance.banner_image.path)
instance.delete()
- [Django]-How to upload a file in Django?
- [Django]-Django TemplateDoesNotExist?
- [Django]-Redirect to named url pattern directly from urls.py in django?
-5👍
this is the right and working way
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()
- [Django]-Django – how to visualize signals and save overrides?
- [Django]-Does django with mongodb make migrations a thing of the past?
- [Django]-Django filter many-to-many with contains