장고로 트윗에 태그를 달아주는 작업을 하던 도중 궁금한 점이 생겼다.
tweet 과 관련된 모델이니 tweet의 models.py/TweetModel 에 tags = TaggableManager(blank=True)
을 추가해주고 views.py에 Tag 관련 클래스들을 추가해줬다.
tweet/views.py
# import ...
from taggit.managers import TaggableManager
from django.views.generic import ListView, TemplateView
# generic 모델은 명시된 모든 모델(TweetModel)을 가져오기 위해 데이터베이스를 쿼리
class TagCloudTV(TemplateView):
template_name = 'taggit/tag_cloud_view.html'
class TaggedObjectLV(ListView):
template_name = 'taggit/tag_with_post.html'
model = TweetModel()
def get_queryset(self):
return TweetModel.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
여기서 generic 모델이란 무엇이고, get_context_data() 는 무엇인가?
우선 generic 은 장고에서 기본적으로 제공하는 클래스이다. 데이터베이스에 있는 데이터들을 보여줄 때 사용하기 좋으며 generic display view 에는 ListView, DetailView, TemplateView 등이 있다. 자세한 상속 관계와 사용 예시는 여기
위의 코드에서는 ListView 를 사용하며 template_name 으로 어떤 html 을 사용할 것인지 알려주었다. (속성이 없다면 장고가 모델 이름에서 유추하여 모델이름_list.html 을 찾아내 보여준다.)
model = TweetModel() 을 통해 object_list 의 형태로 TweetModel() 객체가 전달될 것임을 알 수 있다.
이 다음 get_context_data() 를 재정의하여 {'tagname' : tag} 의 형태로 데이터를 return 하여 준다.
templates/taggit/tag_with_post.html
{% extends "base.html" %}
{% block title %}태그 글 리스트{% endblock %}
{% block content %}
<div class="container">
<h3 class="mt-2">Posts for tag - {{ tagname }}</h3>
<hr>
<div class="card">
<div class="card-body">
{% for tweet in object_list %}
<h4>
<a href="/tweet/{{ tweet.id }}">{{ tweet.content }}</a>
</h4>
{{ tweet.updated_at|timesince}}
<p> {{ tweet.author }}</p>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
이후 home.html 과 tweet_detail.html 의 textbox div 에
{% if tw.tags.all %}
{% for tw in tw.tags.all %}
<a style="text-decoration: none"
href="{% url 'tagged_object_list' tag.name %}">
<span class="badge rounded-pill bg-success">
{{ tag.name }}
</span>
</a>
{% endfor %}
-<a style="text-decoration: none"
href="{% url 'tag_cloud' %}">TagCloud</a>
{% endif %}
이걸 추가해줬는데
Reverse for 'tagged_object_list' with arguments '('',)' not found. 1 pattern(s) tried: ['tag/(?P[^/]+)\Z']
이런 에러가 뜨는 것이다. 찾아봤더니 전달되어야할 id 값이 제대로 전달되지 않았을 때 나는 에러라고 한다.
그리고 다시 보니... tag 라고 적었어야 할 for 문을 너무 자연스럽게 tw 라고 적어놨었다... ㅠㅠ
{% if tw.tags.all %}
{% for tag in tw.tags.all %}
<a style="text-decoration: none"
href="{% url 'tagged_object_list' tag.name %}">
<span class="badge rounded-pill bg-success">
{{ tag.name }}
</span>
</a>
{% endfor %}
-<a style="text-decoration: none"
href="{% url 'tag_cloud' %}">TagCloud</a>
{% endif %}
수정 결과
잘 출력된다!
ListView의 사용법을 익히셨군요! 오류도 잘 해결되어서 다행입니다~!