Search code examples
djangoformsfileattachment

Save Django attachments from a form


Good morning, I would greatly appreciate your help, I am starting to use Django and I am making a web application that allows workers in a job to attach their documentation (files) through a form. The problem is that at the moment of pressing the submit of the form with the attached files, these are not saved, however, the name and other fields of the Charfield type are saved correctly. The only way to save the files is to attach them from the admin portal, but the idea is that each user enters from a url generated with their id that will be sent by email. Also, the files should be saved with the naming (DSR_”rut”-”name”-”filename (form label)”-0-”extension), but I still can't configure the naming of the file name instance. file, according to the label of the form.

models.py:

class Candidato(models.Model):
   nombre = models.CharField(max_length = 70, null=True, blank=True)
   rut = models.CharField(max_length = 10, primary_key=True)
   correo = models.EmailField(null=True, blank=True)
   centro_de_costo =models.CharField(null=True, blank=True, max_length =30, choices = cc)
   estado = models.IntegerField(null=True, blank=True)
   imagen = models.ImageField(upload_to=upload_directory_name, null=True, blank=True)
   certificado_antecedentes = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   hoja_de_vida_conductor = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   certificado_residencia = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   certificado_afiliacion_afp = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   certificado_afiliacion_salud = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   fotocopia_cedula_identidad = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   fotocopia_licencia_conducir = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   curriculum_vitae = models.FileField(upload_to=upload_directory_name, null=True, blank=True)
   ultimo_finiquito = models.FileField(upload_to=upload_directory_name, null=True, blank=True)`

   class Meta:
       verbose_name="candidato"
       verbose_name_plural="candidatos"

   def __str__(self):
       return self.nombre +" "+ self.rut

The file should be uploaded to upload_directory_name, but as I mentioned in the beginning, I'm     still missing the instance for the file name, based on the Label:

def upload_directory_name(instance, filename):
   ext = filename.split('.')[-1]
   filename = "DSR_%s_%s_0.%s" % (instance.rut, instance.nombre , ext)
   return os.path.join('uploads',filename)

views.py

class CandidatoList(ListView):
   model = Candidato
   template_name = 'candidato/candidato_list.html'
   paginate_by = 2

class CandidatoCreate(CreateView):
   model = Candidato
   form_class = Candidato_form
   template_name = 'candidato/candidato_form.html'
   success_url = 'https://www.google.cl/'

class CandidatoUpdate(UpdateView):
   model = Candidato    
   form_class = Candidato_form
   template_name = 'candidato/candidato_form.html'
   success_url = 'https://www.google.cl/'

forms.py:

class Candidato_form(forms.ModelForm):

class Meta:
    model = Candidato

    fields = [
        'nombre',
        'rut',
        'certificado_antecedentes',
        'hoja_de_vida_conductor',
        'certificado_residencia',
        'certificado_afiliacion_afp',
        'certificado_afiliacion_salud',
        'fotocopia_cedula_identidad',
        'fotocopia_licencia_conducir',
        'curriculum_vitae',
        'ultimo_finiquito',
    ]

    labels = {
        'nombre': 'Nombre',
        'rut': 'Rut',
        'certificado_antecedentes': 'Certificado Antecedentes',
        'hoja_de_vida_conductor': 'Hoja de vida del conductor',
        'certificado_residencia': 'Certificado de residencia',
        'certificado_afiliacion_afp': 'Certificado afiliación AFP',
        'certificado_afiliacion_salud': 'Certificado afiliacion de salud',
        'fotocopia_cedula_identidad': 'Fotocopia de cedula de identidad',
        'fotocopia_licencia_conducir': 'Fotocopia de licencia de conducir',
        'curriculum_vitae': 'Curriculum vitae',
        'ultimo_finiquito': 'Ultimo finiquito',
        
    }

    widgets = {
        'nombre': forms.TextInput(attrs={'class':'form-control'}),
        'rut': forms.TextInput(attrs={'class':'form-control'}),
        'certificado_antecedentes': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'hoja_de_vida_conductor': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'certificado_residencia': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'certificado_afiliacion_afp': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'certificado_afiliacion_salud': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'fotocopia_cedula_identidad': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'fotocopia_licencia_conducir': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'curriculum_vitae': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        'ultimo_finiquito': forms.ClearableFileInput(attrs={"multiple":True, 'class':'form-control'}),
        
    }

    def clean_name(self):
        name = self.cleaned_data['nombre']
        if len(name) < 2:
            raise forms.ValidationError("Name must be at least 2 characters long.")
        return name

    def clean_id(self):
        id = self.cleaned_data['rut']
        if len(id) < 2:
            raise forms.ValidationError("ID must be at least 2 characters long.")
        return id

urls.py:

from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from candidato.views import CandidatoUpdate, CandidatoList, CandidatoCreate

urlpatterns = [
  
path("candidato_list/", CandidatoList.as_view(), name="candidato_list"),
path("candidato_create/", CandidatoCreate.as_view(), name="candidato_create"),
path("candidato_edit/<str:pk>/",CandidatoUpdate.as_view(), name="candidato_edit"),
 

]
if settings.DEBUG:
    urlpatterns+=static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

The main part of the block content of the form template:

<form method="post">
   {% csrf_token %}
   {{form.as_p}}
   <button type="submit">Guardar</button>
   <button type="reset" onclick="return confirmarReset()">Reiniciar</button>

</form>

Thanks you so much.


Solution

  • HTML form post doesn't submit file by default. Change the enctype in HTML file to multipart/form-data

       <form method="POST" enctype="multipart/form-data">
    

    more details: [https://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean][1]