2012-04-05 13 views
10

Non ho trovato questo nei documenti, ma penso che sia possibile. Sto parlando specificatamente del widget ClearableFileInput. Da un progetto in Django 1.2.6 ho questo modulo:Come posso personalizzare l'output html di un widget in Django?

# the profile picture upload form 
class ProfileImageUploadForm(forms.ModelForm): 
    """ 
    simple form for uploading an image. only a filefield is provided 
    """ 
    delete = forms.BooleanField(required=False,widget=forms.CheckboxInput()) 

    def save(self): 
     # some stuff here to check if "delete" is checked 
     # and then delete the file 
     # 8 lines 

    def is_valid(self): 
     # some more stuff here to make the form valid 
     # allthough the file input field is empty 
     # another 8 lines 

    class Meta: 
     model = SocialUserProfile 
     fields = ('image',) 

che ho poi resi utilizzando questo codice modello:

<form action="/profile/edit/" method="post" enctype="multipart/form-data"> 
    Delete your image: 
<label> {{ upload_form.delete }} Ok, delete </label> 
<button name="delete_image" type="submit" value="Save">Delete Image</button> 
    Or upload a new image: 
    {{ upload_form.image }} 
    <button name="upload_image" type="submit" value="Save">Start Upload</button> 
{% csrf_token %} 
</form> 

Come Django 1.3.1 ora usa ClearableFileInput come il widget di default, i 'm abbastanza sicuro che posso saltare le 16 linee della mia form.save e basta accorciare il codice del modulo in questo modo:

# the profile picture upload form 
class ProfileImageUploadForm(forms.ModelForm): 
    """ 
    simple form for uploading an image. only a filefield is provided 
    """ 

    class Meta: 
     model = SocialUserProfile 
     fields = ('image',) 

che mi avrebbe dato il buon feeling che ho formcode meno personalizzata, e può contare su ° e Django builtins.

Mi piacerebbe, naturalmente, mantenere l'output html uguale a prima. Quando si utilizza semplicemente il codice del modello esistente, elementi come "Attualmente: somefilename.png" vengono visualizzati in luoghi in cui non li desidero.

La suddivisione del campo del modulo ulteriormente, come non sembra funzionare. La prossima cosa che mi venne in mente fu di scrivere un widget personalizzato. Quale funzionerebbe esattamente contro i miei sforzi per rimuovere il maggior numero possibile di codice personalizzato.

Qualche idea quale sarebbe la cosa più semplice da fare in questo scenario?

+0

risposta breve: FASE 1: estendere il widget di classe FASE 2: ignorare il widget di per il vostro campo Nota: vuoi per utilizzare il widget sottoclasse creato nel passaggio 1 nel metodo '__init__' del modulo django. Se hai bisogno di esempi, fammelo sapere e lo colpirò questo pomeriggio. –

+0

L'ultima cosa a cui stavo pensando è di ignorare semplicemente il modello utilizzato dal widget. Ti sarei grato per questo pomeriggio (sei ovviamente in un altro continente come me, dato che qui sono già le 16:15: D) – marue

+0

sì, quando esco dal lavoro, ti sparo un esempio. ~ 5 ore circa –

risposta

22

In primo luogo, creare un file widgets.py in un'app. Per il mio esempio, ti renderò una classe AdminImageWidget che si estende AdminFileWidget. In sostanza, desidero un campo di caricamento dell'immagine che mostri l'immagine attualmente caricata in un tag <img src="" /> anziché solo l'output del percorso del file.

Mettere la seguente classe nel file widgets.py:

from django.contrib.admin.widgets import AdminFileWidget 
from django.utils.translation import ugettext as _ 
from django.utils.safestring import mark_safe 
import os 
import Image 

class AdminImageWidget(AdminFileWidget): 
    def render(self, name, value, attrs=None): 
     output = [] 
     if value and getattr(value, "url", None): 

      image_url = value.url 
      file_name=str(value) 

      # defining the size 
      size='100x100' 
      x, y = [int(x) for x in size.split('x')] 
      try : 
       # defining the filename and the miniature filename 
       filehead, filetail = os.path.split(value.path) 
       basename, format  = os.path.splitext(filetail) 
       miniature     = basename + '_' + size + format 
       filename      = value.path 
       miniature_filename = os.path.join(filehead, miniature) 
       filehead, filetail = os.path.split(value.url) 
       miniature_url   = filehead + '/' + miniature 

       # make sure that the thumbnail is a version of the current original sized image 
       if os.path.exists(miniature_filename) and os.path.getmtime(filename) > os.path.getmtime(miniature_filename): 
        os.unlink(miniature_filename) 

       # if the image wasn't already resized, resize it 
       if not os.path.exists(miniature_filename): 
        image = Image.open(filename) 
        image.thumbnail([x, y], Image.ANTIALIAS) 
        try: 
         image.save(miniature_filename, image.format, quality=100, optimize=1) 
        except: 
         image.save(miniature_filename, image.format, quality=100) 

       output.append(u' <div><a href="%s" target="_blank"><img src="%s" alt="%s" /></a></div> %s ' % \ 
       (miniature_url, miniature_url, miniature_filename, _('Change:'))) 
      except: 
       pass 
     output.append(super(AdminFileWidget, self).render(name, value, attrs)) 
     return mark_safe(u''.join(output)) 

Ok, allora cosa sta succedendo qui?

  1. ho importare un widget esistente (si può essere parte da zero, ma probabilmente dovrebbe essere in grado di estendere ClearableFileInput se è quello che si sta avviando con)
  2. voglio solo cambiare l'uscita/presentazione del widget , non la logica sottostante Quindi, ho la precedenza sulla funzione render del widget.
  3. nella funzione di rendering. Costruisco l'output che desidero come array output = [] non è necessario farlo, ma salva qualche concatenazione. 3 linee principali:
    • output.append(u' <div><a href="%s" target="_blank"><img src="%s" alt="%s" /></a></div> %s ' % (miniature_url, miniature_url, miniature_filename, _('Change:'))) aggiunge un tag img all'uscita
    • output.append(super(AdminFileWidget, self).render(name, value, attrs)) aggiunge l'uscita del genitore al mio widget di
    • return mark_safe(u''.join(output)) si unisce la mia matrice di output con stringhe vuote ed esonera di fuggire prima di visualizzazione

Come si usa?

class SomeModelForm(forms.ModelForm): 
    """Author Form""" 
    photo = forms.ImageField(
     widget = AdminImageWidget() 
    ) 

    class Meta: 
     model = SomeModel 

O

class SomeModelForm(forms.ModelForm): 
    """Author Form""" 
    class Meta: 
     model = SomeModel 
     widgets = {'photo' : AdminImageWidget(),} 

Il che ci dà:

admin screenshot

+2

Ugh, quasi due anni dopo e questo si sta ancora alzando-voti, per favore non implementarlo così com'è con i suoi script di ridimensionamento personalizzati. Usa SORL o qualcosa del genere. Inoltre, tieni presente che questo non funziona con gli archivi django, si presuppone solo che tu stia scrivendo/leggendo sul filesystem. –

+0

SORL? La compagnia di ricambi auto? – CodyBugstein

+0

sorl miniatura la biblioteca: http://sorl-thumbnail.readthedocs.org/en/latest/ –

Problemi correlati