장고 유형별로 사용자 차단하기 (댓글 혹은 DM 차단 기능 구현)

소요 시간: 10분

오늘은 Django에서 사용자 차단 기능을 확장하는 방법에 대해 기록한다. 최근에 사용자 간의 소통을 보다 원활하게 하고 싶어서 차단 기능을 세분화하는 작업을 진행했다. 이제 사용자는 댓글만 차단할 수도 있고, DM만 차단할 수도 있는 기능을 추가했다.


1. 모델 수정

차단 기능을 구현하기 위해, 우선 Block 모델에 새로운 필드를 추가했다. 기존에는 단순히 사용자를 차단하는 기능만 있었는데, 이번에 block_type이라는 필드를 추가하여 차단 유형을 구분할 수 있게 만들었다.

from django.contrib.auth.models import User
from django.db import models

class Block(models.Model):
    COMMENT_BLOCK = 'comment'
    DM_BLOCK = 'dm'
    BOTH_BLOCK = 'both'

    BLOCK_CHOICES = [
        (COMMENT_BLOCK, 'Comment Only'),
        (DM_BLOCK, 'DM Only'),
        (BOTH_BLOCK, 'Both')
    ]

    blocker = models.ForeignKey(User, related_name='blocking', on_delete=models.CASCADE)
    blocked = models.ForeignKey(User, related_name='blocked', on_delete=models.CASCADE)
    block_type = models.CharField(max_length=10, choices=BLOCK_CHOICES, default=BOTH_BLOCK)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = ('blocker', 'blocked', 'block_type')

    def __str__(self):
        return f"{self.blocker} blocked {self.blocked} ({self.get_block_type_display()})"

이렇게 수정한 모델 덕분에, 이제 사용자는 댓글만 차단할 수도 있고, DM만 차단하거나 둘 다 차단할 수 있게 되었다. 각 차단 유형을 BLOCK_CHOICES 리스트에 정의하여 사용자가 쉽게 선택할 수 있도록 했다.


2. 차단 뷰 수정

이제 사용자 차단 기능을 뷰에서도 반영해야 했다. 사용자가 차단할 유형을 선택할 수 있도록 뷰를 수정했다. 사용자가 어떤 차단 유형을 선택했는지에 따라 적절한 차단 관계를 생성하도록 코드를 작성했다.

@login_required
def block_user(request, user_id):
    blocked_user = get_object_or_404(User, id=user_id)
    block_type = request.POST.get('block_type', Block.BOTH_BLOCK)

    block, created = Block.objects.get_or_create(blocker=request.user, blocked=blocked_user, block_type=block_type)

    if created:
        messages.success(request, f"{blocked_user.username}을(를) {block.get_block_type_display()}로 차단했습니다.")
    else:
        messages.warning(request, f"{blocked_user.username}은(는) 이미 {block.get_block_type_display()}로 차단된 사용자입니다.")

    return redirect('profile', user_id=user_id)

여기서는 사용자가 선택한 차단 유형에 따라 block_type을 설정하고, 그에 따라 차단을 진행하도록 했다. 차단이 성공적으로 이루어지면 사용자에게 성공 메시지를 보여주고, 이미 차단된 사용자를 다시 차단하려고 할 경우에는 경고 메시지를 출력하도록 했다.


3. 차단 해제 뷰 수정

차단 해제도 간단하게 할 수 있어야 하니까, 차단 해제 뷰에서도 차단 유형을 고려해야 했다. 사용자가 특정 유형으로 차단된 경우에만 차단을 해제할 수 있도록 했고, 이를 통해 사용자 경험이 향상되었다.

@login_required
def unblock_user(request, user_id):
    blocked_user = get_object_or_404(User, id=user_id)
    block_type = request.POST.get('block_type', Block.BOTH_BLOCK)

    block = Block.objects.filter(blocker=request.user, blocked=blocked_user, block_type=block_type).first()

    if block:
        block.delete()
        messages.success(request, f"{blocked_user.username}의 {block.get_block_type_display()} 차단을 해제했습니다.")
    else:
        messages.warning(request, f"{blocked_user.username}은(는) {block.get_block_type_display()}로 차단된 사용자가 아닙니다.")

    return redirect('profile', user_id=user_id)

이렇게 하면 사용자가 특정 차단 유형에 대해서만 차단 해제를 할 수 있다. 어떤 유형으로 차단했는지에 따라 적절한 차단 해제를 진행하는 로직을 추가했다.


4. 템플릿 수정

사용자가 차단할 유형을 선택할 수 있도록 폼을 수정했다. HTML에서 사용자에게 댓글 차단, DM 차단, 또는 두 가지 모두 차단할 수 있는 옵션을 제공하기 위해 드롭다운 메뉴를 추가했다.

<form method="post" action="{% url 'block_user' user.id %}">
    {% csrf_token %}
    <label for="block_type">차단 유형:</label>
    <select name="block_type" id="block_type">
        <option value="both">댓글 및 DM 차단</option>
        <option value="comment">댓글만 차단</option>
        <option value="dm">DM만 차단</option>
    </select>
    <button type="submit" class="btn btn-danger">차단하기</button>
</form>

<form method="post" action="{% url 'unblock_user' user.id %}">
    {% csrf_token %}
    <label for="block_type">차단 해제 유형:</label>
    <select name="block_type" id="block_type">
        <option value="both">댓글 및 DM 차단 해제</option>
        <option value="comment">댓글만 차단 해제</option>
        <option value="dm">DM만 차단 해제</option>
    </select>
    <button type="submit" class="btn btn-warning">차단 해제</button>
</form>

사용자는 이제 드롭다운 메뉴에서 차단 유형을 쉽게 선택할 수 있다. 이를 통해 사용자 경험이 더욱 향상되었다.


5. 콘텐츠 필터링

마지막으로, 차단 유형에 따라 필터링을 다르게 적용할 수 있도록 콘텐츠 필터링 기능을 추가했다. 댓글 차단과 DM 차단을 각각 다르게 처리할 수 있도록 작성했다.

def get_filtered_comments(user):
    blocked_users = Block.objects.filter(blocker=user, block_type__in=[Block.COMMENT_BLOCK, Block.BOTH_BLOCK]).values_list('blocked', flat=True)
    return Comment.objects.exclude(author__in=blocked_users)

def can_send_dm(sender, recipient):
    blocked = Block.objects.filter(blocker=recipient, blocked=sender, block_type__in=[Block.DM_BLOCK, Block.BOTH_BLOCK]).exists()
    return not blocked

이렇게 함으로써 댓글만 차단된 사용자의 댓글은 자동으로 필터링되고, DM만 차단된 경우에는 DM을 보낼 수 없는 로직이 적용된다.


오늘 작업을 통해 차단 기능을 더욱 세부적으로 구현하게 되어 매우 만족스럽다. 사용자들이 댓글과 DM을 각각 다르게 차단할 수 있도록 하여 더 나은 경험을 제공할 수 있게 되었다. 다음에는 이와 관련된 기능을 추가로 다룰 예정이다. 이 기록이 누군가에게 도움이 되기를 바란다. 좋은 하루 되길 바란다.

장고 리스트