Джанго: <ul> внутри help_text поля

Я хотел бы иметь <ul> внутри help_text поля формы django.

К сожалению, django отображает help_text внутри <span>.

Согласно спецификации HTML, <span> не должен содержать <ul>. По крайней мере, это то, что говорит мой инструмент проверки.

Вот источник 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)

Что я могу сделать, чтобы получить <ul> в help_text и действительном html.

Переопределение as_table() не работает, так как форма от "core_app", а поле - из плагина. Оба являются двумя различными репозиториями git, и я не хочу изменять ядро только из-за этого.

Ответ 1

Как вы уже упоминали, в HTML есть понятие блочных и встроенных элементов.
В коротких блочных элементах создается новая строка и может содержать другие блок и встроенные элементы. Встроенные элементы не генерируют новую строку и могут содержать другие встроенные элементы, но не блокировать элементы.

Веб-документы MDN предоставляют дополнительную информацию о блочных и встроенных элементах.

Поскольку span является встроенным элементом, вы не можете поместить ul который является элементом уровня блока внутри. Или, вы могли бы, но тогда это не действительный HTML, и это не то, что вы хотите.

Поскольку вы используете сторонний код, модификация может привести к другим проблемам.
Вы можете разветкить его, изменить нужные части, а затем использовать свою вилку. Но когда этот сторонний код обновляется, вам нужно повторить весь процесс.

В таких случаях вы могли бы просто сделать исправление обезьяны.
Для вашей конкретной проблемы мы могли бы сделать что-то вроде этого:

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

Вы можете поместить этот код в свой forms.py или любой другой файл, который вам подходит.

Теперь help_text будет отображаться как элемент div, который является элементом уровня блока. Вы можете разместить неупорядоченный список ul внутри и иметь действительный HTML.

Патч обезьяны - не самый красивый способ решения проблем, но это, на мой взгляд, прагматичный способ преодолеть некоторые сложные проблемы.

Ответ 2

Я думаю, что вы хотите не точно "иметь <ul> внутри вашего help_text ", а скорее "отображать список маркеров внутри вашего текста справки".

Поэтому, если у вас нет возможности переопределить as_table() или использовать что-то другое, кроме as_table(), я надеюсь, что вы все еще можете изменить таблицу стилей. В этом случае вы можете подделать свою ul с span:

from django.utils.safestring import mark_safe

help_text=mark_safe(
    '<span class="fake-ul">'
    '<span class="fake-li">foo</span>'
    '<span class="fake-li">bar</span>'
    '</span>'
)

И вот ваш CSS:

.fake-ul {
  display: block;
  padding-left: 40px;
  list-style-type: disc;
}
.fake-li {
  display: list-item;
}

Ответ 3

Так что, наверное, уже слишком поздно, но я думаю, что вы можете использовать Django виджеты.