2016-05-17 6 views
1

Ich schreibe eine Klasse, die von einem benutzerdefinierten Vorlagenfilter zurückgegeben wird. Es hat eine __str__ Methode, die HTML zurückgibt. Ich möchte nicht, dass HTML maskiert wird.Markieren einer Klasse als "sicher" für das Rendern in Vorlagen

Ich habe versucht, nur mark_safe auf meine Zeichenfolge vor der Rückgabe von der __str__-Methode aufrufen, aber das Ergebnis ist escaped. Ich gehe davon aus, dass Django überprüft, ob das Objekt sicher ist, bevor es in eine Zeichenfolge konvertiert wird?

Kann ich irgendwie die Klasse selbst als sicher markieren?

z.B.

class ParagraphTag(object): 
    def __init__(self, text): 
     self.text = text 

    def __str__(self): 
     return mark_safe('<p>{}</p>'.format(self.text + 'baz')) 

@register.filter(name='paragraph_tag') 
def paragraph_tag(text): 
    return ParagraphTag(text) 

Das Rendern eines Absatz-Tag-Objekts in einer Vorlage führt zu einem Escape-Zeichen.

z.B. {{ paragraph_tag }} -><p>foo</p>

Wenn ich mark_safe auf dem ParagraphTag Objekt selbst nennen, wenn es von meiner Vorlage Filter zurückkehrt, dann wird es in ein SafeBytes Objekt verwandelt, das ist nicht das, was ich will. Ich möchte das Rich-Objekt in meiner Vorlage verfügbar haben und es nur in eine Zeichenfolge konvertieren, wenn es gerendert wird.

+1

können Sie nicht sicher aus dem Vorlagenfilter zurückkehren? Es würde helfen, wenn Sie ein Beispiel-Code-Schnipsel zeigen könnten. – Sayse

+0

@Sayse hat ein Beispiel hinzugefügt – Acorn

+0

In Ihrem ersten Satz sagen Sie, dass diese Klasse von einem benutzerdefinierten Vorlagenfilter zurückgegeben wird, also haben Sie ein Beispiel dafür? es würde mehr Sinn machen (für mich), darin sicher zu sein. Welches Problem versuchen Sie andernfalls zu lösen? – Sayse

Antwort

3

Django verwendet normalerweise unicode(), um eine Zeichenfolge aus Python-Objekten abzurufen. Sie müssen __unicode__ implementieren, damit es eine sichere Unicode-Zeichenfolge zurückgibt. Andernfalls wird der Standardwert, der zurückgegeben wird, von __str__ übernommen, wird jedoch durch die Umwandlung unsicher gemacht.

Für die Aufzeichnung, hier ist der Code, den ich es zu diagnostizieren verwendet:

from django.utils.html import mark_safe 

class ParagraphTag(object): 

    def __init__(self, text): 
     self.text = text 

    def __str__(self): 
     return mark_safe('<p>{}</p>'.format(self.text + 'baz')) 

print str(ParagraphTag("foo")).__class__ 
print str(ParagraphTag("foo")) 
print 
print unicode(ParagraphTag("foo")).__class__ 
print unicode(ParagraphTag("foo")) 
print mark_safe(unicode(ParagraphTag("foo"))).__class__ 

erhalten Sie folgende Ausgabe:

<class 'django.utils.safestring.SafeBytes'> 
<p>foobaz</p> 

<type 'unicode'> 
<p>foobaz</p> 
<class 'django.utils.safestring.SafeText'> 

Und hier ist ein Beispiel für eine Klasse, die sicher Unicode produzieren:

class ParagraphTagFixed(object): 

    def __init__(self, text): 
     self.text = text 

    def __str__(self): 
     return unicode(self).encode("utf-8") 

    def __unicode__(self): 
     return mark_safe(u'<p>{}</p>'.format(self.text + u'baz')) 

print unicode(ParagraphTagFixed("foo")).__class__ 
print unicode(ParagraphTagFixed("foo")) 
print str(ParagraphTagFixed("foo")).__class__ 
print str(ParagraphTagFixed("foo")) 

Es wird sich zeigen:

<class 'django.utils.safestring.SafeText'> 
<p>foobaz</p> 
<class 'django.utils.safestring.SafeBytes'> 
<p>foobaz</p> 
2

Ich denke, dass __str__ sollte eine Zeichenfolge zurückgeben. Deines tut es nicht, und das verursacht dir Ärger.

Django verwendet eher __html__ für Escaped Strings. In der Tat bietet es einen html_safe deecorator, der diese Methode basierend auf Ihrer Definition von __str__ erstellt.

auf Python 3 können Sie Ihre Klasse so definieren:

from django.utils.html import html_safe 

@html_safe 
class Test(): 
    def __str__(self): 
     return '<p>Hey</p>' 

Und auf Python 2:

from django.utils.html import html_safe 
from django.utils.encoding import python_2_unicode_compatible 

@html_safe 
@python_2_unicode_compatible 
class Test(): 
    def __str__(self): 
     return '<p>Hey</p>' 

(oder Sie können __unicode__ definieren, anstatt __str__).

+0

Das ist richtig. Danke für die präzise Lösung. – graup

Verwandte Themen