Django: Upload Files and Save to Disk

7.8k views Asked by At

I'm trying to upload some files through a form on my project and have the files save to disk. Currently, I am able to get the data to insert into the DB (postgreSQL), but the data is not being written to disk. I've done some looking around, and using a modelform and calling save should take care of everything (but apparently I missed something?). Any help is appreciated.

Here's my code: views.py (for uploading files related to a job)

# Upload files to a Job (Developer)
@login_required()
@user_passes_test(lambda u: u.groups.filter(name='Developer').exists(), login_url='/login/', redirect_field_name='not allowed')
@require_http_methods(['POST'])
def job_file_upload(request, jobid):

    # Get the Job
    job = Jobs.objects.get(id=jobid)
    fileform = JobFileSubmitForm(request.POST, request.FILES)
    if fileform.is_valid():
        jfs = fileform.save(commit=False)
        file = request.FILES['file']
        jfs.user_id = request.user.id
        jfs.job_id = jobid
        jfs.file = file.name
        jfs.uploadDate = datetime.now()
        # Save to DB
        jfs.save()

        return redirect('view_job', jobid=jobid, slug=job.slug)

models.py (DB for holding file data and holding saving to the correct path)

from django.core.files.storage import FileSystemStorage

fs = FileSystemStorage(location='/media/')

...


def upload_job_file_path(instance, filename):
    return os.path.join('/uploads/job_meta/files/', instance.id, filename)


# Submit Files for a Job (Developer Role)
class JobFileSubmit(models.Model):
    job = models.ForeignKey(Jobs)
    user = models.ForeignKey(User)
    file = models.FileField(storage=fs, upload_to=upload_job_file_path, blank=False, null=False)
    uploadDate = models.DateTimeField(auto_now=True)

forms.py

class JobFileSubmitForm(forms.ModelForm):

    class Meta:
        model = JobFileSubmit
        fields = 'file',

    def save(self, commit=True):
        jobfilesubmit = super(JobFileSubmitForm, self).save(commit=False)

        if commit:
            jobfilesubmit.save()
        return jobfilesubmit

view.html

                            <form method="post" action="/job/job_file_upload/j{{ job.id }}/" class="form-inline btn-group" enctype="multipart/form-data">
                                {% csrf_token %}
                                <div class="span6 inline">
                                    <label class="control-label">Attach Files: </label>{{ job_file_submit.file }}
                                    <p class="help-block">Attach files that go with this Job.</p>
                                </div>
                                <div class="modal-footer">
                                    <button type="submit" class="btn btn-success btn-med pull-left"><i class="fa fa-check-circle"></i> Attach Files</button>
                                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                                </div>
                            </form>

TL;DR: Currently the form submits, inserts into the DB, but the data is not written to the disk and to the dynamic path it should. For instance, the data is not being written to:

/media/uploads/job_meta/files/{{job.id}}/{{file.name}}

Thanks for taking the time to read this! Any help is much appreciated!

1

There are 1 answers

1
kanu On BEST ANSWER

I am not sure if this is the final answer but its easier to write codeblock here

The upload_job_file_path needs to return a relative path from the MEDIA_ROOT. If I understand it right, the id is the job_id of the instance not its id. This way the following function should work. (It might be that FileField has to be below the job field in the code)

models.py

def upload_job_file_path(instance, filename):
    return 'uploads/job_meta/files/%s/%s' % (instance.job_id, filename)


class JobFileSubmit(models.Model):
    job = models.ForeignKey(Jobs)
    user = models.ForeignKey(User)
    file = models.FileField(upload_to=upload_job_file_path, blank=False, null=False)
    uploadDate = models.DateTimeField(auto_now=True)

I am not too familiar with modeforms but i think the save method should handle the fileupload too. So this might be enough

views.py

if fileform.is_valid():
    jfs = fileform.save(commit=True)