웹 프로그래밍 스쿨 django 수업 3주 차 포스팅입니다😃

 

 

지난주부터 수업시간에 인스타의 기능들을 하나씩 구현해보는 시간을 가져보고 있는데요!

 

오늘은 저번 수업시간에 과제로 내주셨던 Follow 기능과 Follow List를 구현 한 수강생 분들의 

 

첫 과제 발표시간이 있는 날이었습니다.

 

 

첫 발표자로는 맨 뒷자리에서 손을 들어주신 진욱 님과 맨 앞에서 손을 들은 제가.. 당첨되었습니다.

 

 

첫 타자임에도 불구하고 침착하게 발표 잘하시는 진욱님.

 

 

중간에 멘탈이 터져버린 나님.  낯설다 내 코드..

 

발표를 하는 동안 너무 버벅대서 수강생 분들께 죄송한 맘에 이를 악문채로 발표를 마무리 했는데

 

그래도 찰떡같이 알아들어주신 분들이 의외로 좀 계셔서 위로가 되었습니다. 주석보고 이해했어요^^

 

 

아래는 과제 내용입니다.

 

진행된 강의의 코드가 아니라 제 머릿속에서 생각나는 대로 만든 거라 퀄리티에 문제가 있을 수 있습니다.😉

 

 

class Follow(models.Model):
    who = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
    following = models.CharField(default='0 ', max_length=5000)
    followedBy = models.CharField(default='0 ', max_length=5000)

 

Follow와 관련된 정보를 저장할 테이블을 설정하기 위해 모델을 만듭니다.

  • who : search 할 때 기준이 될 유저를 저장할 컬럼으로, User 테이블과 연결된 ForeignKey 필드입니다.

  • following : 기준이 되는 유저가 팔로잉하고 있는 유저들의 User.id 값을 저장할 Char 필드입니다.

  • followedBy : 기준이 되는 유저를 팔로잉 하고 있는 유저들의 User.id 값을 저장할 Char 필드입니다.

 

class UserList(ListView):
    model = User
    template_name = 'accounts/user_list.html'

 

  • 리스트뷰를 상속받아서 model 변수에  User 테이블을 할당하면 상속받은 ListView의 내부 로직이
    User객체들을 리스트로 만들어 줍니다.

  • 객체 리스트를 전달할 템플릿 파일을 지정해줍니다.

 

 

user_list.html

 <table class="table">
   {% for object in object_list %}
     <tr>
       <td>{{ object.username }}</td>
       <td><a href="{% url 'accounts:following' object.id %}" class="btn btn-xs btn-outline-success">Follow</a></td>
       <td><a href="{% url 'accounts:unfollow' object.id %}" class="btn btn-xs btn-outline-success">UnFollow</a></td>
     </tr>
   {% endfor %}
 </table>

 

  • 뷰에서 전달받은 객체 리스트에서 유저 객체를 받아서 username을 출력하고 그 옆에 Follow와 UnFollow 버튼을 만듭니다.

  • 이제 브라우저 화면에서 해당 유저 이름 옆에 있는 Follow 버튼과 UnFollow 버튼을 누르면 해당 기능의 URL을
    요청할 수 있습니다.

 

 

urls.py

app_name = 'accounts'

urlpatterns = [
    path('follow/<int:pk>/', Following.as_view(), name='following'),
    path('unfollow/<int:pk>/', Unfollow.as_view(), name='unfollow'),
]

 

위 코드는 accounts 앱 안에 있는 URL 파일의 일부입니다.

 

해당 유저를 팔로우하기 위해 Following 버튼을 누른다면

 

{% url 'accounts : following ' object.id %} 

 

템플릿에(user_list.html) 있던 팔로잉 버튼의 URL 태그 중 'accounts:following' 부분으로 

app_name='accounts' 부분과 name = following 부분을 찾아 해당 패턴에 맞는 URL 양식을 만들고

 <int:pk> 부분에 object.id 값을 대입한 주소를 요청합니다.

 

해당 주소를 요청받으면 Following 뷰를 작동시킵니다.

 

 

 

views.py

class Following(View):

    def get(self, request, *args, pk):

        if not request.user.is_authenticated:
            return HttpResponseRedirect(reverse('accounts:signin'))

 

오버 라이딩된 get 메서드를 실행하면

 

먼저 버튼을 누른 유저가 로그인이 되어있는 상태인지 확인한 후에 로그인이 되어있지 않다면 로그인 화면으로

돌려보냅니다.

 

 

 

        else :
            user = request.user			# 1. URL을 요청한 유저 정보를 저장
            opponent = User.objects.get(pk=pk)
						# 2. 템플릿으로부터 전달받은 pk변수의 값(object.id)
                                        
            if user != opponent :
                if not Follow.objects.filter(who=user) :	# 3. who컬럼에 user가 이미 있는지 확인 
                    Follow.objects.create(who=user)

                if not Follow.objects.filter(who=opponent):	# 4. who컬럼에 팔로우할 상대가 이미 있는지 확인
                    Follow.objects.create(who=opponent)

                Iam = Follow.objects.get(who=user.id)		# 5. who컬럼의 값이 user.id인 객체를 Iam에 할당
                
                Uare = Follow.objects.get(who=opponent.id)	# 6. who컬럼의 값이 opponent인 객체를 Uare에 할당

                if str(opponent.id) not in Iam.following.split():
                    Iam.following += f'{opponent.id} '		# 7. following 컬럼에 상대방의 id값을 추가
                    Uare.followedBy += f'{user.id} '		# 8. followedby칼럼에 내 id값을 추가
                    Iam.save()
                    Uare.save()

        return HttpResponseRedirect(reverse('accounts:followlist'))

 

1.  버튼을 누른 유저가 로그인된 상태라면 유저 객체를 user 변수에 할당합니다.

 

2.  템플릿에서 전달받은 상대방의 pk값을 이용해 User테이블에서 팔로우하고자 하는 상대방의 정보를 찾아

     opponent 변수에 할당합니다.

 

3.  filter 메소드를 사용해서 user가 예전에 Follow 기능을 사용한 적 있는지 확인하고 없다면 user의 정보를 추가합니다.

 

4.  filter 메소드를 사용해서 opponent가 Follow 기능을 사용한 적이 있는지 확인하고 없다면 user의 정보를 추가합니다.

 

5.  Follow 테이블에서 who 칼럼의 값이 user.id 인 객체를 Iam 변수에 할당합니다.

 

6.  Follow 테이블에서 who 칼럼의 값이 user.id 인 객체를 Uare 변수에 할당합니다.

 

7.  Iam 객체의 following 컬럼에 opponet.id 값을 추가합니다.

 

8.  Uare 객체의 followedBy 컬럼에 user.id 값을 추가합니다.

 

 

 

 

class Unfollow(View):

    def get(self, request, *args, pk):

        if not request.user.is_authenticated:
            return HttpResponseRedirect(reverse('accounts:signin'))
        else :
            user = request.user
            opponent = User.objects.get(pk=pk)

            if user != opponent :
                Iam = Follow.objects.get(who=user.id)
                Uare = Follow.objects.get(who=opponent.id)	# 여기까지 follow 기능과 같음

                if str(opponent.id) in Iam.following.split():
                	# 1. 문자열을 분리해서 리스트안에 언팔로우 하고자 하는 상대방의 id 값이 있다면
                   	# 그 값을 공백으로 대체합니다.
              
                    Iam.following = Iam.following.replace(f' {opponent.id} ', ' ')
                    Uare.followedBy = Uare.followedBy.replace(f' {user.id} ', ' ')
                    Iam.save()
                    Uare.save()
                    
             return HttpResponseRedirect(reverse('accounts:followlist'))

 

Unfollow의 로직도 Follow의 로직과 비슷합니다.

 

다른 점은 유저 객체의 id 값을 더하는 것이 아니라 더해져 있던 id 값을 공백으로 대체한다는 것입니다.

 

 

Database     before & after

 

User 테이블의 id 값이 1인 유저 (who_id  = 1)가 id값이 2, 4, 5번인 유저를 팔로잉하고 있다가  (왼쪽 그림)

 

5번 유저를 언팔로잉 하게 되면 following 컬럼에서 '_5_'가  '_' 로 , (  _ 가 공백입니다. )

who_id = 5 인 객체의 followedBy 컬럼의 '_1_' 이 '_' 로 대체되어 보이지 않게 됩니다 (오른쪽 그림)

 

 

 

다음은 팔로우하고 있는 사람과 나를 팔로우 하고 있는 사람을 보여줄 FollowList 뷰입니다.

 

class FollowList(View):
    template_name = 'accounts/follow_list'

    def get(self, request, *args, **kwargs):
        context = {}

        context['following_list'] = self.get_following_list()
        context['followed_list'] = self.get_followedBy_list()
        return render(request, 'accounts/follow_list.html', context)

 

Follow 리스트와 Followed 리스트를 구분해서 전달해 주기 위해

get 메소드를 오버라이딩해서 템플릿에 넘겨줄 context 딕셔너리에 각 다른 키값으로 객체 리스트를 넣어 둡니다.

 

 

    def get_following_list(self):
        user = self.request.user
        selected = Follow.objects.get(who=user.id)

        following_id = selected.following.split() # following 컬럼에 있는 문자열을 분리
        following_id.remove('0')
        following_list = []
        for num in following_id:		# 분리된 문자열의 결과를 User테이블의 id에 반영해서
            follower = User.objects.get(id=int(num))	# Following 하고있는 유저객체를 찾아냄
            following_list.append(follower)

        return following_list

 

템플릿 파일에 전달할 유저객체 리스트를 만들 메소드입니다.

 

  • Follow와 같은 원리로 해당 user의 following 컬럼에 접근하고 문자열을 분리합니다.

  • 분리된 문자열을 User 테이블의 id 값에 대입해서 해당 유저객체를 만들어 리스트에 추가합니다.

같은 방식으로 get_followed_list 메소드를 실행하고 context 딕셔너리에 담아 템플릿 파일에 전달하면

 

Following 리스트와 Followed 리스트를 같은 화면에 출력할 수 있습니다.

 

 

 

웹 프로그래밍 스쿨에 대해 더 알아보기 ⭐

 

 

BELATED ARTICLES

more