devspoon-portfolio-blog 오픈소스에 admin 기능 구현하기
* 참고 : https://docs.djangoproject.com/en/4.1/ref/contrib/admin/
1. app별 admin 분리 (완료)
- app별로 site_header, site_title, index_title 적용
- user에 get_app_list으로 메뉴 출력 순서 소팅
2. 리스트 페이지 수정
- action 적용
- is_deleted 불리언 제어 : delete/activate
- is_hidden 불리언 제어 : hidden/visible
- 상위 기능 mixin으로 제공
- user는 별개로 직접 구현
- 커스텀 필드 적용 : 상호 작용/ 검증할 내용 없음 적용 안함
- SimpleListFilter 적용
- user에만 적용
- rangefilter 설치 : 날자, 시간별로 필터 가능
- 설치 명령어 : pip install django-admin-rangefilter
- get_readonly_fields : 썸네일 출력
- 썸네일이 없는 경우 공백으로 처리
- readonly_fields에 해당 필드를 등록을 해 놓고, get_readonly_fields로 해당 동작이 실행전 검사를 통해 출력 여부 설정
- 예) obj가 있다면 해당 필드를 그대로 유지, 없다면 제거
- 다른 필드에 있어도 get_***_fields로 사전 처리가 가능할 것으로 예상됨
- 커스텀 버튼 달기 : 당장 추가해야 할 기능이 없어서 삭제 / html 오버라이딩 기능이기에 다른 구현 사항 참고
- boolean 아이콘 : 특정 값을 불리언으로 만들면 django amin에서 자동으로 아이콘 생성함
- editable : 해당 동작은 model에서 설정가능하다.
- 예를 들어 아래 코드와 같이 모델에 선언하면, 해당 코드는 admin에서 보이지 않는다.
class Article(models.Model):
title = models.CharField('제목', max_length=126, null=False)
content = models.TextField('내용', null=False)
author = models.CharField('작성자', max_length=16, null=False)
created_at = models.DateTimeField('작성일', auto_now_add=True)
# created의 editable 속성에 True를 설정
created_at.editable = True
- 하지만, admin 자체에서 exclude = ['created_at',] 이렇게 선언해도 동일하게 동작된다.
- response_change ***
- response_change는 관리 양식이 제출된 후 객체 및 모든 관련 인스턴스가 저장된 직후에 호출됩니다.
- 객체가 변경된 후 이를 재정의하여 기본 동작을 변경할 수 있습니다.
- 예를 들어 아래와 같이 오버라이딩된 htrml 코드가 있다면, name에 선언된 값을 참고로 if를 통해 분기하여
원하는 작업을 추가적으로 실행하고 redirect할 수 있다.
<div class="submit-row">
<input type="submit" value="Make Unique" name="_make-unique">
</div>
- list_editable : 인스턴스로 이동하지 않고 리스트 페이지에서 바로 수정을 할 수 있도록 지원한다.
- search_fields : 검색에 반영할 필드 지정
- autocomplete_fields : search_fields와 연계하여 설정할 수 있음 - 조건이 까다로워서 적용 안함
- admin_order_field : 정렬기능을 추가할 수 있음 - 적용 안함
- short_description : 리스트의 컬럼 항목의 제목을 수정할 수 있음
- boolean : True, False 대신 O, X의 아이콘 모양으로 출력함
3. 디테일 페이지 수정
- form 적용
- save_model : 특정 페이지 저장시 자동으로 특정 필드 업데이트
- inlines : 다른 모델의 내용을 한 페이지에서 저장, 수정을 할 수 있도록 페이지를 결합해 준다
- StackedInline, TabularInline 두 가지중 하나를 선택할 수 있으며, 가로 세로의 결합 화면을 만들어 준다.
class UserProfileInline(admin.TabularInline):
model = UserProfile # OneT
class CustomUserAdmin(UserAdmin):
....
inlines = [UserProfileInline]
- readonly_fields : 수정 없이 읽기만 가능한 필드
- raw_id_fields : 대량의 데이터가 있는 경우 select로 찾기가 어렵다. 새로운 창을 띄워 전체를 쉽게 확인할 수 있도록 지원하며 페이지네이션 또한 자동으로 지원한다.
- formfield_for_foreignkey : 외래키 참조로 셀렉트 박스의 내용을 재정의 할 수 있다.
- 세가지 경우에 대한 예시 코드를 정리함
1) 셀렉트 선택 항목 제한
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "category":
#kwargs["queryset"] = Category.objects.filter(name__in=['a', 'b'])
2) 선택하는 목록들의 출력 내용 재 정의
class CategoryChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return "Category: {}".format(obj.name)
@admin.register(Hero)
class HeroAdmin(admin.ModelAdmin, ExportCsvMixin):
....
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "category":
return CategoryChoiceField(queryset=Category.objects.all())
return super().formfield_for_foreignkey(db_field, request, **kwargs)
3) 외래키 참조에 obj를 직접 접근해서 queryset을 가져와야 하는 경우
# reference : https://wikidocs.net/10437
# formfield_for_foreignkey 메소드에서 request.user 객체는 바로 접근할 수 있지만
# 참조하는 인스턴스에는 바로 접근할 수 없다
# get_form() 메소드를 오버라이딩해서 request 객체에 현재 인스턴스를 담아두고
# formfield_for_foreignkey 필드에서 꺼내 쓰는 형식이다.
def get_form(self, request, obj=None, **kwargs):
request.current_object = obj
return super(MessageAdmin, self).get_form(request, obj, **kwargs)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
instance = request.current_object
if db_field.name == 'category':
kwargs['queryset'] = Category.objects.filter(board=instance.board)
return super(MessageAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
- fieldsets : 상세 페이지를 관련된 항목끼리 그룹화 하여 분류, 출력할 수 있다 아래 코드 참고
fieldsets = [
('key information', {'fields': ['username', 'email', 'password', 'nickname','gender']}),
('detail information', {'fields': ['date_joined', 'last_login_at', 'last_login','verified', 'is_superuser', 'is_staff', 'is_active','is_privacy_policy', 'is_terms_of_service', 'is_mobile_authentication', 'is_deleted']}),
('more information', {'fields': ['profile_image', 'deleted_at']}),
- 해당 코드는 3개의 그룹으로 분류된다. 처음 오는 문자열은 그룹 제목이 된다.
- 보기/감추기 (접기 기능)
- fieldsets에 'classes' : ['collapse']를 속성으로 추가
- inlines의 경우는 테스트 안해봄
fieldsets = [
('key information', {'fields': ['username', 'email', 'password', 'nickname','gender'],'classes': ['collapse']}),
('detail information', {'fields': ['date_joined', 'last_login_at', 'last_login','verified', 'is_superuser', 'is_staff', 'is_active','is_privacy_policy', 'is_terms_of_service', 'is_mobile_authentication', 'is_deleted'],'classes': ['collapse']}),
('more information', {'fields': ['profile_image', 'deleted_at'],'classes': ['collapse']}),
]
4. csv 적용
- 내보내기
- 가져오기
5. 그래프 : 구글 애널리틱스 적용 후 그래프 구현할 예정
- 참고 :
- https://yomangstartup.tistory.com/42?category=963415
'Study > django' 카테고리의 다른 글
i18n 다국어 기능 적용하는 방법 (1) | 2023.01.11 |
---|---|
django admin - raw_id_fields, search_fields problem (0) | 2022.12.19 |
Django ORM Cookbook 학습 정리 (0) | 2022.12.07 |
Django Admin Cookbook 학습 정리 - 기대보다 큰 배움 (0) | 2022.12.01 |
django Test/Study Project for Admin 공유 (0) | 2022.11.24 |
댓글