59 트리구조 메뉴 만들기- treebeard
59.1 django-treebeard 패키지 설치 및 셋팅파일 설정
패키지는 아래 명령어로 설치합니다.
pip install django-treebeard
패키지 설치가 완료되었으면 셋팅파일에 추가합니다.
DJANGO_BASE_APP = [
...
'django.contrib.sitemaps',
'markdownx',
'treebeard',
]
MY_APP =['myapp.blog','myapp.coding']
INSTALLED_APPS = DJANGO_BASE_APP + MY_APP
59.2 모델 수정하기 - models.py
MP_Node 를 import하고 상속 받습니다.
node_order_by 기준을 regist_dt로 정했습니다.
get_prev_sibling와 get_next_sibling는
현재 글의 같은 카테고리에서
이전 글과 다음 글을 가져오는 기능입니다.
더 많은 함수는 아래 링크에서 확인하시면 됩니다.
https://django-treebeard.readthedocs.io/en/latest/api.html
#myapp/coding/model.py
from django.db import models
from django.urls import reverse
from markdownx.models import MarkdownxField
from markdownx.utils import markdownify
from treebeard.mp_tree import MP_Node
IMG_SIZE_CHOICES = {(30,'30%'),(40, '40%'),(50, '50%'),(70, '70%'),(100, '100%')}
class PyCoding(MP_Node):
id = models.AutoField(primary_key=True)
tags = models.CharField(max_length=200)
title = models.CharField(max_length=100)
sub_title = models.CharField(max_length=100, blank=True, null=True)
img_url = models.CharField(max_length=200, blank=True, null=True)
img_size = models.IntegerField(choices=IMG_SIZE_CHOICES, null=False, blank=False)
#content_body = models.TextField(null=False, blank=False)
content_body = MarkdownxField()
update_dt = models.DateTimeField(auto_now=True)
regist_dt = models.DateTimeField(auto_now_add=False)
node_order_by = ['regist_dt']
def get_absolute_url(self):
if not self.is_root():
return reverse('coding:coding_detail', kwargs={'pk':self.pk} )
def get_previous(self):
if not self.is_root():
return self.get_prev_sibling()
def get_next(self):
if not self.is_root():
return self.get_next_sibling()
def get_is_root(self):
return self.is_root()
def __str__(self):
return self.title
class Meta:
db_table = 'py_coding'
59.3 관리자 추가하기 - admin.py
#myapp/coding/admin.py
from django.contrib import admin
from markdownx.admin import MarkdownxModelAdmin
from markdownx.widgets import AdminMarkdownxWidget
from markdownx.models import MarkdownxField
from .models import PyCoding
from treebeard.forms import movenodeform_factory
from treebeard.admin import TreeAdmin
class CategoryAdmin(TreeAdmin):
form = movenodeform_factory(PyCoding)
admin.site.register(PyCoding, CategoryAdmin)
59.4 뷰 수정하기 - views.py
common_views.py의 menuMixin 클래스를
상속 받아 context[]coding_menu]로 담았습니다.
#myapp/common/views.py
from django.utils.functional import cached_property
from myapp.blog.models import PyBlog, PyBlogDetail
from myapp.coding.models import PyCoding
import logging as log
class menuMixin(object):
@cached_property
def getMenuList(self):
return {"blog_menu":PyBlog.objects.all(),
"coding_menu": PyCoding.objects.all()}
#myapp/coding/views.py
from django.shortcuts import render
from django.views import generic
from .models import PyCoding
#sidebar
from myapp.common.common_views import menuMixin
class codingDetail(menuMixin, generic.DetailView):
model = PyCoding
def get_context_data(self, **kwargs):
context = super(codingDetail, self).get_context_data(**kwargs)
queryset = PyCoding.objects.get(id=self.kwargs['pk'])
context['pageInfo'] = queryset
context['blog_menu'] = self.getMenuList['blog_menu']
context['coding_menu'] = self.getMenuList['coding_menu']
return context
59.5 좌측메뉴 수정하기 - sidebar.html
if list.is_root로 여부로 부모와 자식을 구분합니다.
<li id="menu_coding" class="nav-item" >
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities"
aria-expanded="true" aria-controls="collapseUtilities">
<i class="fas fa-fw fa-wrench"></i>
<span>Python 코딩</span>
</a>
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
{% for list in coding_menu %}
{% if list.is_root %}
<h6 class="collapse-header">{{list.title}} </h6>
{% endif%}
{% if not list.is_root %}
<a id="col-item-coding{{list.id}}" class="collapse-item pl-4" href=" {{ list.get_absolute_url }}" >{{list.title}}</a>
{% endif%}
{% endfor %}
</div>
</div>
</li>
59.6 상세페이지 수정하기 - pycoding_detail.html
우측 서브메뉴와 하단 이전,다음글 부분입니다.
model에 정의한
get_absolute_url, get_previous, get_next 함수를 이용하여 구현 하였습니다.
{% if pageInfo.get_previous or pageInfo.get_next %}
<div class="col-lg-4 mb-4">
<div id="right_menu" class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col">
{% if pageInfo.get_previous %}
<div>
<span class="h6 mb-1 font-weight-bold anchor_link">
<a href="{{pageInfo.get_previous.get_absolute_url}}">{{pageInfo.get_previous}}</a>
</span>
</div>
{% endif %}
<hr class="d-none d-md-block">
<div> <span class="h6 mb-1 font-weight-bold anchor_link"><a href="#{{pageInfo.title}}">{{pageInfo.title}}</a></span></div>
<div>
<span class="h6 mb-1 font-weight-bold anchor_link active">
<a href="#{{pageInfo.sub_title}}">{{pageInfo.sub_title}}</a>
</span>
</div>
<hr class="d-none d-md-block">
{% if pageInfo.get_next %}
<div>
<span class="h6 mb-1 font-weight-bold anchor_link">
<a href="{{pageInfo.get_next.get_absolute_url}}">{{pageInfo.get_next}}</a>
</span>
</div>
{% endif %}
</div><!--<div class="col mr-2">-->
</div>
</div>
</div>
</div>
</div>
{% endif %}
</div>
<div class="row">
<div class="col-lg-8 mb-4">
<div class="card shadow mb-4">
{% if pageInfo.get_previous %}
<div class="card-body"><span class="font-weight-bold text-gray-800">이전글</span> : <span class=" text-primary font-weight-bold"> <a href="{{pageInfo.get_previous.get_absolute_url}}">{{pageInfo.get_prev_sibling}}</a></span></div>
{% endif %}
{% if pageInfo.get_next %}
<div class="card-body"><span class="font-weight-bold text-gray-800">다음글</span> : <span class=" text-primary font-weight-bold"><a href="{{pageInfo.get_next.get_absolute_url}}">{{pageInfo.get_next_sibling}}</a> </span></div>
{% endif %}
</div>
</div>
</div>
59.7 브라우저에서 확인하기
현재글 : 59 트리구조 메뉴 만들기- treebeard
Comments
Login: