2012-04-05 13 views
10

No pude encontrar esto en los documentos, pero creo que debe ser posible. Estoy hablando específicamente del widget ClearableFileInput. A partir de un proyecto en Django 1.2.6 tengo este formulario:¿Cómo puedo personalizar la salida html de un widget en 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',) 

que luego representa utilizando el código de plantilla:

<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> 

Como Django 1.3.1 ahora utiliza ClearableFileInput como el control por defecto, i bastante seguro de que puedo saltar las 16 líneas de mi form.save y simplemente acortar el código del formulario de esta manera:

# 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',) 

que me daría la buena sensación que tengo formcode menos personalizado, y puede depender de XX e Django builtins.

Me gustaría, por supuesto, mantener la salida html igual que antes. Cuando utilice el código de plantilla existente, cosas como "Actualmente: nombredearchivo.png" aparecen en lugares donde no las quiero.

Dividir el formfield aún más, como {{ upload_form.image.file }} parece que no funciona. Lo siguiente que me vino a la mente fue escribir un widget personalizado. Lo cual funcionaría exactamente en contra de mis esfuerzos para eliminar tantos códigos personalizados como sea posible.

¿Alguna idea de lo que sería lo más simple de hacer en este escenario?

+0

respuesta corta: PASO 1: extender el PASO clase de aparato 2: reemplazar el widget para su campo Nota: desea para usar el widget subclasificado que creó en el paso 1 en el método '__init__' de la forma django. Si necesita ejemplos, hágamelo saber y lo haré esta tarde. –

+0

Lo último en lo que estaba pensando es en sobreescribir la plantilla utilizada por el widget. Le agradecería que sintonice esta tarde (obviamente se encuentra en un continente diferente al que yo tengo, ya que aquí está listo para las 16:15: D) – marue

+0

Sí, cuando salga del trabajo, mal le doy un ejemplo. ~ 5 o más horas –

Respuesta

22

En primer lugar, cree un archivo widgets.py en una aplicación. Para mi ejemplo, voy a hacer una clase AdminImageWidget que se extiende AdminFileWidget. Básicamente, quiero un campo de carga de imágenes que muestre la imagen cargada actualmente en una etiqueta <img src="" /> en lugar de simplemente generar la ruta del archivo.

ponga la siguiente clase en el archivo de 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, así que lo que está pasando aquí?

  1. me importa un widget de existente (que puede estar empezando desde cero, pero probablemente debería ser capaz de extender ClearableFileInput si eso es lo que está comenzando con)
  2. sólo quiero cambiar la salida/presentación del widget , no la lógica subyacente. Por lo tanto, anulo la función render del widget.
  3. en la función de representación Creo que el resultado que deseo como matriz output = [] no tiene que hacer esto, pero guarda alguna concatenación. 3 líneas principales:
    • output.append(u' <div><a href="%s" target="_blank"><img src="%s" alt="%s" /></a></div> %s ' % (miniature_url, miniature_url, miniature_filename, _('Change:'))) añade una etiqueta img a la salida
    • output.append(super(AdminFileWidget, self).render(name, value, attrs)) añade la salida de los padres de mi aparato
    • return mark_safe(u''.join(output)) se une a mi matriz de salida con cadenas vacías y exime que se escape antes de la visualización

¿Cómo uso esto?

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(),} 

Lo que nos da:

admin screenshot

+2

Ugh, casi dos años más tarde y esto todavía se está levantando -votos, por favor no implemente esto como está- con sus scripts personalizados de cambio de tamaño. Use SORL o algo así. Además, tenga en cuenta que esto no funciona con los almacenamientos django, simplemente supone que está escribiendo/leyendo en el sistema de archivos. –

+0

SORL? ¿La compañía de autopartes? – CodyBugstein

+0

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

Cuestiones relacionadas