4

我在管理员中有一个文本字段,其中包含来自 txt 文件的文本。我的 txt 有换行符。问题是当 TextField 位于 readonly_fields 中时,所有换行符都消失并且所有内容都被分组。如何在 readonly_fields 模式下使用该字段保持格式?不在 readonly_fields 中时不会发生此问题。谢谢!

4

3 回答 3

3

我仍在使用 django 1.3,终于找到了解决方案。因此,如果其他人仍在这条船上:

覆盖模板 fieldset.html(从 pythondir/djangodir/django/contrib/admin/templates/admin/includes/fieldset.html 复制到 djangoprojectdir/templates/admin/includes/fieldset.html)

它包含以下行:

                        {% if field.is_readonly %}
                            <p>{{ field.contents }}</p>

将它们更改为:

                        {% if field.is_readonly %}
                            <p>{{ field.contents|linebreaksbr }}</p>

这是在尝试 Danny 的解决方案后发现它不起作用,因为从内容函数返回的文本被转义以用转义码替换标签(“<”代表“<”等),然后阅读:https:/ /code.djangoproject.com/ticket/19226

于 2014-02-19T02:07:24.837 回答
2

当您查看页面的源代码时,您会看到换行符。该空格在浏览器中显示为单个空格。您需要将所有换行符 ( \n) 转换为 HTML 换行符 ( <br />) 以使其看起来符合您的要求。

选项 1: jQuery 来拯救。

像这样的东西:

    <script type="text/javascript">
      (function($) {

        $(document).ready(function() {
       // Adjustments for read-only fields:
       // a) Convert quoted HTML entities back to HTML
            $('.readonly').each(function() {
                // Ensure there isn't valid html in the field
                // The RegEx checks for any valid html opening tag
                {% comment %}
                TODO: It would be better to check against a special class name
                on the widget
                {% endcomment %}
                if ($(this).html().match(/<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/) == null) {
                  $(this).html($(this).text());
                  $('ul', this).addClass('with_bullet');
                  $('li', this).addClass('with_bullet');
                }
            });

            // b) Insert &nbsp; into empty <p>'s (m2m fields) so they don't break layout
            // (see comment on text nodes: http://api.jquery.com/empty-selector/)
            $('p.readonly:empty').each(function() { $(this).html('&nbsp;') })
        });
      })(django.jQuery);
    </script>

(注意:我们添加了“with_bullet”类,因为我们使用了 grappelli,并且 ul 和 li 的样式没有项目符号(list-style-type: none)所以这是一种让它们重新出现在我们自己的 CSS 中的方法。 ..) 还要注意最后的布局修复,我认为在更高版本的 grappelli 中不需要。

选项 2:monkeypatch django.contrib.admin.helpers.AdminReadonlyField:

from django.contrib.admin import helpers
from django.contrib.admin.util import (lookup_field,
    display_for_field, label_for_field, help_text_for_field)
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.fields.related import ManyToManyRel
from django.forms.util import flatatt
from django.template.defaultfilters import capfirst
from django.utils.encoding import force_unicode, smart_unicode
from django.utils.html import escape, conditional_escape
from django.utils.safestring import mark_safe


class BetterAdminReadonlyField(object):
    def __init__(self, form, field, is_first, model_admin=None):
        label = label_for_field(field, form._meta.model, model_admin)
        # Make self.field look a little bit like a field. This means that
        # {{ field.name }} must be a useful class name to identify the field.
        # For convenience, store other field-related data here too.
        if callable(field):
            class_name = field.__name__ != '<lambda>' and field.__name__ or ''
        else:
            class_name = field
        self.field = {
            'name': class_name,
            'label': label,
            'field': field,
            'help_text': help_text_for_field(class_name, form._meta.model)
        }
        self.form = form
        self.model_admin = model_admin
        self.is_first = is_first
        self.is_checkbox = False
        self.is_readonly = True

    def label_tag(self):
        attrs = {}
        if not self.is_first:
            attrs["class"] = "inline"
        label = self.field['label']
        contents = capfirst(force_unicode(escape(label))) + u":"
        return mark_safe('<label%(attrs)s>%(contents)s</label>' % {
            "attrs": flatatt(attrs),
            "contents": contents,
        })

    def contents(self):
        from django.contrib.admin.templatetags.admin_list import _boolean_icon
        from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
        field, obj, model_admin = self.field['field'], self.form.instance, self.model_admin
        try:
            f, attr, value = lookup_field(field, obj, model_admin)
        except (AttributeError, ValueError, ObjectDoesNotExist):
            result_repr = EMPTY_CHANGELIST_VALUE
        else:
            if f is None:
                boolean = getattr(attr, "boolean", False)
                if boolean:
                    result_repr = _boolean_icon(value)
                else:
                    result_repr = smart_unicode(value)
                    if getattr(attr, "allow_tags", False):
                        result_repr = mark_safe(result_repr)
            else:
                if value is None:
                    result_repr = EMPTY_CHANGELIST_VALUE
                elif isinstance(f.rel, ManyToManyRel):
                    result_repr = ", ".join(map(unicode, value.all()))
                else:
                    result_repr = display_for_field(value, f)
        return conditional_escape(result_repr)

helpers.AdminReadonlyField = BetterAdminReadonlyField

你可以把它放在一个文件夹“monkeypatches”中并称之为“admin_readonly_field.py”(不要忘记添加一个空__init__.py文件夹以使该文件夹成为一个模块)。然后在您的应用程序中__init__.py添加

from monkeypatches import admin_readonly_field

你走了。

上面的代码只包含monkeypatch AdminReadonlyField 的相关导入和代码(在本例中从Django 1.3 复制)。与原始课程相比,实际上没有任何变化。更改您认为对您的情况最有用的任何内容。

在您的特定情况下,您可以将这两行添加到倒数第二行:

        result_repr = display_for_field(value, f)

        if isinstance(field, models.TextField):
            result_repr = result_repr.replace('\n', '<br />')

from django.db import models在顶部)

很抱歉,Django 附带的课程太糟糕了,选项 2 是我推荐的方法。您的 TextField 并不是唯一在只读模式下看起来很糟糕的字段...

于 2013-02-04T07:22:27.163 回答
1

文本中的换行符通常由字符\n\r或经常表示\r\n(查看维基百科上的这篇文章以获取更多信息)。

您遇到的问题是这些字符将用于在文本编辑字段中显示新行,但它们不代表 html 中的新行(它们被忽略)。

如果您希望它们显示在只读字段中,则可以将它们替换为<br/>元素。

如果您可以将您的字符串标记为安全(即,如果您可以安全地添加 html 代码,而没有任何人使用该字段添加恶意代码的风险),那么您可以覆盖模型上的 save 方法以将文本换行符换成 html 行休息 -

from django.utils.safestring import mark_safe

def save(self, *args, **kwargs):
    self.text_field = mark_safe(self.text_field.replace("\n", "<br/>"))
    super(YourModel, self).save(*args, **kwargs)

另一种选择是使用django-tinymce 之类的插件添加全文格式化功能。

我的最后一个建议是用 javascript 破解它。将 admin 文件夹添加到您的模板,然后创建一个 base_site.html 文件,该文件扩展了原始文件并添加了一个简单的 javascript 函数(如此所述)。就像是 -

{% extends "admin/base.html" %}

{% block extrahead %}
    <script type="text/javascript">
        window.onload = function () {
            var p_elements = document.getElementById('content-main').getElementsByTagName('p');
            var unixNewLine = new RegExp("\n", "g");
            for (var i = p_elements.length - 1; i >= 0; i--) {
                p_elements[i].innerHTML = p_elements[i].innerHTML.replace(unixNewLine, '<br/>');
            }
        }
    </script>
{% endblock %}

您需要为replace文本中的每种类型的新行添加一个(例如\r\r\n)。虽然这可能会满足您的需求,但它似乎是所有这些中最肮脏的黑客。

于 2013-02-04T07:39:44.897 回答