Shift 'n Tab
Shift 'n Tab

Reputation: 9443

It is possible for Django to upload file without FORMS?

I'm currently working with a custom HTML template not using forms on my Django app to upload an image in a specific path.

app structure

src/
    media/
        app/
            img/
    app_name/
        templates/
            app_name/
                app_template.html
        __init__.py
        admin.py
        apps.py
        models.py
        tests.py
        urls.py
        views.py
    proj_name/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    manage.py

settings.py

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

models.py

class Document(models.Model):
    doc_file = models.FileField(upload_to='app/img')

views.py

def app_save(request):
    if request.method == 'POST':
        newdoc = Document(doc_file=request.FILES.get('myfile'))
        newdoc.save()

app_template.html

<form id="myform" method="POST" action="{% url 'my_app:save' %}" 
      enctype="multipart/form-data">

    <input type="file" name="myfile">
    <input type="submit"> 
</form>

#Result After submitting the form I dont have any internal server error and no python traceback. But there was no image uploaded in the app/img path and in my database, I have a blank record inserted because of newdoc.save() query.

It is possible to work with file managing without forms?


#UPDATE

i added this on forms.py

class UploadFileForm(forms.Form):
    file = forms.FileField()

and updated my app_template.html to:

<form id="myform" method="POST" action="{% url 'my_app:save' %}" 
      enctype="multipart/form-data">

    {{ form.file }}
    <input type="submit"> 
</form>

then i would like to include the function of loading the app_template.html in views.py:

def index(request):
    form = UploadFileForm()
    return render(request, 'app_name/app_template.html', { 'form': form })

And also updated the app_save() function to:

 def app_save(request):
    form = UploadFileForm(request.POST, request.FILES)
    if request.method == 'POST':
        if form.is_valid():
            newdoc = Document(doc_file=request.FILES.get('file')) # note 'file' is the name of input file of a form.
            newdoc.save()

The problem now is

There is no error found in the application but there is no media/app/img path create with the uploaded image file. What went wrong? I think I missed something here.

Upvotes: 5

Views: 20989

Answers (3)

Perfect
Perfect

Reputation: 1636

There is ContentFile in django.core.files and it's so handy to use it to save your file as your model field. Suppose that you declared a field as FileField and you may need to create a file and save it attached to the field. Then you can do this as following.

from django.core.files.base import ContentFile
from django.db import models

class YourModel(models.Model):
    content = models.FileField(upload_to="any_path_or_callable")
    ...
    def save_file(self, content: str):
        temp_file = ContentFile(content)
        self.content.save(f'{self.pk}.txt', temp_file)

I hope this would help you.

Thank you

Upvotes: 0

Sergey Gornostaev
Sergey Gornostaev

Reputation: 7787

Your backend code is fine. The problem is with a frontend. You can't submit file input with jQuery.ajax like other fields. Use FormData:

$('#myform').submit(function(event) {
    if(window.FormData !== undefined) {
        event.preventDefault();

        var formData = new FormData(this);
        var xhr = new XMLHttpRequest();
        xhr.open('POST', $(this).attr('action'), true);
        xhr.setRequestHeader('X-REQUESTED-WITH', 'XMLHttpRequest')            
        xhr.onreadystatechange = function() {
            if(xhr.readyState == 4) {
                if(xhr.status == 200) {
                    result = JSON.parse(xhr.responseText);
                    // Code for success upload
                }
                else {
                    // Code for error
                }
            }
        };
        xhr.send(formData);
    }
});

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599550

I don't understand why you don't want to use a modelform; it'll make things a lot easier.

However, if you really do want to do it without one, you'll need to take care of the actual uploading yourself. The documentation has a good example of what you'll need to do; basically you just take the file from request.FILES and save it to the location you want.

Upvotes: 0

Related Questions