Django_web_project 개발일지2) tag기능 추가

Mongle·2020년 7월 24일
1

DjangoBoard

목록 보기
3/7

😺1.환경설정 setting.py

taggit 오픈소스를 사용해 tag기능을 추가해보자!!

GettingStart django-taggit
django tag기능 공식 문서 사이트

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bookmark.apps.BookmarkConfig',
    'blog.apps.BlogConfig',
    'taggit.apps.TaggitAppconfig',
    'taggit_templatetags2',
]
TAGGIT_CASE_INSENSITIVE = TRUE
TAGGIT_LIMIT = 50

🐱2. models.py

from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager

#중략

    modify_dt = models.DateTimeField('MODIFY DATE', auto_now=True)
    tags = TaggableManager(blank=True)

#중략

TaggableManager를 import한 후, 기존 Post 테이블에 tags 필드를 추가한다.

👩‍💻 TaggitManager에 대해서

django-taggit 패키지에 taggit 앱이 들어있고, taggit 앱의 디렉터리 하위의 manager.py 파일에 TaggableManager 클래스가 정의되어있다.

😽3. admin.py


admin.py

from django.contrib import admin
from blog.models import Post

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'modify_dt', 'tag_list')
    list_filter = ('modify_dt',)
    search_fields = ('title', 'content')
    prepopulated_fields = {'slug':('title',)}

    def get_queryset(self, request):
        return super().get_queryset(request).prefetch_related('tags')
    
    def tag_list(self, obj):
        teturn ', '.join(o.name for o in obj.tags.all())

list_display에 'tag_list'를 추가한 후, 메서드를 추가한다.

👩‍🏫 여기서 왜 두 메서드를 추가해야할까?

Post 레코드 리스트를 가져오는 get_queryset() 메소드를 오버라이딩 해야한다. 왜냐하면, Post 테이블과 Tag테이블이 ManyToMany 관계이므로, Tag 테이블의 관련 레코드를 한 번의 쿼리로 미리 가져오기 위함이다.
다대다 관계에서 쿼리 횟수를 줄여 성능을 높이고자 할 때 prefetch_related()메소드를 사용한다.
tag_list 항목에 보여줄 내용을 정의한다.

😺4. admin에서 db세팅 확인


Taggit app의 테이블이 생성되었다.


Post테이블에 Tags칼럼이 추가된 것을 확인할 수 있다.


tag테이블과 taggedIte테이블이 생성되었다.


여기까지가 db에 관련 세팅
makemigrations/migrate


😺5. URLconf 코딩

#/blog/tag/
path('tag/', views.TagCloudTV.as_view(), name='tag_cloud'),#TemplateView를 상속받아 정의
#/blog/tag/tagname/
path('tag/<str:tag>/', views.TaggedObjectLV.as_view(), name='tagged_object_list'),#ListView를 상속받아 정의

/blog/tag/ 요청을 처리할 url을 만들어주고 view의 TagCloudTV로 연결
/blog/tag/tag변수 요청을 처리할 url을 만들어주고 view의 TagObjectLV로 연결

🐱6. views 코딩

#TemplateView를 추가로 import한다.
from django.views.generic import ListView, DetailView,TemplateView

TemplateView 클래스형 제네릭 뷰를 임포트한다.

👩‍💻 짚고 넘어가기

제네릭 뷰와 관련해서 모르는 것이 많다.
어떤 메서드에는 TemplateView를 어떤 메서드에는 ListView를 매개변수로 넣어주는데 그 기준이 무엇인지, 제네릭뷰의 종류, 제네릭뷰를 왜 사용하는 것이고 어떻게 사용하는 것인지 알아보고 수정할 것!

class TagCloudTV(TemplateView):
    template_name - 'taggit/taggit_cloud.html'

class TaggedObjectLV(ListView):
    template_name = 'taggit/taggit_post_list.html'
    model = Post

    def get_queryset(self):
        return Post.objects.filter(tags_name=self.kwargs.get('tag'))
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['tagname'] = self.kwargs['tag']
        return context

👩‍💻 짚고 넘어가기

컨텍스트 변수를 템플릿 파일에 전달하기 위한 메서드라는 것은 알겠는데...
아마 ListView에 정의되어 있는 get_context_data()를 오버라이딩해서 super().get_context_data()를 호출해서 컨텍스트 변수를 구한 후, url에서 'tag'라는 파라미터 값으로 넘어온 값을 'tagname'이라는 이름으로 컨텍스트에 추가한다는 의미인 것 같다. --> 확인해보기

😽7. template 코딩

post_detail.html

<br>
    <div>
        <b>TAGS</b> <i class="fas fa-tag"></i>
        {% load taggit_templatetag2_tags %} <!--taggit_templatetag2_tags 모듈을 가져온다-->
        {% get_tags_for_object object as "tags" %} <!-- ** -->
        {% for tag in tags %}
        <a href="{% url 'blog:tagged_object_list' tag.name %}">{{tag.name}}</a>
        {% endfor %}
        &emsp;
        <a href="{% url 'blog:tag_cloud' %}"><span class="btn btn-info btn-sm">TagCloud</span></a>
    </div>

👉 object 객체(PostDV클래서형 뷰에서 넘겨주는 컨텍스트 변수로 특정 Post객체가 담겨있음)에 달려 있는 태그들의 리스트를 추출해서 tags템플릿 변수에 할당한다.

blog/taggit/taggit_cloud.html

{% extends "base.html" %}

{% block title %}taggit_cloud.html{% endblock %}

{% block extra-style %}
<style>
    .tag-cloud{
        width: 40%;
        margin-left: 30px;
        text-align: center;
        padding: 5px;
        border: 1px solid orange;
        background-color: #ffc;
    }
    .tag-1 {font-size: 12px}
    .tag-2 {font-size: 14px}
    .tag-3 {font-size: 16px}
    .tag-4 {font-size: 18px}
    .tag-5 {font-size: 20px}
    .tag-6 {font-size: 24px}
</style>
{% endblock %}

{% block content %}
    <h1>Blog Tag Cloud</h1>
    <br>

    <div class="tag-cloud">
        {% load taggit_templatetags2_tags %}
        {% get_tagcloud as tags %} <!--모든 태그 추출해서 tags변수에 할당-->
        {% for tag in tags %}
        <span class="tag-{{tag.weight|floatformat:0}}"> <!-- style 관련-->
            <a href="{% url 'blog:tagged_object_list' tag.name %}"> {{tag.name}}({{tag.num_times}})</a>
        </span>
        {% endfor %}
    </div>
{% endblock %}

🧐 태그 객체와 관련된 속성의 의미

  • {{tag.name}}
    : 태그의 이름
  • {{tag.num_times}}
    : 태그가 사용된 횟수
  • {{tag.weight}}
    : 태그의 중요도. tag_num_times의 값을 미리 정해놓은 값에 따라 1.0~6.0사이의 수로 변환한 수치
  • {{tag.weight|floatformat:0}}
    : '|' 오른쪽의 값은 필터의 역할을 한다. tag.weight를 반올림해서 정수형으로 바꾼 값을 의미한다.

taggit_post_list.html

{% extends "base.html" %}

{% block title %}taggit_post_list.html{% endblock %}

{% block content %}

<h1>Posts for tag - {{ tagname }}</h1>
<br>
{% for post in object_list %} <!-- object_list 객체는 TaggedObjectLV 클래스형 뷰에서 넘겨주는 컨텍스트 변수로서 Post 리스트가 담겨있음-->
    <h2><a href='{{ post.get_absolute_url }}'>{{ post.title }}</a></h2>
    {{ post.modify_dt|date:"N d, Y" }}
    <p> {{ post.description }}</p>
{% endfor %}

{% endblock %}

🐱8. tag기능 확인


게시물 하단에 태그가 병렬로 나열된다.
django라는 태그를 클릭하면


이렇게 해당 태그를 가지고있는 게시물들을 모아서 출력해준다.

이전 페이지의 TagCloud버튼을 클릭하면,

등록되어있는 태그 목록을 보여주는데 글씨 크기로 태그 등록 순위를 알 수 있다.

🦊마치며...

오픈소스를 사용해서 tag기능을 만들었다. 전체적인 웹의 구조는 어느정도 이해한 것 같다. 이제 세부적으로 taggit앱을 가져와서 화면에 적용시키는 것 까지의 과정을 여러번 보면서 익숙하게 만들어야겠다.
참고한 블로그

👆 한가지 더 👆

'_'과 '__'은 코드상으로 구분하기 정말 어렵다. 주석으로 상기시켜주면 좋을 것 같다.

profile
https://github.com/Jeongseo21

0개의 댓글