I don’t know about you, but I run into a situation every so often where I need to programmatically push a file from the local file system or remotely via a URL into a Django model. Using a Python shell, a one off script, or a Django management command.
This should be easy, but with a typical web app you do it infrequently. Mostly I find we do it when we’re converting someone’s site from something else to Django and need to associate an image with another Content item for example.
If you start Googling around for answers to how to do this you get the default docs for File Uploads, File objects, and Managing Files which are all great. However, they don’t exactly spell out how you’re supposed to do this.
My first inclination is to just assign the model field to a file, but this is missing the relative file path information Django needs.
I took the time to write this post mostly for my own benefit so I don’t have to figure this out yet again in the future, but hopefully you’ll get some use out of it as well.
Steps for loading Django ImageField with a local file
Here is a quick example showing you the moving pieces. The steps you need to perform are:
- Retrieve the file (if remote) and store it locally
- Open that file as a normal Python file object
- Covert that open file to a Django File
- Attach it to your model field
Example Model
Suppose we have a model like this:
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=100)
logo = models.ImageField()
Let’s create an entry for RevSys, pulling the logo in with requests:
import requests
from django.core.files import File
from .models import Company
r = requests.get(“http://media.revsys.com/img/revsys-logo.png”)
with open(“/tmp/revsys-logo.png”, “wb”) as f:
f.write(r.content)
reopen = open(“/tmp/revsys-logo.png”, “rb”)
django_file = File(reopen)
revsys = Company()
revsys.name = “Revolution Systems”
revsys.logo.save(“revsys-logo.png”, django_file, save=True)
The last line here is the important bit. save
is given three arguments here:
- The relative path and filename for inside MEDIA_ROOT
- The open file using Django’s File object
- Whether or not we want to save the revsys
Company
instance after the image is saved.
Now if you’re doing this for a bunch of images, you’ll want to parse your URLs or filenames to build the paths for you. Something like this would be a good starting point, note this is using Python 3:
import os
from urllib.parse import urlparse
# from urlparse import urlparse for Python 2.7
url = “http://media.revsys.com/img/revsys-logo.png”
filename = os.path.basename(urlparse(url).path)
# This returns ‘revsys-logo.png’ from the URL
…
revsys.logo.save(filename, django_file, save=True)
Hope this helps!