Link to home
Start Free TrialLog in
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.
SOLUTION
Avatar of gelonida
gelonida
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Errang Genevre
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
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...
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.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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.
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.
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.
I didn't receive a response from anyone else.