Django admin實現TextField字段changelist頁面換行、空格正常顯示

問題背景

在Django後台的使用admin view綁定model後,可以很方便的通過網頁對底層的數據表進行增刪查改操作。
在實際工作中有一些數據字段會存儲了json或者其他包含換行符、空格符的文本內容,這些文本內容在記錄編輯詳情頁是能正常顯示換行、空格的,如下:

但是在changelist頁面則會省略所有空格、換行,導致可讀性較差,如下:
image

原因

究其原因,其實是因為在編輯詳情頁面,存放文本的標籤是textarea,在該標籤中的文本內容並不會忽略換行、空格字符,通過使用瀏覽器開發者工具可以看到如下代碼:

<textarea name="lang_content" cols="40" rows="10" class="vLargeTextField" required="" id="id_lang_content">{
  "en": "this is a content",
  "zh-hant": "這是默認正文內容"
}</textarea>

而在changelist頁面,默認使用的是直接就是td標籤,即直接放入一個表單元格之中,這時根據HTML標準會將所有連續的空格、換行符均處理為單個空格:

<td class="field-lang_content">{
  "en": "this is a content",
  "zh-hant": "這是默認正文內容"
}</td>

解決方案

以一個簡單的test_record table的admin view為例。
表結構:

CREATE TABLE `test_table` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `title` varchar(255) NOT NULL DEFAULT '0',
  `content` varchar(255) NOT NULL,
  `lang_content` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

models.py:

# coding=utf-8
from django.db import models


class TestRecord(models.Model):
    class Meta:
        db_table = "test_record"
        db_tablespace = 'test_db'

    id = models.AutoField(primary_key=True, verbose_name="id")
    title = models.CharField(max_length=255)
    content = models.CharField(max_length=255)
    lang_content = models.TextField()

admin.py

from django.contrib import admin
from django.utils.html import format_html

from .models import TestRecord


@admin.register(TestRecord)
class TestRecordAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'content', 'lang_content', 'lang_content_view')

使用list_editable

將lang_content放入list_editable,如下:

    list_editable = ('lang_content', )

這樣在changelist頁面,將使用textarea標籤修飾lang_content內容,於是空格、換行符就能夠正確顯示:

同時在changelist頁面將可以直接編輯lang_content字段,無法滿足只希望該字段在changelist頁面可讀,而不可編輯的需求,相當於是把編輯功能和顯示功能強制綁定無法分離,缺乏靈活性。

使用format_html–滿足只讀需求

在django.utils.html中提供了一個format_html函數,該函數可用於將所有輸出內容按HTML格式轉義渲染。
於是可以通過在admin class中定義一個專門負責展示lang_content內容的實例方法,將lang_content內容用pre或textarea標籤包裹,而後經過format_html轉義後返回。此方法更加靈活,還可通過調整標籤各屬性定製輸出效果–比如設置高度(rows)、寬度(cols)等。
代碼如下所示

    def lang_content_view(self, obj):
        # return format_html('<textarea cols=40 rows={} readonly>{}</textarea>', obj.lang_content.count('\n')+1, obj.lang_content)
        return format_html('<pre>{}</pre>', obj.lang_content)

顯示效果如下:
image
對應網頁代碼如下:

<td class="field-lang_content_view"><pre>{
  "en": "this is a content",
  "zh-hant": "這是默認正文內容"
}</pre></td>

轉載請註明出處,原文地址://www.cnblogs.com/AcAc-t/p/django_admin_changelist_textfield_newline_display.html