Backend/Django

[파이썬] Django - SNS 기초 실습 7) tag (django-taggit)

Sungwoo Koo 2022. 5. 30. 23:49

 

taggit 모듈 사전 준비

1. Django 태그 모듈 설치

$ pip install django-taggit

$ pip install django-taggit-templatetags2

 

2. project/settings.py 에서 install한 모듈 등록 및 설정 추가

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tweet',
    'user',
    'restaurant',
    'taggit.apps.TaggitAppconfig',
    'taggit_templatetags2',
]

TAGGIT_CASE_INSENSITIVE = True
TAGGIT_LIMIT = 50

 

3. tweet/models.py의 TweetModel 클래스에 TaggableManager 객체 선언

# Create your models here.
class TweetModel(models.Model):
    class Meta:
        db_table = "tweet"

    author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
    content = models.CharField(max_length=256)
    tags = TaggableManager(blank=True)  # TaggableManager 선언 (blank=True: 비어있어도 작동)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

4. 변경한 models.py 내용 적용

$ python manage.py makemigrations

$ python manage.py migrate

 

taggit 모듈 사용

1. tweet/views.py의 tweet 메서드 수정

def tweet(request):
    if request.method == 'GET':
        user = request.user.is_authenticated  # is_authenticated : 로그인 되어 있는지 검사
        if user:
            all_tweet = TweetModel.objects.all().order_by('-created_at')  # -created_at : created_at 기준 역순 (최신 먼저)
            return render(request, 'tweet/home.html', {'tweet': all_tweet})  # 로그인 한 사용자라면 home.html 이동
        else:
            return redirect('/sign-in')  # 로그인 하지 않은 사용자라면 로그인 페이지로 이동

    elif request.method == 'POST':
        user = request.user  # 지금 로그인 되어있는 사용자의 정보 전체를 가져온다
        content = request.POST.get('my-content', '')
        tags = request.POST.get('tag', '').split(',')

        # 내용이 비어있을 경우
        if content == '':
            all_tweet = TweetModel.objects.all().order_by('-created_at')
            return render(request, 'tweet/home.html', {'error': '내용을 입력해주세요', 'tweet': all_tweet})
        else:
            my_tweet = TweetModel.objects.create(author=user, content=content)
            for tag in tags:
                tag = tag.strip() # strip() : 공백 제거
                if tag != '':
                    my_tweet.tags.add(tag)

            my_tweet.save()
            return redirect('/tweet')

 

2. tweet/views.py에 클래스 추가


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

 

3. tweet/ulrs.py path 추가

path('tag/', views.TagCloudTV.as_view(), name='tag_cloud'),
path('tag/<str:tag>/', views.TaggedObjectLV.as_view(), name='tagged_object_list'),

 

4. templates/tweet/home.html 수정

{% extends 'base.html' %}
{% block title %}
    메인페이지
{% endblock %}

{% block content %}
    <div class="container timeline-container">
        <div class="row">
            <!-- 왼쪽 컬럼 -->
            <div class="col-md-3">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">{{ user.username }}</h5>
                        <p class="card-text"> {{ user.bio }}</p>

                    </div>
                </div>
            </div>
            <!-- 오른 쪽 컬럼-->
            <div class="col-md-7">
                <!-- 글을 작성 하는 곳 -->
                <div class="row mb-2">
                    <div class="col-md-12">
                        <div class="card">
                            <div class="card-body">
                                <div class="media">
                                    <div class="media-body">
                                        <h5 class="mt-0">나의 이야기를 적어주세요</h5>
                                        <p>
                                        <form action="/tweet/" method="post">
                                            {% csrf_token %}
                                            {% if error %}
                                                <div class="alert alert-danger" role="alert">
                                                    {{ error }}
                                                </div>
                                            {% endif %}
                                            <div class="form-group mb-2">
                                                <textarea class="form-control" style="resize: none" name='my-content'
                                                          id="my-content"></textarea>
                                                <div class="mt-3 row">
                                                    <label for="tag"
                                                           class="col-sm-2 col-form-label">이 글의 태그</label>
                                                    <div class="col-sm-10">
                                                        <input type="text" class="form-control" name="tag" id="tag"
                                                               placeholder="콤마(,)로 구분 해 주세요">
                                                    </div>
                                                </div>
                                            </div>
                                            <button type="submit" class="btn btn-primary" style="float:right;">작성하기
                                            </button>
                                        </form>
                                        </p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <hr>
                <!-- 작성 된 글이 나오는 곳 -->
                <div class="row">
                    {% for tw in tweet %}
                        <div class="col-md-12 mb-2">
                            <div class="card">
                                <div class="card-body">
                                    {% if tw.author == user %}
                                        <div style="text-align: right">
                                            <a href="/tweet/delete/{{ tw.id }}">
                                                <span class="badge rounded-pill bg-danger">삭제</span>
                                            </a>
                                        </div>
                                    {% endif %}
                                    <div style="text-align: right">
                                        <a href="/tweet/{{ tw.id }}">
                                            <span class="badge rounded-pill bg-success">보기</span>
                                        </a>
                                    </div>

                                    <div class="media">
                                        <div class="media-body">
                                            <h5 class="mt-0">{{ tw.content }}</h5>
                                            {% 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 %}
                                        </div>
                                        <div style="text-align: right">
                                            <span style="font-size: small">{{ tw.author.username }}-{{ tw.created_at|timesince }} 전</span>
                                        </div>

                                    </div>
                                </div>
                            </div>
                        </div>
                    {% endfor %}
                </div>
            </div>
            <div class="col-md-2"></div>
        </div>
    </div>
{% endblock %}

 

5. templates/tweet/tweet_detail.html 수정

{% extends 'base.html' %}

{% block title %}
    게시글 자세히보기
{% endblock %}

{% block content %}
    <div class="container timeline-container">
        <div class="row">
            <!-- 왼쪽 컬럼 -->
            <div class="col-md-3">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">{{ user.username }}</h5>
                        <p class="card-text"> {{ user.bio }}</p>

                    </div>
                </div>
            </div>
            <!-- 오른 쪽 컬럼-->
            <div class="col-md-7">
                <div class="row">
                    <div class="col-md-12 mb-2">
                        <div class="card">
                            <div class="card-body">
                                {% if tweet.author == user %}
                                    <div style="text-align: right">
                                        <a href="/tweet/delete/{{ tweet.id }}">
                                            <span class="badge rounded-pill bg-danger">삭제</span>
                                        </a>
                                    </div>
                                {% endif %}
                                <div class="media">
                                    <div class="media-bod">
                                        <h5 class="mt-0">{{ tweet.content }}</h5>
                                        {% if tweet.tags.all %}
                                            {% for tag in tweet.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 %}
                                    </div>
                                    <div style="text-align: right">
                                        <span style="font-size: small">{{ tweet.author.username }}-{{ tweet.created_at|timesince }} 전</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <!-- 글 작성 하는 곳 -->
                <form class="input-group mb-3" action="/tweet/comment/{{ tweet.id }}" method="post">
                    {% csrf_token %}
                    <input type="text" class="form-control" id='comment' name='comment' placeholder="댓글을 작성 해 주세요"/>
                    <button class="btn btn-outline-secondary" type="submit">작성</button>
                </form>

                <hr>
                <!-- 반복문이 들어 갈 곳 -->
                {% for cm in comment %}
                    <div class="row">
                        <div class="col-md-12">
                            <div class="media">
                                <div class="media-body">
                                    <h5 class="mt-0"> {{ cm.comment }} </h5>
                                    <span> {{ cm.author }}</span>
                                    <span> - {{ cm.created_at | timesince }} 전</span>
                                </div>
                                {% if cm.author == user %}
                                    <div style="float: right">
                                        <a href="/tweet/comment/delete/{{ cm.id }}">
                                            <span class="badge bg-danger">삭제</span>
                                        </a>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </div>
                    <hr>
                {% endfor %}
                <!-- 반복문이 끝난 곳 -->
            </div>
        </div>
    </div>
{% endblock %}