Twitch
Twitch

Reputation: 693

Saving files to upload field in Django using a Python script

Building an application to list reports for inspections. The actual inspection report is going to be made available for download. Saving the reports to the database using django-db-file-storage.

Lots of records to process, so writing a script to do everything in bulk. Testing in the manage.py shell throws an error.

from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from inspections.models import InspectionInformation, RestaurantInformation

file = open('/docs/Data/2011/12/12-07-11_1498.pdf', 'r').read()

InspectionInformation(
                insp_rest_permit=RestaurantInformation.objects.get(rest_permit=int('1814')),
                insp_date='2011-12-12',
                insp_score='100',
                insp_inspector='Philip',
                insp_report=default_storage.save('report.pdf', ContentFile(file))
            ).save()

Traceback

Traceback (most recent call last):
  File "<console>", line 6, in <module>
  File "/venv/lib/python2.7/site-packages/django/core/files/storage.py", line 48, in save
    name = self.get_available_name(name)
  File "/venv/lib/python2.7/site-packages/django/core/files/storage.py", line 74, in get_available_name
    while self.exists(name):
  File "/venv/lib/python2.7/site-packages/db_file_storage/storage.py", line 77, in exists
    model_class_path, content_field, filename_field, mimetype_field, filename = name.split('/')
ValueError: need more than 1 value to unpack

Models

from django.db import models


class RestaurantInformation(models.Model):
    rest_permit = models.IntegerField(unique=True, verbose_name='Permit')
    rest_name = models.CharField(max_length=200, verbose_name='Name')
    rest_address = models.CharField(max_length=200, verbose_name='Address')
    rest_city = models.CharField(max_length=100, verbose_name='City')
    rest_zip = models.IntegerField(verbose_name='Zip Code')
    rest_owner = models.CharField(max_length=200, verbose_name='Owner')
    rest_latitude = models.CharField(max_length=40, verbose_name='Latitude')
    rest_longitude = models.CharField(max_length=40, verbose_name='Longitude')

    class Meta:
        ordering = ['rest_name']

    def __unicode__(self):
        return self.rest_name + ', ' + self.rest_address + ', ' + self.rest_city


class InspectionInformation(models.Model):
    insp_rest_permit = models.ForeignKey(RestaurantInformation, null=False, to_field='rest_permit')
    insp_score = models.DecimalField(verbose_name='Score', decimal_places=2, max_digits=5)
    insp_date = models.DateField(verbose_name='Date')
    insp_inspector = models.CharField(max_length=200, verbose_name='Inspector')
    insp_report = models.FileField(upload_to='restaurants.InspectionFile/bytes/filename/mimetype',
                                   blank=True, null=True, verbose_name='Inspection Report')

    class Meta:
        unique_together = ("insp_rest_permit", "insp_score", "insp_date")
        ordering = ['insp_date']


class InspectionFile(models.Model):
    bytes = models.TextField()
    filename = models.CharField(max_length=255)
    mimetype = models.CharField(max_length=50)

Upvotes: 0

Views: 965

Answers (1)

Charlie
Charlie

Reputation: 2271

1.It looks like db_file_storage.storage.save() expects their custom format specified to be used with the model plus the filename e.g. "console.ConsolePicture/bytes/filename/mimetype" + filename.

So for your example instead of

'report.pdf' 

it would be

'restaurants.InspectionFile/bytes/filename/mimetype/report.pdf'

I looked at the documentation and it isn't clear why it's being done this way as this violates DRY by making you enter the same thing twice, but they use the same format throughout the DatabaseFileStorage class.

2.It also looks like there's a bug in the save method (line 60) where

mimetype = content.file.content_type

should be changed to

mimetype = content.content_type

And the file you pass it should be something with a content_type attribute so probably a Django SimpleUploadedFile:

from django.core.files.uploadedfile import SimpleUploadedFile
file_ = SimpleUploadedFile('report.pdf', open('/docs/Data/2011/12/12-07-11_1498.pdf', 'r').read())  

The reason I think this is a bug is that when I tried passing in a mock object that looked like "content.file.content_type" I got a Python core library exception later on.

Upvotes: 1

Related Questions