1
votes

I'm trying to make a form, with the ModelForm class, for people to be recruited by a small company. So I need photo of their identity card (face and back) and their life card. The problem is that when I send the form, after selecting the photos from my computer, it does not register in the database (not even the path), and they do not a copy to the desired media folder. By cons, if I do it from the admin, it works, I can even open the image in my browser. However, they still do not upload to the media folder.

models.py :


from django.db import models
from django.contrib.auth.models import User


class UserExtention (models.Model):
    user = models.OneToOneField(User, on_delete = models.CASCADE, null=True, verbose_name='utilisateur')
    phone_number = models.CharField (max_length = 10, null = True, blank=True, verbose_name='numéro de téléphone')
    postal_code = models.IntegerField (null = True, blank=True, verbose_name='code postal')
    town = models.CharField (max_length=50, null=True, blank=True, verbose_name='ville')
    address = models.CharField (max_length=500, null=True, blank=True, verbose_name='adresse')
    id_card_recto = models.ImageField (upload_to = 'pictures/id_card_recto', null=True, blank=True, verbose_name="photo du recto de la carte d'identité") 
    id_card_verso = models.ImageField (upload_to = 'pictures/id_card_verso', null=True, blank=True, verbose_name="photo du verso de la carte d'identité")
    vital_card = models.ImageField (upload_to = 'pictures/vital_card', null=True, blank=True, verbose_name="photo de la carte vitale")
    hours_number = models.IntegerField (null=True, blank=True, verbose_name="nombre d'heure effectuée par le salarié")


    def __str__(self):
        return "Profil de {}".format(self.user.username)

forms.py :


from django import forms
from .models import UserExtention
from django.contrib.auth.models import User

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = (
            'password',
            'username',
            'first_name',
            'last_name',
            'email',
            )

class UserExtentionForm(forms.ModelForm):
    class Meta:
        model = UserExtention
        exclude = ('user', 'hours_number')


views.py :


from django.shortcuts import render
from .forms import UserForm, UserExtentionForm

def registration (request):
    form = UserForm(request.POST or None, request.FILES)
    form2 = UserExtentionForm(request.POST or None)
    envoi = False
    if form.is_valid() and form2.is_valid():
        user = form.save()
        user_extention = form2.save(commit = False)
        user_extention.user = user
        user_extention.save()
        envoi = True

    return render (request, 'registration/registration.html', locals())

The template :


<h1>Ceci est la page principale de l'application nommée "Registration"</h1>
{% if not envoi %}
<form action="{% url "registration" %}" enctype="multipart/form-data" method="post">
    {% csrf_token %}
    {{ form.as_p}}
    {{ form2.as_p}}
    <input type="submit" value="submit">    
</form>
{% else %}
<p>Votre inscription a bien été prise en compte, vous pouvez à présent vous connecter dans l'onglet <a href="#">connexion</a></p>
{% endif %}

STATIC_URL = '/static/'

STATICFILES_DIRS = ( os.path.join(BASE_DIR, "static"), )

MEDIA_ROOT = '/media/'

MEDIA_URL = '/media/'

Thanks for answer !

1
You should pass the request.FILES to the UserExtentionForm, not the UserForm, since that form contains image form fields. - Willem Van Onsem
Thanks very much for your answer. It works! It's a beginner mistake! Thanks really. - Robin Joseph

1 Answers

0
votes

The form where you have media form fields is the UserExtentionForm, but in your code, you pass request.FILES only to the UserForm, that has no such media fields.

def registration (request):
    if request.method == 'POST':
        form = UserForm(request.POST, request.FILES)
        form2 = UserExtentionForm(request.POST, request.FILES)
        if form.is_valid() and form2.is_valid():
            user = form.save()
            user_extention = form2.save(commit = False)
            user_extention.user = user
            user_extention.save()
            return redirect('some-view-name')
    else:
        form = UserForm()
        form2 = UserExtentionForm()
    return render (
        request,
        'registration/registration.html',
        {'form': form, 'form2': form2}
    )

Your view however contains some serious anti-patterns that are now (partially) migitated by the proposed solution:

  1. you should not use request.POST or None, since a valid POST request can be empty, but it is still a POST request;
  2. in case the POST request is successful, you should make a redirect, to implement the Post/Redirect/Get pattern [wiki]; and
  3. please do not use locals(), since it will pass all variables to the template, even uninteded ones. Furthermore since it is not clear what you pass to the template, later you might be tempted to remove some variables from your view for optimization, and the IDE will not raise a warning/error that these variables are still necessary in the template.

If you want to add a message that the submission was successful, I advise you to use Django's messaging framework [Django-doc], and not pass a variable through the context. This framework is designed to post messages, regardless of the template itself, and prevent showing the same message multiple times.