image: Jeff Couturier

Jeff Couturier
designer / developer

Wagail: Read & parse the contents of an uploaded file

written by Jeff on 2024-09-21

tags: django, wagtail, python

In Wagtail I wanted a clean way to upload a file (like CSV or JSON) to the admin, parse it, and make it available to the front-end. This is handy for small chunks of data that you don't want to have to build a model for, or edit/update field-by-field each time the data changes. Instead, editors can upload their data file to the admin as a simple bulk data import. For my purposes, this was used for map coordinates displaying multiple pins and editors already have an auto-generated CSV file. So the aim was to prevent them from having to manually input new data each time it was updated.

Here's what I came up with:

In your model:

# Add a file upload field to your model. Uses built-in Documents section.
my_file = models.ForeignKey(
  get_document_model(),
  null=True,
  blank=True,
  on_delete=models.SET_NULL,
  related_name='my_file',
  verbose_name='Data File',
  help_text="Select a CSV file or upload one if you haven't already.",
)

# Read and parse that file...
def get_file_contents(self):
  if self.my_file:
    # Open the file and read its contents
    with self.my_file.file.open() as file:
      # Read the content of the file
      csv_content = file.read().decode('utf-8')  # Decode bytes to string
      # Use StringIO to treat the CSV content as a file-like object
      csv_file = io.StringIO(csv_content)
      # Read the CSV data into a dictionary
      reader = csv.DictReader(csv_file)
      # Convert the CSV data into a list of dictionaries
      result = [row for row in reader]
      return result
  return None

Now in your template you can reference {{ page.get_file_contents }} and use it in a for loop, etc.