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

if form.is_valid() 

    do_stuff 

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

Ora formare avrà le informazioni di errore insieme ai valori originali dei campi, ma non mantenere un file selezionato Come faccio a mantenere il file selezionato se il modulo fallisce la validazione?Come fare un modulo di Django mantenere un file dopo aver fallito la validazione

+0

Ho la stessa domanda. Se sto utilizzando un campo modello, devo davvero salvare il file quando la convalida fallisce, così posso caricarlo quando la convalida ha successo? Poi devo anche fare un carico di garbage collection per rimuovere i file che sono stati caricati ma l'utente non ha mai completato correttamente il modulo. Sono sicuro che Django ha un bel modo di farlo! – PhoebeB

risposta

2

Django salverà il file sul disco da solo se si utilizza un modelForm e si salva una nuova istanza di quel modello che ha un fileField.

Nel tuo caso, ciò che devi fare è ottenere il file dal dizionario request.FILES e salvarlo su disco da solo. Dovrebbe assomigliare a qualcosa di simile a questo.

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

Ora che avete il file salvato su disco, devi solo per ricordare il percorso del file, in modo da poter aprire di nuovo quando l'utente invia nuovamente il modulo fallito.

9

Il problema con ciò che si vuole fare è che, per motivi di sicurezza, i browser non consentono a una casella di immissione file di avere un valore preselezionato al caricamento della pagina. Questo è vero anche se sta semplicemente preservando il valore da un'istanza precedente della stessa pagina. Non c'è niente che Django possa fare per cambiare questo.

Se si desidera evitare di chiedere all'utente di selezionare nuovamente e ricaricare il file, sarà necessario salvare il file caricato anche quando la convalida non riesce, quindi sostituire il campo di immissione del file con qualcosa che indichi che si sta già avere i dati Probabilmente vorrai anche un pulsante che esegua JavaScript per riabilitare il campo del file se l'utente vuole inserire un file diverso. Non penso che Django abbia qualche macchinario per questo, quindi dovrai codificarlo da solo.

1

Po 'difficile ma qui è la logica.

  1. Insieme al file di input HTML, disporre di un altro campo nascosto.
  2. Scrivere un JavaScript per mantenere il percorso del file selezionato + nome in questo campo nascosto.
  3. Durante il caricamento della pagina, il tuo JavaScript dovrebbe controllare il valore del campo nascosto e impostarlo sul campo File, se ne ha.

Al primo caricamento, il campo nascosto è vuoto, quindi non succede nulla.
Alla selezione del file, salva percorso + nome nel campo nascosto.
Al secondo carico, campo nascosto non è vuoto, in modo che impostare il percorso del file

In questo modo, tutto il lavoro sporco che accade nel browser, e se non hai valida forma, non c'è bisogno di salvare il file sul server.

+6

Questo NON funzionerà. Javascript non può cambiare tipo di input = valori di file o utenti malintenzionati potrebbero scaricare nomi di file indovinati casuali dal tuo computer. –

3

Ok, quindi ho prima mosso e implementato la soluzione di Narendra prima di rendermi conto che non poteva funzionare poiché javascript non può impostare valori di input type = "file". Vedere: http://www.w3schools.com/jsref/prop_fileupload_value.asp

Ma ecco una soluzione che funziona:

  1. Separare il resto del modulo, dai file che hanno bisogno di essere caricati.
  2. Salvare sempre il file (o eseguire la convalida per vedere se il file deve essere salvato) e salvare nel modello temporaneo.
  3. Nel modello, avere un campo nascosto che dice l'id dell'istanza del modello temporaneo, quindi se si modifica il file la modifica si propaga. È possibile ottenere file aggiuntivi salvati sul server, ma è possibile eseguire la pulizia esterna.
  4. Quando è possibile salvare il modulo meno tutti i file, salvarlo, associare i file salvati al modello originale ed eliminare il modello di file caricato intermedio.

Ok, ecco uno schizzo della procedura, che lavora per me di un esempio in cui si sta tentando di salvare un PDF di un libro con un indirizzo email (scelto come messaggi di posta elettronica a volte non convalidare) di un autore.

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

Prova 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') 
    }, 
} 

utilizzo

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 prima volta che tento di caricare, i file scompaiono. Il secondo tentativo ha successo. Avete qualche spiegazione per questo? – Benjamin

Problemi correlati