管理者のtxtファイルからのテキストを含むTextFieldがあります。私のtxtには改行があります。問題は、TextField が readonly_fields にあり、すべての改行が消え、すべてのコンテンツがグループ化されている場合です。readonly_fields モードでこのフィールドを使用してフォーマットを維持するにはどうすればよいですか? readonly_fields にない場合、問題は発生しません。ありがとう!
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>
これは、コンテンツ関数から返されたテキストがエスケープされてタグがエスケープ コード ("<" の場合は "<" など) に置き換えられるため、機能しないことが判明したダニーのソリューションを試してから、これを読んだ後です: https:/ /code.djangoproject.com/ticket/19226 .
ページのソースを表示すると、改行が表示されます。その空白は、単一のスペースのようにブラウザーに表示されます。\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 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(' ') })
});
})(django.jQuery);
</script>
(注: grappelli を使用しており、ul と li は箇条書きなしでスタイル設定されるため (list-style-type: none)、「with_bullet」クラスを追加しました。これは、独自の CSS でそれらを再表示する方法です。 ..) 最後にレイアウトの修正にも注意してください。これは、grappelli の以降のバージョンでは必要ないと思います。
オプション 2: モンキーパッチ 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 からコピーされています)。元のクラスから実際には何も変更されていません。あなたの状況で最も役立つと思うものは何でも変更してください。
あなたの特定のケースでは、これらの2行を最後から2番目の行に追加できます。
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 は、読み取り専用モードで見栄えが悪い唯一の種類のフィールドではありません...
テキストの改行は、通常、文字\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
)。これはあなたが必要とすることをするかもしれませんが、それらすべての中で最も汚いハックのようです.