3 minute read

프로필 정보 추가

    profile_pic = models.ImageField(
        default="default_profile_pics.jpg",
        upload_to="profile_pics"
    )

    intro = models.CharField(max_length=60, blank=True)

media폴더 아래에 기본 사진을 넣어 둔다.
프로필 기본 사진과 자기소개 필드
작성 후 마이그레이션
admin.py에 추가

<div class="cp-avatar" style="background-image: url('{{review.author.profile_pic.url}}')"></div>  

템플릿에서 닉네임이 쓰이는 곳에 작성해서 프로필 사진이 나오게 설정

프로필 페이지

# urls.py

path('users/<int:user_id>/', views.ProfileView.as_view(), name="profile"),
class ProfileView(DetailView):
    model = User
    template_name = "coplate/profile.html"
    pk_url_kwarg = "user_id"
    context_object_name = "profile_user"

    def get_context_data(self, **kwargs):
        # 기존의 context를 가져온다
        context = super().get_context_data(**kwargs)
        # url의 user_id파라미터를 가져온다
        user_id = self.kwargs.get('user_id')
        # author_id가 user_id인 게시글 중에서 내림차순으로
        # 앞에서 4개까지 가져온다
        context["user_reviews"] = Review.objects.filter(author_id=user_id).order_by("-dt_created")[:4]
        return context

상세 페이지니까 DetailView사용하면 된다.
상세 페이지에서 유저가 작성한 글을 보여주려면 유저가 작성한 글을 템플릿에 전달해야 한다. get_context_data를 오버라이드 하면 된다.
get_context_data는 템플릿 파일에 변수나 데이터 같은 추가 context를 넘겨줄 때 사용한다.

유저 글 목록 페이지

class UserReviewListView(ListView):
    model = Review
    template_name = "coplate/user_reivew_list.html"
    context_object_name = "user_reviews"
    paginate_by = 4

    def get_queryset(self):
        user_id = self.kwargs.get("user_id")
        return Review.objects.filter(author_id=user_id).order_by('dt_created')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["profile_user"] = get_object_or_404(User, id=self.kwargs.get("user_id"))
        return context

모든 글이 아니라 해당 유저가 작성한 글만 가져올 것이니 get_queryset을 오버라이드 한다. ListView에서 보여줄 오브젝트 리스트를 제어하고 싶을 때는 get_queryset을 오버라이드 하면된다. get_queryset은 ordering속성을 사용할 수 없기 때문에 필터 결과 자체를 정렬한다.

ListView를 사용하면 글 리스트만 전달되고 유저 정보는 전달되지 않으므로 get_context_data를 오버라이드해 전달한다.
get_object_or_404는 주어진 “user_id”에 해당하는 유저가 없으면 404에러를 낸다.

이렇게 하면 프로필 유저는 profile_user, 프로필 유저의 글 목록은 user_reviews로 전달되게 된다.

프로필 설정 페이지

path(
    'set-profile/',
    views.ProfileSetView.as_view(),
    name="profile-set",
),
class ProfileSetView(UpdateView):
    model = User
    form_class = ProfileForm
    template_name = "coplate/profile_set_form.html"

    def get_object(self, queryset=None):
        return self.reqeust.user

    def get_success_url(self):
        return reverse('index')

프로필 설정 페이지는 이미 생성되어 있는 유저에 정보를 추가하는 것이니 UpdateView를 사용한다.
UpdateView는 어떤 오브젝트를 업데이트 할지 알아야 한다.
기본적으로 url로 전달되고 pk_url_kwag로 설정하는데
여기선 url로 id가 전달돼지 않는다. 현재 로그인된 유저의 프로필을 설정하는 것이기 때문이다.
그래서 업데이트할 오브젝트를 알려주는게 get_object이다.

ListView는 여러개의 오브젝트를 다루니까 get_queryset을 오버라이드하고
DetailView, CreateView, DeleteView, UpdateView들은 하나의 오브젝트를 다루니까 get_object를 오버라이드한다.

Middleware

Middleware는 Mixin처럼 하나의 뷰에만 적용되는 것이 아니라 전체에 적용이 된다.
모든 요청은 url dispatcher로 도착하기 전에 Middleware를 먼저 거쳐야 한다.
이 때 요청을 프로세싱 후에 전달할 수 도 있다.
뷰에서의 응답도 모두 Middleware를 거치게 된다.
이 때 응답도 프로세싱을 할 수 있다.

settings.py에 MIDDLEWARE에 작성하면 된다.
요청은 작성 순서대로 위에서 부터 아래로 통과하고
응답은 아래에서 부터 위로 통과한다.

프로필 설정을 하지 않은 유저가 어디로 접근하든지 간에 항상 프로필 설정으로 안내할 때 즉 url과 상관없이 리디렉트 시키려면 Middleware를 사용하면된다.
Middleware

# middleware.py

from django.urls import reverse
from django.shortcuts import redirect

class ProfileSetupMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if (
            # 유저가 로그인 상태인지 확인
            request.user.is_authenticated and
            # 프로필을 설정했는지 닉네임으로 확인
            not request.user.nickname and
            # 유저가 어디로 요청을 보냈는지 확인
            # 즉 프로필 설정페이지가 아닌 다른 
            # 페이지로 요청을 보냈는지 확인
            request.path_info != reverse('profile-set')
        ):
            return redirect("profile-set")

        # 위에서 걸리는게 없으면 평소처럼 처리
        response = self.get_response(request)

        return response

이렇게 작성하고 settings.py에서 MIDDLEWARE에 명시해 준다.

    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'coplate.middleware.ProfileSetupMiddleware',

이 때 AuthenticationMiddleware보다 아래에 작성해야 한다.
ProfileSetupMiddleware코드에는 request.user를 사용하는데 이것은
AuthenticationMiddleware를 거쳐야만 설정되기 때문이다.

제네릭 뷰

get_success_url

CreateView, UpdateView, DeleteView에서 사용한다.
요청이 성공적으로 처리되었을 때 리디렉트할 URL을 정한다.
뷰가 다루고 있는 오브젝트는 self.object로 접근할 수 있다.

form_valid

CreateView, UpdateView에서 사용한다.
폼 데이터가 유효하면 폼 데이터를 새로운 오브젝트 , 또는 기존의 오브젝트에 저장한다.
폼 데이터가 저장되기 전에 액션을 취하고 싶을 때 사용한다.

get_context_data

모든 제네릭 뷰에서 사용한다.
템플릿에 전달되는 컨텍스트를 정해주는 메소드이다.
이 메소드를 오버라이드해서 컨텍스트에 데이터를 추가한다.
super()를 사용해 원래 전달되는 컨텍스트를 가져오고 컨텍스트에 데이터를 추가하고 리턴하면 된다.

get_queryset

ListView에서 보여 줄 오브젝트 리스트를 설정한다.
기본적으론 model에 해당하는 모든 오브젝트 리턴하고 이를 바꾸고 싶으면 get_queryset을 오버라이드 한다.

get_object

DetailView, UpdateView, DeleteView에서 다루는 오브젝트를 설정한다.
CreateView는 새로운 오브젝트를 설정하는 것임으로 사용하지 않는다.
기본적으론 pk_url_kwarg파라미터로 전달되는 id값을 가진 오브젝트를 리턴하고 이를 바꾸고 싶으면 get_object를 오버라이드 한다.

Leave a comment