Tidbits | Dec. 3, 2014

Loading Django FileField and ImageFields from the file system

by Frank Wiles

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:

  1. Retrieve the file (if remote) and store it locally
  2. Open that file as a normal Python file object
  3. Covert that open file to a Django File
  4. 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:

  1. The relative path and filename for inside MEDIA_ROOT
  2. The open file using Django’s File object
  3. 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!

How to load files into Django models, not via a file upload, but from a script or Python shell.

2014-12-03T15:44:12 2018-04-18T16:26:13.260595 2014 programming,django