Django Admin仅查看权限用户RichTextField格式化及KeyError问题解决
问题描述
我有一个仅拥有模型查看权限的用户,该模型包含RichTextField,但该用户查看数据时内容未按HTML格式化。我知道在list_display中可以用以下方法处理:
def what_field(self, obj): return format_html(obj.what)
原本打算把Django Admin作为管理主页面,Activity模型包含what、when、where等字段,超级用户登录查看该模型时,借助django-ckeditor能正常显示RichTextField内容,但仅拥有查看权限的用户不行。
核心问题:
- 如何在Django Admin仅查看权限的页面中使用
strip_tags或format_html? - 当前重写
get_form方法时出现KeyError: 'what'错误,项目使用了django-jazzmin。
model.py
from django.db import models from django.utils.translation import gettext_lazy as _ from django.conf import settings from datetime import date, datetime from ckeditor.fields import RichTextField class Activity(models.Model): what = RichTextField(verbose_name=_('What')) where = RichTextField(verbose_name=_('Where')) when = models.DateField(verbose_name=_('When')) why = RichTextField(verbose_name=_('Why')) who = RichTextField(verbose_name=_('Who')) created_on = models.DateTimeField(auto_now_add=True) modified_on = models.DateTimeField(auto_now=True) author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, verbose_name=_('Author')) class Meta: verbose_name = _('Activity Announcements') verbose_name_plural = _('Activity Announcements') def __str__(self): from django.utils.html import strip_tags return '%s' % (strip_tags(self.what))
admin.py
from django.contrib import admin from django.utils.translation import gettext_lazy as _ from .models import * from django.utils.html import format_html @admin.register(Activity) class ActivityAdmin(admin.ModelAdmin): inlines = [ParticipantsInline, Aar_uploadInline] list_display = ('__str__','created_on',) def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) if obj: form.base_fields['what'].initial = format_html(obj.what) return form
错误信息
KeyError at /admin/activity_announcements/activity/1/change/ 'what' Request Method: GET Request URL: http://localhost:8000/admin/activity_announcements/activity/1/change/ Django Version: 4.0.5 Exception Type: KeyError Exception Value: 'what' Exception Location: /app/activity_announcements/admin.py, line 29, in get_form Python Executable: /py/bin/python Python Version: 3.9.9 Python Path: ['/app', '/usr/local/lib/python39.zip', '/usr/local/lib/python3.9', '/usr/local/lib/python3.9/lib-dynload', '/py/lib/python3.9/site-packages'] Server time: Fri, 21 Oct 2022 12:24:19 +0800
解决方案
1. 修复KeyError: 'what'错误
出现这个错误是因为仅拥有查看权限的用户,其表单不会包含可编辑字段,form.base_fields里自然找不到what字段。修改get_form方法,先判断字段是否存在:
def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) if obj and 'what' in form.base_fields: form.base_fields['what'].initial = format_html(obj.what) return form
2. 让仅查看权限的用户看到格式化后的HTML内容
对于无修改权限的用户,Django Admin会显示只读页面,通过自定义只读字段的显示方法来实现HTML格式化:
from django.utils.html import format_html, strip_tags @admin.register(Activity) class ActivityAdmin(admin.ModelAdmin): inlines = [ParticipantsInline, Aar_uploadInline] list_display = ('__str__','created_on',) # 自定义格式化显示方法 def formatted_what(self, obj): return format_html(obj.what) formatted_what.short_description = _('What') def formatted_where(self, obj): return format_html(obj.where) formatted_where.short_description = _('Where') def formatted_why(self, obj): return format_html(obj.why) formatted_why.short_description = _('Why') def formatted_who(self, obj): return format_html(obj.who) formatted_who.short_description = _('Who') # 根据用户权限返回对应只读字段 def get_readonly_fields(self, request, obj=None): if not request.user.has_perm('activity_announcements.change_activity'): return ('formatted_what', 'formatted_where', 'when', 'formatted_why', 'formatted_who', 'created_on', 'modified_on', 'author') return ('created_on', 'modified_on', 'author') # 修复后的get_form方法 def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) if obj and 'what' in form.base_fields: form.base_fields['what'].initial = format_html(obj.what) return form
3. 列表页的HTML格式化(可选)
如果需要在列表页也显示格式化后的内容,修改list_display:
def what_field(self, obj): return format_html(obj.what) what_field.short_description = _('What') list_display = ('what_field', 'created_on',)
内容的提问来源于stack exchange,提问作者Markmeplease
相关产品推荐
相关产品推荐

