Avatar of Errang Genevre
Errang Genevre
 asked on

File upload error in Django

Hello,

I'm trying to figure out why I'm having problems with file upload in Django... I made sure to create the directory and also made sure it has the appropriate permissions. This is working on my local machine; but failing with "Bad Request (400)" when I'm running it on OpenShift. I did get it working once, but it stopped working after that and I can't figure it out; I would greatly appreciate a second set of eyes.

The File module code:
from django.db import models
from django.dispatch import receiver
from BAGCA.settings import MEDIA_ROOT_FILES

class Files(models.Model):
    class Meta:
        verbose_name_plural = "Files"

    def __str__(self):
        return u'%s' % self.filename

    filename = models.CharField(max_length=100)
    file = models.FileField(upload_to=MEDIA_ROOT_FILES)


# These two auto-delete files from filesystem when they are unneeded:
@receiver(models.signals.post_delete, sender=Files)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    """Deletes file from filesystem
    when corresponding `Files` object is deleted.
    """
    if instance.file:
        if os.path.isfile(instance.file.path):
            os.remove(instance.file.path)


@receiver(models.signals.pre_save, sender=Files)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """Deletes file from filesystem
    when corresponding `Files` object is changed.
    """
    if not instance.pk:
        return False

    try:
        old_file = Files.objects.get(pk=instance.pk).file

        if not old_file:
            return False
    except Files.DoesNotExist:
        return False

    new_file = instance.file
    if not old_file == new_file:
        if os.path.isfile(old_file.path):
            os.remove(old_file.path)

Open in new window


Variables in the settings file:
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'media')
MEDIA_ROOT_FILES = os.path.join(os.environ['OPENSHIFT_DATA_DIR'], 'USER_UPLOADED_FILES')
MEDIA_URL = '/media/'

Open in new window


Value of $OPENSHIFT_DATA_DIR:
echo $OPENSHIFT_DATA_DIR
/var/lib/openshift/5521fe5afcf9334c7600019a/app-root/data/

Output of the makemigrations command:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Files',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('filename', models.CharField(max_length=200)),
                ('file', models.FileField(upload_to=b'/var/lib/openshift/5521fe5afcf9334c7600019a/app-root/data/')),
            ],
            options={
            },
            bases=(models.Model,),
        ),
    ]

Open in new window


I've been working at this for a while, and I can't figure out why this isn't working... I would greatly appreciate any information in resolving this error.
PythonWeb FrameworksWeb DevelopmentWeb Languages and StandardsAJAX

Avatar of undefined
Last Comment
Errang Genevre

8/22/2022 - Mon
SOLUTION
gelonida

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Errang Genevre

ASKER
Even with DEBUG = True in settings.py; I just get the "bad request" error. Looking into why that is.

And my files are a few kb; nothing gigantic
Errang Genevre

ASKER
Hm... I think I've been following an outdated tutorial.

It told me to start a "Python" cartridge on OpenShift; and run Django through there.

But, OpenShift now has a "Django" cartridge; includes a nice demo; started a "file_upload" module there and I'm able to upload files.

Doesn't actually solve the problem; but this is a better alternative.

I am still curious why the file upload didn't work in a Python environment...
Errang Genevre

ASKER
This is ridiculous... when I integrate the "File Upload" module with the rest of the application; it stops working...

I'm using the same file path, and everything...

This method works:

def create_quiz_form(request):
    if request.method == 'POST':
        form = UploadQuizData(request.POST, request.FILES)
        if form.is_valid():

            filename = "temporary_file.txt"
            fd = open('%s/%s' % (MEDIA_ROOT_FILES, filename), 'wb')

            group = request.POST['group_choices']
            quiz_name = request.POST['quiz_name']
            trainer = request.POST['trainer']
            quiz_description = request.POST['quiz_description']
            course_code = request.POST['course_code']
            due_date = request.POST['due_date']
            duration_hours = request.POST['duration_hours']
            required_score = request.POST['required_score']

            determine_if_quiz_exists = Quiz.objects.filter(quiz_name=quiz_name)

            if not determine_if_quiz_exists:
                create_quiz = Quiz(quiz_name=quiz_name,
                                   quiz_description=quiz_description,
                                   trainer=trainer,
                                   course_code=course_code,
                                   due_date=due_date,
                                   duration_hours=duration_hours,
                                   required_score=required_score)
                create_quiz.save()
                create_quiz.groups.add(group)
                quiz_id = Quiz.objects.get(quiz_name=quiz_name)

                for line in request.FILES['file'].read():
                    fd.write(line)

                fd.close()

                written_file = open(MEDIA_ROOT_FILES + '/temporary_file.txt', 'r')

                for line in written_file:
                    parts = re.split(r'\t', line)

                    create_question = Question(quiz=quiz_id, question_text=parts[0])
                    create_question.save()
                    for part_counter in range(1, len(parts)):
                        is_answer = False
                        parts[part_counter] = parts[part_counter].strip()
                        if parts[part_counter][0] == '(' and \
                                        parts[part_counter][len(parts[part_counter]) - 1] == ')':
                            parts[part_counter] = parts[part_counter][1:len(parts[part_counter]) - 1]
                            is_answer = True

                        create_choice = Choice(question=Question.objects.get(pk=create_question.id),
                                               choice_text=parts[part_counter].strip(), answer=is_answer)
                        create_choice.save()

                fd.close()
                os.remove(MEDIA_ROOT_FILES + '/temporary_file.txt')
                form = UploadQuizData()
                data = {'form': form}
                return render(request, 'create_quiz_form.html', data)

    else:
        form = UploadQuizData()

    data = {'form': form}
    return render(request, 'create_quiz_form.html', data)

Open in new window


This method:
- Reads in a file from a file input form
- Writes the file to a directory on the system
- Reads the file back in and inserts data into a database
- Deletes the file

Its a little crazy that my method works; but Django's built in functionality fails...

I know better than to place the blame on Django; but I can't figure out what's going on.
Your help has saved me hundreds of hours of internet surfing.
fblack61
ASKER CERTIFIED SOLUTION
Errang Genevre

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
gelonida

Glad you found it.
It is still strange, that you found nowhere trace logfiles etc. to indicate this.


True in my personal projects all my data was below MEDIA_ROOT, that's why I never enncountered this issue
Errang Genevre

ASKER
Yea, there was a python.log file; but all it had was an entry that a 400 response has been sent.

And yea, I didn't want to put it under MEDIA_ROOT because it was under version control and didn't want the files to be overwritten.
gelonida

ah I see.
In my projects mediaroot was always empty.
What you could do (not sure it makes sense for ypour project)
have your version controlled files in one directory and either copy (or symlink) them during server installation.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Errang Genevre

ASKER
These are user upload files; and they would also have to be able to delete it.

I would have to potentially save 100s of files, and restore them; and also integrate Django's file storage with git.
Errang Genevre

ASKER
I didn't receive a response from anyone else.