O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

Django admin site 커스텀하여 적극적으로 활용하기

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Carregando em…3
×

Confira estes a seguir

1 de 67 Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (20)

Semelhante a Django admin site 커스텀하여 적극적으로 활용하기 (20)

Anúncio

Mais recentes (20)

Django admin site 커스텀하여 적극적으로 활용하기

  1. 1. Django admin site 커스텀하여 적극적으로 활용하기 박영우
  2. 2. 2년 조금 넘는 기간 동안, 스타트업에서 이것저것 개발하며 배운 것 중, 공유하고 싶은 것이 있어서 발표를 하게 되었습니다.
  3. 3. ‘캠쿠’ 대학생활 개선 앱 ‘트웬티’ 대학생 미디어 ‘ALT’ 뉴미디어 스타트업 RESTful API CMS (Contents Management System)
  4. 4. ‘트웬티’ 앱을 개발하던 2015년 9월쯤, Python과 Django를 알게 됐고, 덕분에 RESTful API와 CMS를 쉽고 빠르게 만들 수 있었습니다.
  5. 5. 그런데, 6개월이 지나서야 Django admin site의 존재를 알게 됐습니다. CMS를 모두 다 구현하고 난 뒤에…
  6. 6. Django admin site를 커스텀해서 사용하는 것이, 직접 만든 CMS 보다 훨씬 쉽고, 빠르고, 안정적이었습니다.
  7. 7. 이번 파이콘 주제가 ‘Back to the basic’ 인 걸 보고, 경험을 공유하고 싶다는 생각이 들었습니다.
  8. 8. 이 발표에서 다루는 내용 • Django admin site의 기본적인 사용 방법 • Django admin site를 커스텀 하는 여러가지 방법과 그 결과 • Python • Django 내부 동작, 구현
  9. 9. 들어가기 전에… Django ? • Documentation • Middleware • Model (ORM) • Form • Class based view • Template Django admin site
  10. 10. 발표의 모든 내용은 여기에 있습니다. • https://docs.djangoproject.com/en/1.11/ref/contrib/admin • ModelAdmin, InlineModelAdmin, AdminSite, LogEntry • Overriding admin templates, Reversing admin urls • https://docs.djangoproject.com/en/1.11/ref/contrib/admin/actions/ • Writing actions, Advanced action techniques • https://docs.djangoproject.com/en/1.11/ref/contrib/admin/admindocs/ • https://docs.djangoproject.com/en/1.11/ref/contrib/admin/javascript/
  11. 11. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  12. 12. 예제를 위한 모델 MEMBER name 이름 email 이메일 permission 권한 certification_date 인증일 is_certificated 인증상태 POST member 작성자 category 카테고리 title 제목 subtitle 부제목 content 내용 is_deleted 삭제여부 created_at 작성일 COMMENT member 작성자 post 원글 content 내용 report_count 신고수 created_at 작성일 CATEGORY name 이름 * permission (관리자, 에디터, 일반)
  13. 13. 예제를 위한 모델 - Member class Member(AbstractBaseUser): TYPE_PERMISSIONS = ( ('AD', '관리자'), ('ET', '에디터'), ('MB', '일반'), ) email = models.EmailField('이메일', max_length=255, unique=True) username = models.CharField('닉네임', max_length=30) permission = models.CharField('권한', max_length=2, choices=TYPE_PERMISSIONS, default='MB') certification_date = models.DateField('인증일', default=None, null=True, blank=True) is_certificated = models.BooleanField('인증여부', default=False)
  14. 14. 예제를 위한 모델 - Post class Category(models.Model): name = models.CharField('카테고리 이름', max_length=20) class Post(models.Model): member = models.ForeignKey(Member, verbose_name='작성자') category = models.ForeignKey(Category, verbose_name='카테고리') title = models.CharField('제목', max_length=255) content = models.TextField('내용') is_deleted = models.BooleanField('삭제된 글', default=False) created_at = models.DateTimeField('작성일', auto_now_add=True) class Comment(models.Model): member = models.ForeignKey(Member, verbose_name='작성자') post = models.ForeignKey(Post, verbose_name=‘원본글’) content = models.TextField() is_blocked = models.BooleanField('노출 제한', default=False)
  15. 15. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  16. 16. Django 설치 example $ pyenv virtualenv 3.6.2 pyconExample # 가상 환경 추가 example $ pyenv shell envExample # 가상 환경 실행 (envExample) example $ pip install django # django 설치 (envExample) example $ django-admin.py startproject example # django 프로젝트 생성 (envExample) example $ python manage.py startapp member # member, post 앱 추가 (envExample) example $ python manage.py startapp post (envExample) example $ python manage.py createsuperuser # 관리자 추가 (envExample) example $ python manage.py runserver # 실행 http://localhost:8000 http://localhost:8000/admin/
  17. 17. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  18. 18. Model을 admin site에 등록 # member/admin.py from django.contrib import admin from member.models import Member admin.site.register(Member) # post/amdin.py from django.contrib import admin from post.models import Category, Post, Comment admin.site.register(Post) admin.site.register(Category) admin.site.register(Comment)
  19. 19. Model을 admin site에 등록 # post/models.py class Category(models.Model): class Meta: verbose_name_plural = "categories" name = models.CharField(max_length=20)
  20. 20. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  21. 21. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin):
  22. 22. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5
  23. 23. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', )
  24. 24. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', ) list_editable = ('permission', )
  25. 25. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', ) list_editable = ('permission', ) list_filter = ('permission', )
  26. 26. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', ) list_editable = ('permission', ) list_filter = ('permission', ) search_fields = ('username', )
  27. 27. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', ) list_editable = ('permission', ) list_filter = ('permission', ) search_fields = ('username', ) ordering = ('-id', 'email', 'permission', )
  28. 28. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', ) list_editable = ('permission', ) list_filter = ('permission', ) search_fields = ('username', ) ordering = ('-id', 'email', 'permission', ) def post_count(self, obj): return Post.objects.filter(member=obj).count() post_count.short_description = '작성한 글 수'
  29. 29. 기본 - List # member/admin.py class MemberAdmin(admin.ModelAdmin): list_per_page = 5 list_display = ( 'id', 'email', ‘username', 'permission', ‘is_certificated', ‘certification_date’, ‘post_count', ) list_editable = ('permission', ) list_filter = ('permission', ) search_fields = ('username', ) ordering = ('-id', 'email', 'permission', ) def post_count(self, obj): return Post.objects.filter(member=obj).count() post_count.short_description = '작성한 글 수' admin.site.register(Member, MemberAdmin)
  30. 30. 기본 - Form # post/admin.py class PostAdmin(admin.ModelAdmin): list_per_page = 10 list_display = ( 'id', 'title', ‘member', 'is_deleted', 'created_at', ) list_editable = ('is_deleted', ) list_filter = ( ‘member__permission', 'category__name', 'is_deleted', ) fields = ('member', 'category', 'title', ) admin.site.register(Category) admin.site.register(Post, PostAdmin) admin.site.register(Comment)
  31. 31. 기본 - Form # post/admin.py class PostAdmin(admin.ModelAdmin): . . . fieldsets = ( ('기본 정보', { 'fields': (('member', 'category', ), ) }), ('제목 및 내용', { 'fields': ( 'title', 'subtitle', ‘content', ) }), ('삭제', { 'fields': ('is_deleted', 'deleted_at', ) }) ) . . .
  32. 32. 기본 - Custom Validation # post/forms.py class MyPostAdminForm(forms.ModelForm): def clean_content(self): # clean_{field_name} ModelForm Documentation https://docs.djangoproject.com/en/1.11/topics/forms/modelforms
  33. 33. 기본 - Custom Validation # post/forms.py class MyPostAdminForm(forms.ModelForm): def clean_content(self): # clean_{field_name} content = self.cleaned_data['content'] words = ['심심하다', ‘관리자’, ‘금지어’, ] error_message = '[{0}] {1}'.format(', '.join(words), ‘와…’) if any(word in content for word in words): raise forms.ValidationError(error_message) return content ModelForm Documentation https://docs.djangoproject.com/en/1.11/topics/forms/modelforms
  34. 34. 기본 - Custom Validation # post/forms.py class MyPostAdminForm(forms.ModelForm): def clean_content(self): # clean_{field_name} content = self.cleaned_data['content'] words = ['심심하다', ‘관리자’, ‘금지어’, ] error_message = '[{0}] {1}'.format(', '.join(words), ‘와…’) if any(word in content for word in words): raise forms.ValidationError(error_message) return content # post/admin.py class PostAdmin(admin.ModelAdmin): form = MyPostAdminForm . . . ModelForm Documentation https://docs.djangoproject.com/en/1.11/topics/forms/modelforms
  35. 35. 기본 - Custom Validation # post/forms.py class MyPostAdminForm(forms.ModelForm): def clean_content(self): # clean_{field_name} content = self.cleaned_data['content'] words = ['심심하다', ‘관리자’, ‘금지어’, ] error_message = '[{0}] {1}'.format(', '.join(words), ‘와…’) if any(word in content for word in words): raise forms.ValidationError(error_message) return content # post/admin.py class PostAdmin(admin.ModelAdmin): form = MyPostAdminForm . . . ModelForm Documentation https://docs.djangoproject.com/en/1.11/topics/forms/modelforms [심심하다, 관리자, 금지어]와 같은 단어들은 입력하실 수 없습니다.
  36. 36. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  37. 37. 심화 - Custom list filter # post/filters.py class CreatedDateFilter(admin.SimpleListFilter): title = '작성일' parameter_name = 'date' def lookups(self, request, model_admin): results = [] for i in range(-3, 6): date = datetime.date.today() + datetime.timedelta(days=i) display_str = '{0} [{1}개]'.format( date, Post.objects.filter(created_at__date=date).count() ) display_str += ' - 오늘' if i == 0 else '' results.append((date, display_str)) return results def queryset(self, request, queryset): if self.value(): return queryset.filter(created_at__date=self.value()) else: return queryset.all()
  38. 38. 심화 - Custom list filter # post/filters.py class CreatedDateFilter(admin.SimpleListFilter): title = '작성일' parameter_name = 'date' def lookups(self, request, model_admin): results = [] for i in range(-3, 6): date = datetime.date.today() + datetime.timedelta(days=i) display_str = '{0} [{1}개]'.format( date, Post.objects.filter(created_at__date=date).count() ) display_str += ' - 오늘' if i == 0 else '' results.append((date, display_str)) return results def queryset(self, request, queryset): if self.value(): return queryset.filter(created_at__date=self.value()) else: return queryset.all()
  39. 39. 심화 - Custom list filter # post/filters.py class CreatedDateFilter(admin.SimpleListFilter): title = '작성일' parameter_name = 'date' def lookups(self, request, model_admin): results = [] for i in range(-3, 6): date = datetime.date.today() + datetime.timedelta(days=i) display_str = '{0} [{1}개]'.format( date, Post.objects.filter(created_at__date=date).count() ) display_str += ' - 오늘' if i == 0 else '' results.append((date, display_str)) return results def queryset(self, request, queryset): if self.value(): return queryset.filter(created_at__date=self.value()) else: return queryset.all()
  40. 40. 심화 - Custom action # member/admin.py from member.forms import SetCertificationDateForm class MemberAdmin(admin.ModelAdmin): actions = ['set_certification_date'] action_form = SetCertificationDateForm # SelectDateWidget
  41. 41. 심화 - Custom action # member/admin.py from member.forms import SetCertificationDateForm class MemberAdmin(admin.ModelAdmin): actions = ['set_certification_date'] action_form = SetCertificationDateForm # SelectDateWidget def set_certification_date(self, request, queryset): year, month, day = . . . # POST Request에서 값을 꺼냄 if year and month and day: date_str = '{0}-{1}-{2}'.format(year, month, day) date = strptime(date_str, "%Y-%d-%m").date() for member in queryset: Member.objects .filter(id=member.id) .update(is_certificated=True, certification_date=date) messages.success(request, '{0}명의 회원을 인증했습니다.'.format(len(queryset))) else: messages.error(request, '날짜가 선택되지 않았습니다.')
  42. 42. 심화 - Custom action # member/admin.py from member.forms import SetCertificationDateForm class MemberAdmin(admin.ModelAdmin): actions = ['set_certification_date'] action_form = SetCertificationDateForm # SelectDateWidget def set_certification_date(self, request, queryset): year, month, day = . . . # POST Request에서 값을 꺼냄 if year and month and day: date_str = '{0}-{1}-{2}'.format(year, month, day) date = strptime(date_str, "%Y-%d-%m").date() for member in queryset: Member.objects .filter(id=member.id) .update(is_certificated=True, certification_date=date) messages.success(request, '{0}명의 회원을 인증했습니다.'.format(len(queryset))) else: messages.error(request, '날짜가 선택되지 않았습니다.') set_certification_date.short_description = '선택된 유저를 해당 날짜 기준으로 인증합니다.'
  43. 43. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  44. 44. 페이지 추가하기 # post/admin.py class PostAdmin(admin.ModelAdmin): def get_urls(self): urls = super(PostAdmin, self).get_urls() post_urls = [ url(r'^status/$', self.admin_site.admin_view(self.post_status_view)) ] return post_urls + urls def post_status_view(self, request): context = dict( self.admin_site.each_context(request), posts=Post.objects.all(), key1=value1, key2=value2, ) return TemplateResponse(request, "admin/post_status.html", context)
  45. 45. 페이지 추가하기 # post/admin.py class PostAdmin(admin.ModelAdmin): def get_urls(self): urls = super(PostAdmin, self).get_urls() post_urls = [ url(r'^status/$', self.admin_site.admin_view(self.post_status_view)) ] return post_urls + urls def post_status_view(self, request): context = dict( self.admin_site.each_context(request), posts=Post.objects.all(), key1=value1, key2=value2, ) return TemplateResponse(request, "admin/post_status.html", context)
  46. 46. 페이지 추가하기 # post/admin.py class PostAdmin(admin.ModelAdmin): def get_urls(self): urls = super(PostAdmin, self).get_urls() post_urls = [ url(r'^status/$', self.admin_site.admin_view(self.post_status_view)) ] return post_urls + urls def post_status_view(self, request): context = dict( self.admin_site.each_context(request), posts=Post.objects.all(), key1=value1, key2=value2, ) return TemplateResponse(request, "admin/post_status.html", context)
  47. 47. 페이지 추가하기 # templates/admin/post_status.html {% extends "admin/base_site.html" %} {% block content %} <h2>Post Status</h2> <ul> {% for post in posts %} <li>{{ post.title }}</li> {% endfor %} </ul> {% endblock %} http://localhost:8000/admin/post/post/status/
  48. 48. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  49. 49. UI 변경하기 ├── example # Project Directory │   ├── assets │   │   └── admin │   │   ├── css │   │   │   ├── custom.css # 전체 레이아웃을 수정하는 CSS │   │   │   ├── dropdown.css # 상단 메뉴바에 드롭다운 메뉴를 적용하기 위한 CSS • https://github.com/bbayoung/django-admin-site-custom-example/blob/master/example/assets/admin/css/custom.css • https://github.com/bbayoung/django-admin-site-custom-example/blob/master/example/assets/admin/css/dropdown.css # example/settings.py . . . STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'assets'), ) . . .
  50. 50. • https://github.com/django/django/ UI 변경하기 ├── admin │   ├── templates │   │   ├── admin │   │   │   ├── 404.html │   │   │   ├── 500.html │   │   │   ├── actions.html │   │   │   ├── app_index.html │   │   │   ├── auth │   │   │   ├── base.html │   │   │   ├── base_site.html │   │   │   ├── change_form.html │   │   │   └── index.html base.html base_site.html app_index.htmlindex.html login.html
  51. 51. # templates/admin/base_site.html {% extends "admin/base.html" %} {% load static %} {% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} {% block extrastyle %} {% endblock %} {% block branding %} <h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1> {% endblock %} {% block nav-global %}{% endblock %} UI 변경하기
  52. 52. # templates/admin/base_site.html {% extends "admin/base.html" %} {% load static %} {% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} {% block extrastyle %} <link rel="stylesheet" type="text/css" href="{% static "admin/css/dropdown.css" %}" /> <link rel="stylesheet" type="text/css" href="{% static "admin/css/custom.css" %}" /> {% endblock %} {% block branding %} <h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1> {% endblock %} {% block nav-global %}{% endblock %} UI 변경하기 # example/settings.py admin.site.site_title = '파이콘 한국 2017’ # 브라우저 타이틀 admin.site.site_header = 'Back to the basic’ # 웹사이트 header 부분 타이틀
  53. 53. UI 변경하기
  54. 54. UI 변경하기
  55. 55. # example/context_processors.py def gnb_menus(request): menus = [ { 'name': '회원', 'sub_menus': [ {'name': '관리자', 'url': '/admin/member/member/?permission__exact=AD'}, {'name': '에디터', 'url': '/admin/member/member/?permission__exact=ET'}, {'name': '일반', 'url': '/admin/member/member/?permission__exact=MB'}, ] }, { 'name': ' 글 ', 'sub_menus': [ {'name': 'GENDER', 'url': '/admin/post/post/?category__name=GENDER'}, {'name': 'SOCIAL', 'url': '/admin/post/post/?category__name=SOCIAL'}, {'name': 'POLITICS', 'url': '/admin/post/post/?category__name=POLITICS'}, {'name': '통계', 'url': '/admin/post/post/status/'}, ] } ] return {'gnb_menus': menus} UI 변경하기
  56. 56. # example/settings.py TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, "templates")], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ‘example.context_processors.gnb_apps', # 장고에 추가한 기본 앱 메뉴 ‘example.context_processors.gnb_menus', # 이전 페이지에서 직접 정의한 상단 메뉴 ], }, }, ] UI 변경하기
  57. 57. # templates/admin/base_site.html {% block nav-global %} <div id="gnb"> <div id="gnb-app-list"> <ul class="drop-down-menu"> {% for menu in gnb_menus %} // 커스텀 메뉴 출력 - - - - - - - - - - - - - (1) {% endfor %} {% if gnb_apps %} // Django 전체 모델 출력 - - - - - - - - - (2) {% endif %} </ul> </div> </div> {% endblock %} UI 변경하기
  58. 58. # templates/admin/base_site.html . . . (1) {% for menu in gnb_menus %} <li> <a {% if menu.url %}href="{{ menu.url }}"{% endif %}>{{ menu.name }}</a> <ul> {% for sub_menu in menu.sub_menus %} <li><a href="{{ sub_menu.url }}">{{ sub_menu.name }}</a></li> {% endfor %} </ul> </li> {% endfor %} . . . UI 변경하기
  59. 59. # templates/admin/base_site.html . . . (2) {% if gnb_apps %} <li><a>전체 앱</a> <ul> {% for app in gnb_apps %} <li><a href="/admin/{{ app.app_url }}">{{ app.name }}</a> <ul> {% for model in app.models %} <li><a href="{{ model.admin_url }}">{{ model.name }}</a></li> {% endfor %} </ul> </li> {% endfor %} </ul> </li> {% endif %} . . . UI 변경하기
  60. 60. UI 변경하기
  61. 61. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  62. 62. Django admin site 분리하기 # post/admin.py from django.contrib.admin import AdminSite class CommentAdminSite(AdminSite): site_header = 'Comment administration' comment_admin = CommentAdminSite(name='comment admin') comment_admin.register(Comment, CommentAdmin)
  63. 63. Django admin site 분리하기 # post/admin.py from django.contrib.admin import AdminSite class CommentAdminSite(AdminSite): site_header = 'Comment administration' comment_admin = CommentAdminSite(name='comment admin') comment_admin.register(Comment, CommentAdmin) # example/urls.py urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^admin/comment/', comment_admin.urls), ]
  64. 64. 순서 1.Django 설치 2.Model을 admin site에 등록하기 3.기본적인 사용법 4.조금 더 심화된 사용법 5.커스텀 페이지 추가 6.UI 변경하기 7.Admin site 분리하기 8.마지막으로 (간단한) 문서화!
  65. 65. 문서화 (envExample) example $ pip install docutils # docutils 설치 # example/urls.py urlpatterns = [ . . . url(r'^admin/doc/', include('django.contrib.admindocs.urls')), . . . ] # example/settings.py INSTALLED_APPS = [ . . . 'django.contrib.admindocs', . . . ]
  66. 66. 문서화 # post/models.py class Comment(models.Model): """ 사용들이 작성한 글에 대한 댓글입니다. 댓글은 :model:`post.Post` 와 :model:`member.Member`. 모델과 1:N 관계입니다. """ member = models.ForeignKey(Member, verbose_name='작성자') post = models.ForeignKey(Post, verbose_name='원본글') content = models.TextField(verbose_name='내용', help_text='댓글 내용입니다.')
  67. 67. • 시간이 길지 않아, 준비한 내용은 여기까지입니다. • 이 외에도 공식 문서에 추가적인 커스텀 방법들이 소개되어 있습니다. • 예제 코드는 아래에서 확인하실 수 있습니다.
 https://github.com/bbayoung/django-admin-site-custom-example 감사합니다.

×