Octavian Niculescu
Octavian Niculescu

Reputation: 83

Trying to use file upload without forms.py - 'InMemoryUploadedFile' object is not callable

So I'm trying to make a form with some data and an upload field. Django docs doesn't provide any good tutorial of doing this without forms.py. I don't want to use that.

I tried to adapt their tutorial with forms.py (https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/) with my project but I'm getting an error. "InMemoryUploadedFile' object is not callable" I've tried searching it on google but I didn't find this error.

I obviously miss something, because when I used to do file uploads with Node I had to do more things, like setting file storage ect. I just don't know how to handle this in django. So what am I missing and why do I get this error?

views.py

def incarcarecv(req):
    context = {
        'title': "title"
    }
    if req.method == 'POST':
        nume = req.POST['nume']
        prenume = req.POST['prenume']
        telefon = req.POST['telefon']
        email = req.POST['email']
        CV = req.FILES['CV']
        cvUpload = CV(solicitant = req.user, nume=nume, prenume=prenume, telefon=telefon, emailContact=email, CV=CV)        
    return render(req, "../templates/pagini/incarcare-cv.html", context)

models.py

class CV(models.Model):
    solicitant = models.ForeignKey(User, on_delete=models.CASCADE)
    dataUploadCV = models.DateField(auto_now_add=True)
    nume = models.CharField(max_length=12)
    prenume = models.CharField(max_length=12)
    telefon = models.CharField(max_length=12)
    emailContact = models.EmailField(max_length=40)
    CV = models.FileField(upload_to='documents/%d/%m/%Y')
    rezolvata = models.BooleanField(default=False)
    def __str__(self):
        return self.solicitant

html

{% extends 'base.html' %}
{% load static %}
{% block content %}
            <div class="container container-centru">
                <h1 class="heading-contact">Incarca CV</h1>
                {% include 'partials/_alerts.html' %}
                <form action="{% url 'incarcarecv' %}" method="POST" class="form-contact"  enctype="multipart/form-data">
                    {% csrf_token %}
                        <div class="form-group">
                            <label for="inputnume" class="email-contact">Nume</label>
                            <input type="text" name="nume" class="form-control" id="inputnume" aria-describedby="emailHelp" placeholder="Introdu nume">
                        </div>
                        <div class="form-group">
                                <label for="inputprenume" class="email-contact">Prenume</label>
                                <input type="text" name="prenume" class="form-control" id="inputprenume" aria-describedby="emailHelp" placeholder="Introdu prenume">
                        </div>
                        <div class="form-group">
                            <label for="inputtelefon" class="email-contact">Telefon</label>
                            <input type="text" name="telefon" class="form-control" id="inputtelefon" aria-describedby="emailHelp" placeholder="Introdu telefon">
                        </div>
                        <div class="form-group">
                            <label for="inputemail" class="email-contact">Email</label>
                            <input type="email" name="email" class="form-control" id="inputemail" aria-describedby="emailHelp" placeholder="Introdu email">
                        </div>
                        <div class="form-group">
                                <label for="inputcv" class="email-contact">CV</label>
                                <input type="file" name="CV" class="form-control" id="inputemail" aria-describedby="emailHelp">
                            </div>
                        <div class="form-group form-group-custom">
                                <input type="submit" value="Trimite" class="btn btn-secondary btn-block btn-login-custom">
                                <input type="submit" value="Resetează câmpurile" class="btn btn-secondary btn-block btn-reset-custom">
                        </div>                   
                </form>
            </div>              
{% endblock %}

Let me translate: name = last name, prenume = first name, telefon = phone.

So how can I handle files in this situation and without using forms.py? As I said, django doesn't provide any tutorial on this.

Thanks!

Upvotes: 1

Views: 509

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477200

In your view, you shadow the CV model, by defining a local variable named CV. Indeed, you write:

    CV = req.FILES['CV']

So in this view, CV does not refer to the model CV, but to the file, later you then call the constructor of the model CV(..), but you thus call the file handler instead.

def incarcarecv(req):
    context = {
        'title': 'title'
    }
    if req.method == 'POST':
        nume = req.POST['nume']
        prenume = req.POST['prenume']
        telefon = req.POST['telefon']
        email = req.POST['email']
        cv = req.FILES['CV']
        cv_upload = CV(
            solicitant=req.user,
            nume=nume,
            prenume=prenume,
            telefon=telefon,
            emailContact=email,
        )
        cv_upload.cv.save(cv.name, cv)
        cv_upload.save()
    return render(req, '../templates/pagini/incarcare-cv.html', context)

You will need to cv_upload.save(), since otherwise you construct a CV object, but you did not store in in the database.

That being said, I strongly advise you to use a Form, here it looks like a simple ModelForm will be sufficient. A form also can validate the input, and produce errors that you can send back to the user about what is missing.

By using the PEP-8 naming conventions, it is also less likely that such name clashes will occur.

You also should, in case of a successful POST request, redirect to a page. This is the Post/Redirect/Get web development pattern. Otherwise in case the submission was successful, if you render a page, and the user refreshes the page in the browser, the browser will make the same POST request.

Upvotes: 1

Related Questions