Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: <ul> inside help_text of field

I would like to have a <ul> inside the help_text of a django form field.

Unfortunately django renders the help_text inside a <span>.

According to the HTML spec a <span> must not contain a <ul>. At least that is what my validation tool says.

Here is the source of django: https://github.com/django/django/blob/master/django/forms/forms.py#L283

def as_table(self):
    "Return this form rendered as HTML <tr>s -- excluding the <table></table>."
    return self._html_output(
        normal_row='<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
        error_row='<tr><td colspan="2">%s</td></tr>',
        row_ender='</td></tr>',
        help_text_html='<br><span class="helptext">%s</span>',
        errors_on_separate_row=False)

What can I do to get <ul> in the help_text and valid html.

Overriding as_table() does not work, since the form is from "core_app" and the field is from a plugin. Both are two different git repos and I don't want to modify the core just because of this.

like image 547
guettli Avatar asked Mar 12 '18 13:03

guettli


1 Answers

As you already mentioned, in HTML there is a concept of block and inline elements.
In short block elements generate a new line and may contain other block and inline elements. Inline elements don't generate a new line and may contain other inline elements, but not block elements.

MDN web docs offers more information on block and inline elements.

Since span is an inline element, you can't place ul which is a block-level element inside. Or, you could, but then it's not a valid HTML, and that's not what you want.

Since you're using a third-party code, modifiying it could introduce other problems.
You could fork it, modify the parts you need and then use your fork. But when that third-party code gets updated, you have to repeat the whole process.

In cases like that you could just do monkey patching.
For your particular problem we could therefore do something like this:

from django import forms

class MyBaseForm(forms.BaseForm):
    def as_table(self):
        "Return this form rendered as HTML s -- excluding the ."
        return self._html_output(
            normal_row='%(label)s%(errors)s%(field)s%(help_text)s',
            error_row='%s',
            row_ender='',
            help_text_html='<div class="helptext">%s</div>',
            errors_on_separate_row=False)

BaseForm.as_table = MyBaseForm.as_table

You can place this code in your forms.py or any other file that is suitable to you.

Now the help_text will be rendered as a div element, which is a block-level element. You can place an unordered list ul inside and have a valid HTML.

Monkey patching isn't the most beautiful way of solving problems, but it is in my opinion a pragmatic way to overcome some tricky issues.

like image 152
cezar Avatar answered Sep 21 '22 16:09

cezar