2010-06-22 27 views
18
form = AddItemForm(request.POST, request.FILES) 

if form.is_valid() 

    do_stuff 

return render_to_response(blah.html, {'form':form}) 

Ahora formulario tendrá la información de error junto con los valores originales de los campos, pero no conserva un archivo seleccionado ¿Cómo puedo mantener el archivo seleccionado si el formulario no valida?Como hacer un formulario de Django retener un archivo después de fallar la validación

+0

Tengo la misma pregunta. Si estoy usando un campo de modelo, ¿realmente tengo que guardar el archivo cuando falla la validación para que pueda subirlo cuando la validación sea exitosa? Luego, tengo que cargar un montón de basura para eliminar los archivos que se cargaron pero el usuario nunca completó el formulario. ¡Estoy seguro de que Django tiene una buena manera de hacer esto! – PhoebeB

Respuesta

2

Django solo guardará el archivo en el disco si está utilizando un modelForm y guardará con éxito una nueva instancia de ese modelo que tenga un archivoField.

En su caso lo que tiene que hacer es conseguir el archivo del diccionario request.FILES, y guárdelo en el disco por su cuenta. Debería verse algo como esto.

input_file = request.FILES['fileformfieldname'] 
new_file = open('/path/to/file.xxx') 
new_file.write(input_file.read()) 

Ahora que tiene el archivo guardado en el disco, sólo hay que recordar la ruta de acceso al archivo, para que pueda abrir de nuevo cuando el usuario vuelve a enviar el formulario fallado.

9

El problema con lo que se quiere hacer es que, por razones de seguridad, los navegadores no permitirán que una caja de entrada de archivo para tener un valor preseleccionado al cargar la página. Esto es cierto incluso si simplemente preserva el valor de una instancia anterior de la misma página. No hay nada que Django pueda hacer para cambiar esto.

Si desea evitar pedirle al usuario que vuelva a seleccionar y volver a cargar el archivo, deberá guardar el archivo cargado incluso cuando la validación falla, y luego reemplazar el campo de entrada del archivo con algo para indicar que ya tener los datos. También es probable que también desee un botón que ejecute JavaScript para volver a habilitar el campo del archivo si el usuario desea agregar un archivo diferente. No creo que Django venga con ninguna maquinaria para esto, así que tendrás que codificarlo tú mismo.

1

poco complicado pero aquí es la lógica.

  1. Junto con su archivo de entrada HTML, tenga otro campo oculto.
  2. Escriba un poco de JavaScript para mantener la ruta del archivo seleccionado + nombre en este campo oculto.
  3. Durante carga de la página, JavaScript debe comprobar su valor del campo oculto y establecer que a Archivo campo, si tiene alguna.

En la primera carga, el campo oculto está vacío, por lo que no ocurre nada.
Al seleccionar el archivo, guarda la ruta + nombre en el campo oculto. En
segunda carga, campo oculto no está vacío, por lo que establecer la ruta del archivo

De esta manera, todo el trabajo sucio que sucede en el explorador ya menos que tenga la forma válida, usted no tiene que guardar el archivo en servidor.

+6

Esto NO funcionará. Javascript no puede cambiar el tipo de entrada = valores de archivo o los usuarios malintencionados pueden descargar nombres de archivos adivinados aleatoriamente de su computadora. –

3

Ok, así que primero elevé e implementé la solución de Narendra antes de darme cuenta de que no podía funcionar, ya que javascript no puede establecer valores de tipo de entrada = "archivo". Ver: http://www.w3schools.com/jsref/prop_fileupload_value.asp

Pero he aquí una solución que funciona:

  1. separada del resto de la forma, a partir de los archivos que necesitan ser cargados.
  2. Guarde siempre el archivo (o ejecute la validación para ver si el archivo debe guardarse) y guárdelo en el modelo temporal.
  3. En la plantilla, tenga un campo oculto que indique la identificación de la instancia del modelo temporal, de modo que si cambia el archivo, la modificación se propaga. Puede obtener archivos extra guardados en su servidor, pero puede limpiarlos externamente.
  4. Cuando se puede guardar el formulario sin ningún archivo, guárdelo, vincule los archivos guardados con el modelo original y elimine el modelo de archivo cargado intermedio.

autorización, aquí es un esbozo del procedimiento, que trabaja para mí de un ejemplo en el que está intentando guardar un archivo PDF de un libro con una dirección de correo electrónico (elegido como mensajes de correo electrónico a veces no validan) de un autor.

models.py

class Book(models.Model): 
    pdf = models.FileField("PDF", upload_to="books/") 
    author_email = models.EmailField("Author Email") 

class TempPDF(models.Model): 
    pdf = models.FileField("PDF", upload_to="books/") 

forms.py

from project_name.app_name.models import Book, TempPDF 
from django.forms import ModelForm 
from django.contrib.admin.widgets import AdminFileWidget 

class BookForm(ModelForm): 
    class Meta: 
     model = Book 
     exclude = ['pdf',] 

class TempPDFForm(ModelForm): 
    class Meta: 
     model = TempPDF 
     widgets = dict(pdf = AdminFileWidget) 
     # The AdminFileWidget will give a link to the saved file as well as give a prompt to change the file. 
     # Note: be safe and don't let malicious users upload php/cgi scripts that your webserver may try running. 

views.py

def new_book_form(request): 
    if request.method == 'POST': 
     ## Always try saving file. 
     try: 
      temp_pdf_inst = TempPDF.objects.get(id=request.POST.has_key('temp_pdf_id')) 
     except: ## should really catch specific errors, but being quick 
      temp_pdf_inst = None 
     temp_pdf_form = TempPDFForm(request.POST, request.FILES, instance=temp_pdf_inst, prefix='temp_pdf') 
     if temp_pdf_form.is_valid() and len(request.FILES) > 0: 
      temp_pdf_inst = temp_pdf_form.save() 
      temp_pdf_id = temp_pdf_inst.id 
     book_form = BookForm(request.POST, prefix='book') 

     if book_form.is_valid(): # All validation rules pass 
      book = book_form.save(commit=False) 
      book.pdf = temp_pdf_inst.pdf 
      book.save() 
      if temp_pdf_inst != None: 
       temp_pdf_inst.delete() 
      return HttpResponseRedirect('/thanks/') # Redirect after POST 
    else: 
     book_form = BookForm() # An unbound form 
     temp_pdf_form = TempPDFForm() 
     temp_pdf_id = None 
    return render_to_response('bookform_template.html', 
           dict(book_form = book_form, 
            temp_pdf_form = temp_pdf_form, 
            temp_pdf_id = temp_pdf_id) 
          ) 

bookform_template.html

<table> 
    {{ book_form }} 
    {{ temp_pdf_form }} 
    <input type="hidden" name="temp_pdf_id" value="{{ temp_pdf_id }}"> 
</table> 
9

Trate django-file-resubmit

insallation

pip install django-file-resubmit 

settings.py

INSTALLED_APPS = { 
    ... 
    'sorl.thumbnail', 
    'file_resubmit', 
    ... 
} 

CACHES = { 
    'default': { 
     'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 
    }, 
    "file_resubmit": { 
     'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 
     "LOCATION": project_path('data/cache/file_resubmit') 
    }, 
} 

uso

from django.contrib import admin 
from file_resubmit.admin import AdminResubmitMixin 

class ModelAdmin(AdminResubmitMixin, ModelAdmin): 
    pass 

o

from django.forms import ModelForm 
from file_resubmit.admin import AdminResubmitImageWidget, AdminResubmitFileWidget 

class MyModelForm(forms.ModelForm) 

    class Meta: 
     model = MyModel 
     widgets = { 
      'picture': AdminResubmitImageWidget, 
      'file': AdminResubmitFileWidget, 
     } 
+0

La primera vez que intento cargar, los archivos desaparecen. El segundo intento es exitoso. ¿Tienes alguna explicación para esto? – Benjamin

Cuestiones relacionadas