2012-04-05 3 views
10

Ich konnte das nicht in den Dokumenten finden, aber denke, dass es möglich sein muss. Ich spreche speziell von dem ClearableFileInput-Widget. 1.2.6 aus einem Projekt in django Ich habe dieses Formular:Wie kann ich die HTML-Ausgabe eines Widgets in Django anpassen?

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

, die ich dann dieses Template-Code gerendert:

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

Wie Django 1.3.1 verwendet nun ClearableFileInput als Standard-Widget, i ist ziemlich sicher, dass ich die 16 Zeilen meines form.save überspringen und wie so die Form Code verkürzen:

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

das ist mir das gute Gefühl geben würde, dass ich weniger maßgeschneiderte formcode habe und kann auf th verlassen e Django Builtins.

Ich würde natürlich gerne die HTML-Ausgabe wie zuvor beibehalten. Wenn Sie nur den vorhandenen Vorlagencode verwenden, erscheinen solche Dinge wie "Currently: somefilename.png" an Orten, an denen ich sie nicht haben möchte.

Die Aufteilung des Formularfelds weiter, wie {{ upload_form.image.file }} scheint nicht zu funktionieren. Das nächste, was mir in den Sinn kam, war ein benutzerdefiniertes Widget zu schreiben. Das würde genau gegen meine Bemühungen arbeiten, so viel benutzerdefinierten Code wie möglich zu entfernen.

Irgendwelche Ideen, was wäre die einfachste Sache in diesem Szenario zu tun?

+0

kurze Antwort: Schritt 1: Verlängerung der Widget-Klasse SCHRITT 2: Widget für Ihr Feld Hinweis außer Kraft gesetzt: Sie wollen Verwenden Sie das untergeordnete Widget, das Sie in Schritt 1 in der Methode "__init__" der Django-Form erstellt haben. Wenn Sie Beispiele brauchen, lassen Sie es mich wissen und ich werde es heute Nachmittag treffen. –

+0

Das letzte, worüber ich nachgedacht habe, ist, einfach die vom Widget verwendete Vorlage zu überschreiben. Ich würde mich freuen, wenn du heute nachmittag reinkommst (du bist offensichtlich auf einem anderen Kontinent als ich, denn hier ist es schon 16:15 Uhr: D) – marue

+0

ja, wenn ich von der Arbeit steige, erschieße ich dir ein Beispiel. ~ 5 oder so Stunden –

Antwort

22

Erstellen Sie zuerst eine widgets.py Datei in einer App. Für mein Beispiel mache ich Sie eine AdminImageWidget Klasse, die AdminFileWidget erweitert. Im Wesentlichen möchte ich ein Bild-Upload-Feld, das das aktuell hochgeladene Bild in einem <img src="" />-Tag anzeigt, anstatt nur den Pfad der Datei auszugeben.

Setzen Sie die folgende Klasse in Ihrer widgets.py Datei:

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, so was hier passiert?

  1. ich importieren Sie eine vorhandene Widget (Sie von Grund auf neu werden kann beginnen, sollte aber wahrscheinlich in der Lage sein ClearableFileInput zu verlängern, wenn das ist, was Sie beginnen mit)
  2. Ich möchte nur die Ausgabe/Präsentation des Widgets ändern , nicht die zugrunde liegende Logik. Also überschreibe ich die render Funktion des Widgets.
  3. in der Render-Funktion Ich baue die Ausgabe möchte ich als Array output = [] müssen Sie dies nicht tun, aber es spart einige Verkettung. 3 Schlüssellinien:
    • output.append(u' <div><a href="%s" target="_blank"><img src="%s" alt="%s" /></a></div> %s ' % (miniature_url, miniature_url, miniature_filename, _('Change:'))) Fügt ein img-Tag mit dem Ausgang
    • output.append(super(AdminFileWidget, self).render(name, value, attrs)) der Eltern Ausgabe meiner Widget fügt
    • return mark_safe(u''.join(output)) verbindet meine Ausgabe-Array mit leeren Saiten, und stellt es an der Flucht vor der Anzeige

Wie verwende ich das?

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

    class Meta: 
     model = SomeModel 

ODER

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

Was uns gibt:

admin screenshot

+2

Ugh, fast zwei Jahre später und das ist immer noch up-Stimmen, bitte nicht implementieren, wie es ist mit seinen benutzerdefinierten Größenänderung Skripte. Benutze SORL oder etwas ähnliches. Bitte beachten Sie auch, dass dies nicht mit Django-Speichern funktioniert, sondern nur davon ausgegangen wird, dass Sie auf dem Dateisystem schreiben/lesen. –

+0

SORL? Die Auto-Teile-Firma? – CodyBugstein

+0

Sorl thumbnail die Bibliothek: http://sorl-thumbnail.readthedocs.org/en/latest/ –

Verwandte Themen