django admin에서 list의 항목, 상세 페이지의 항목 커스터마이징 하는 방법
1. django의 admin을 수정하는 방법은 2가지가 있다.
- 정의된 admin class에서 오버라이딩을 통한 방법
- django에서 제공하는 template를 수정하는 방법
2. 이 포스트에서는 admin에서 오버라이딩을 이용하여 수정하는 방법을 정리한다.
- 문제 정의
- 썸머노트를 admin의 form에 적용하는 경우, text에 스타일을 정의하면 관련한 html 태그가 저장된다.
- 나의 경우 title이라는 필드에 저장했으며, list에 출력, 상세 페이지에도 subscript에 출력이 되었다.
- 생성 후, 리스트에서 확인시, title에 html 태그가 같이 출력이 되고, 상세 페이지에서 subscript에도 동일하게 html 태그가 출력 되었다.
- 해결을 위한 접근 방법
- chatgpt의 여러 종류를 통해 다양한 질문을 던져봤지만, 정확한 정답을 알려주는 결과는 없었다.
- 직접 만든 코드를 입력하고, list에서 title의 html 태그를 삭제하는 방법을 질문하는 경우 관련한 코드를 생성해 주었다.
- format_html, strip_tags 두 방법에 대해 제시해 줬으며 format_html 방법을 차용했다.
- 해당 방법은 기존 함수의 오버라이딩이 아닌, 공식 문서에서 제시하는 field 값의 커스텀 방법이다.
- 문제는 이 방법으로 상세 페이지의 field 정보는 해결할 수 없다.
- 상세 페이지의 subscript의 커스텀을 위한 접근 방법
- 상속받은 클래스들을 따라가며 title이 어디에서 정의되는지 확인하기로 한다.
# 최초 정의 코드
class WorkExperienceAdmin(AdminCacheClean, SummernoteModelAdmin):
->
# SummernoteModelAdmin 추적 => django_summernote/admin.py
class SummernoteModelAdmin(SummernoteModelAdminMixin, admin.ModelAdmin):
pass
->
# admin.ModelAdmin 추적 => admin/options.py
class ModelAdmin(BaseModelAdmin):
...
# 확인된 코드
@csrf_protect_m
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
with transaction.atomic(using=router.db_for_write(self.model)):
return self._changeform_view(request, object_id, form_url, extra_context)
def _changeform_view(self, request, object_id, form_url, extra_context):
to_field = request.POST.get(TO_FIELD_VAR, request.GET.get(TO_FIELD_VAR))
if to_field and not self.to_field_allowed(request, to_field):
raise DisallowedModelAdminToField(
"The field %s cannot be referenced." % to_field
)
...
context = {
**self.admin_site.each_context(request),
"title": title % self.opts.verbose_name,
- 결론적으로 changeform_view 함수를 오버라이딩 하면 된다고 판단했다.
- 빠른 작업을 위해 관련한 changeform_view 및 _changeform_view 코드를 복사해 chatgpt에 원하는 결과를 입력했다.
- 해결된 코드 결과
- 기존 title 필드는 get_cleaned_title로 변경되고 관련된 함수가 하단에 정의되었다. 해당 코드는 list에서 출력되는 결과에 대해 html 태그를 제거된 text만 출력하게 만들어 준다.
- changeform_view 함수에서 먼저 super를 이용해 기존 처리를 완료한 결과를 받도록 만들고 반환된 결과에서 subscript만 format_html()로 html 태그를 제거했다.
class WorkExperienceAdmin(AdminCacheClean, SummernoteModelAdmin):
cache_prefix = "portfolio"
use_pk = False
list_display = [
"id",
"get_cleaned_title",
"role",
"color",
"sort_num",
"language",
"project_start_date",
]
list_display_links = ["id", "get_cleaned_title", "role"]
list_editable = (
"color",
"sort_num",
"language",
)
summernote_fields = (
"title",
"summary",
"content",
)
actions = [
"delete_all_cache",
"delete_selected_items",
]
def get_actions(self, request):
actions = super(WorkExperienceAdmin, self).get_actions(request)
del actions["delete_selected"]
return actions
def get_cleaned_title(self, obj):
# HTML 태그를 제거하고 텍스트만 반환
return format_html(
obj.title
) # 또는 obj.title.strip()으로 HTML 제거 가능, 만약 HTML 태그를 제거하고 싶다면, strip_tags를 사용
get_cleaned_title.short_description = "Title" # Admin에서 표시될 제목
def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
response = super().changeform_view(request, object_id, form_url, extra_context)
# title에서 HTML 태그를 제거
if "title" in response.context_data:
response.context_data["subtitle"] = format_html(
response.context_data["subtitle"]
)
return response
3. 완료
- chatgpt를 사용하면서 느끼는 것이지만, 일반적인 서술적 질문과 간단한 코드 몇줄로는 기본적인 문제의 해결 외에는 원하는 답을 얻기 힘들다.
- 최대한 문제의 본질에 대한 질문을 하고, 최대한 reference를 제공해야 결과가 쓸만하다.
- 이런 과정에도 거짓말을 하며 동작하지 않는 코드 혹은 말도 안되는 코드를 제공하는 경우가 많은 편이다.
- 최대한 기존 admin의 html 파일을 수정하지 않는 방법을 선호하기에 이번 과정에 대해 만족스러웠다.
- 관련한 정보를 찾을 수 없었다. 물론 해외 커뮤니티를 한참 뒤지다 보면 방법을 찾을 수 있겠지만, 소비될 엄청난 시간대비 정말 짧은 시간에 원하는 결과를 도출했다.
- 누군가에게 이 글이 도움이 되길 바란다.