I am not able to pass a variable to a widget with its "mark_safe" attribute intact.

43 views
Skip to first unread message

Dennis Marwood

unread,
Jun 16, 2015, 10:46:51 PM6/16/15
to django...@googlegroups.com
Hello,

I want to display images in my manyTomany so that a user can choose what images would be included inside of a "BlogWidgetCarousel". The issue I am running into is that the render function for the widget returns html via the "format_html" and the variable has lost its "safe" setting at that point.

In my model I return the choice_label with "mark_safe" but somewhere along the way the string is altered and it must be losing that quality. (For the example I just changed it to a <b> tag)

I have found the render method and confirmed that I can set the string back to a safe state and it works fine.

My questions
  1. Am I just making some kind of mistake when I try to send back the string from the model?
  2. Am I doing something that is unexpected? It seems like this should work.
  3. Would you create a custom widget to solve this issue, if not what would you use?



#models.py
class BlogWidgetCarousel(models.Model):
    entry
= models.TextField()
    blog
= models.ForeignKey(Blog, blank=True, null=True)
    position
= models.PositiveSmallIntegerField("Position")
    images
= models.ManyToManyField("Image")

   
class Meta:
        ordering
= ('position', )

   
def __str__(self):
       
return str(self.position)
   
   
def save(self, *args, **kwargs):
       
self.entry = "<b><i>TODO: create image slider</i></b>"
       
super(BlogWidgetCarousel, self).save(*args, **kwargs)

   
def display(self):
       
return self.entry

class Image(models.Model):
    title
= models.CharField(max_length=60, blank=False, null=False)
    image
= models.ImageField(upload_to="images/")

   
def thumb(self):
       
return '<a href="{0}"><img src="{0}"></a>'.\
                    format
(MEDIA_URL + str(self.image))

   
def __str__(self):
       
return mark_safe(u'<b>bold</b>')
    __str__
.allow_tags = True


#admin.py
class BlogWidgetCarouselInline(admin.StackedInline): #, SortableInline):
    model
= BlogWidgetCarousel
    extra
= 0

    formfield_overrides = {
        models
.ManyToManyField: {'widget': CheckboxSelectMultiple},
   
}

    fieldsets
= (
       
("Create Carousel:", {
           
'fields': (("position"), 'images',)
       
}),
       
("Result:", {
           
'fields': ('thumb', 'display_as',)
       
}),
   
)
    readonly_fields
= ('display_as', 'thumb',)

   
def display_as(self, instance):
       
return instance.display()
    display_as
.allow_tags = True

   
def thumb(self, instance):
        x
= ""
       
for i in instance.images.all():
            x
+= i.thumb()
       
return x
    thumb
.allow_tags = True

class EntryAdmin(admin.ModelAdmin):
    list_display
= ("title", "created")
    prepopulated_fields
= {"slug": ("title",)}
    inlines
= [
               
BlogWidgetTextInline, BlogWidgetCarouselInline,
           
]


#dist-packages/django/forms/widgets
#...
@html_safe
@python_2_unicode_compatible
class ChoiceInput(SubWidget):
    """
    An object used by ChoiceFieldRenderer that represents a single
    <input type='$input_type'>.
    """
    input_type = None  # Subclasses must define this

    def __init__(self, name, value, attrs, choice, index):
        self.name = name
        self.value = value
        self.attrs = attrs
        self.choice_value = force_text(choice[0])
        self.choice_label = force_text(choice[1])
        self.index = index
        if 'id' in self.attrs:
            self.attrs['id'] += "_%d" % self.index

    def __str__(self):
        return self.render()

    def render(self, name=None, value=None, attrs=None, choices=()):
        if self.id_for_label:
            label_for = format_html(' for="{}"', self.id_for_label)
        else:
            label_for = ''
        attrs = dict(self.attrs, **attrs) if attrs else self.attrs
        #print self.choice_label <---- Prints
"<b>bold</b>" as expected.
        return format_html('<label{}>{} {}</label>', label_for, self.tag(attrs), self.choice_label) # choice_label is escaped by format_html
        #return format_html('<label{}>{} {}</label>', label_for, self.tag(attrs), mark_safe(self.choice_label)) <---Works


Dennis Marwood

unread,
Jun 20, 2015, 9:15:27 PM6/20/15
to django...@googlegroups.com
I found that the "correct" way to address this issue is to use raw_id_fields.
Reply all
Reply to author
Forward
0 new messages