2011-10-25 13 views
15

Tutaj jest problem, mam Django formularz zawierający pola Plik, a mianowicie:Pole Django Form pliku znika w przypadku błędu formularza

photo = forms.FileField(help_text="Please attach a photo", required=False) 

Jeśli formularz sprawdza, pole pliku jest ograniczona i zapisane prawidłowo. Problem występuje, gdy użytkownik wypełnia cały formularz i nie sprawdza poprawności: ścieżka wybranego pliku znika.

Tak więc, jeśli użytkownik nie zdaje sobie z tego sprawy, naprawia błędy innych pól i przesyła je ponownie - tym razem bez zdjęcia.

Tylko w przypadku, forma jest tworzona w widoku jak ten:

ProfileForm(request.POST or None, request.FILES or None) 

i HTML jest:

<div id="uniform-id_photo" class="uploader"> 
    <input id="id_photo" class="clearablefileinput" type="file" name="photo" size="19" style="opacity: 0;"> 
    <span class="filename" style="-moz-user-select: none;">No file selected</span> 
    <span class="action" style="-moz-user-select: none;">Choose File</span> 
</div> 

Czy ktoś miał ten sam problem przed? Wszelkie myśli w kierunku rozwiązania? :)

Dzięki!

+0

Jeśli spojrzysz na administratora django, za każdym razem, gdy prześlesz nieprawidłowy formularz, resetuje ścieżki plików. Chyba nie ma sposobu, aby to zrobić, ale dlaczego nie podświetlić pola pliku w swoim html? – iva123

+0

Tak, to prawdopodobnie najlepszy sposób na zwrócenie uwagi użytkownika. Dzięki! – Sam

Odpowiedz

26

Niestety, jest to problem (na pewno funkcja bezpieczeństwa) narzucony przez przeglądarki i nie można go rozwiązać jako takiego. Przeglądarki nie pozwalają określić wartości początkowej dla plików wejściowych i nie ma niczego, co można by zrobić, aby obejść to.

Powodem jest to, że gdyby strona mogła to zrobić, otworzyła by się wektor, który pozwoliłby jakiejkolwiek stronie internetowej wykraść dowolny plik na twoim komputerze, odgadując ścieżki plików - mogliby po prostu uruchomić skrypt w tle próbował wysłać interesujące pliki z powrotem na serwer.

Jedynym rozwiązaniem jest faktyczne zapisanie przesłanego pliku na serwerze, niezależnie od tego, czy formularz zostanie zatwierdzony, a następnie po wyświetleniu formularza i błędów użytkownikowi, należy wskazać, że otrzymano plik i że powinny one tylko wypełnij to pole, aby je zastąpić.

+0

Rozumiem, ma sens. Dzięki za miłą i szczegółową odpowiedź! – Sam

+0

Innym rozwiązaniem jest wykonanie żądania AJAX w celu sprawdzenia poprawności formularza. –

0

piszę jakieś rozwiązanie:

class CustomClearableFileInput(ClearableFileInput): 

def render(self, name, value, attrs=None): 
    if len(<YourModel>.objects.filter(id=self.form_instance_id))>0: 
     file = <YourModel>.objects.get(id=self.form_instance_id).<yourField> 
    else: 
     file = '' 
    substitutions = { 
     'initial_text': self.initial_text, 
     'input_text': self.input_text, 
     'clear_template': '', 
     'clear_checkbox_label': self.clear_checkbox_label, 
    } 
    template = '%(input)s' 
    substitutions['input'] = super(ClearableFileInput, self).render(name, value, attrs) 
    self.template_with_initial = ('<p class="file-upload">%s</p>' 
         % self.template_with_initial) 
    self.template_with_clear = ('<span class="clearable-file-input">%s</span>' 
         % self.template_with_clear) 

    if value and hasattr(value, "url"): 
     template = self.template_with_initial 
     substitutions['initial'] = format_html(self.url_markup_template, 
               value.url, 
               force_text(value)) 
     if not self.is_required: 
      checkbox_name = self.clear_checkbox_name(name) 
      checkbox_id = self.clear_checkbox_id(checkbox_name) 
      substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name) 
      substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id) 
      substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id}) 
      substitutions['clear_template'] = self.template_with_clear % substitutions 
      url = '' if file == '' else file.url 
    else: 
     template = self.template_with_initial 

     substitutions['initial'] = format_html(self.url_markup_template, 
               url, 
               force_text(file)) 
     if not self.is_required: 
      checkbox_name = self.clear_checkbox_name(name) 
      checkbox_id = self.clear_checkbox_id(checkbox_name) 
      substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name) 
      substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id) 
      if fav == '': 
       substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id, 'disabled': 'disabled'}) 
      else: 
       substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id}) 
      substitutions['clear_template'] = self.template_with_clear % substitutions 



    return mark_safe(template % substitutions) 

a następnie w formularzu trzeba napisać:

class <YourModel>Form(ModelForm): 
    class Meta: 
     model = <YourModel> 
     fields = '__all__' 
     widgets= {'<YourField>': CustomClearableFileInput} 

    def __init__(self, *args, **kwargs): 
     super(OperatorSettingsForm, self).__init__(*args, **kwargs) 
     self.fields['<YourField>'].widget.form_instance_id = self.instance.id 

to działa na mnie. Myślę, że nie będziesz miał problemu :)

Powiązane problemy