Backend/Python

[인스타그램클론] 폼 에러메시지 표시

비비빅B 2020. 7. 18. 14:05

문제 현상

  • 이메일에 잘못된 형식이 들어가도 에러메시지가 뜨지 않음
  • 그냥  DB에 저장도 되지 않고 다음 페이지로 리다이렉트 됨

형식에 맞지 않는 이메일을 써도 프로필페이지로 리다이렉트 되고 다시 편집창으로 들어가면 DB에 저장되지 않은 모습


원인

    def post(self, request):
        current_user = User.objects.get(pk=request.user.pk)
        user_form = UserForm(request.POST, instance=current_user)

        if user_form.is_valid():
            user_form.save()

        # PROFILE UPDATE
        if hasattr(current_user, "profile"):
            profile = current_user.profile
            profile_form = ProfileForm(
                request.POST, request.FILES, instance=profile)

        # PROFILE CREATE
        else:
            profile_form = ProfileForm(request.POST, request.FILES)

        if profile_form.is_valid():
            # PROFILE CREATE의 경우 USER와 연결이 필요함
            profile = profile_form.save(commit=False)
            profile.user = current_user                 # Profile 모델의 user에 current_user 지정
            profile.save()

        return redirect("accounts:profile", slug=request.user.profile.slug)
  • 하나의 액션에 폼을 2개 사용하고 있는 상황
  • 자세히 보면 user_form이 유효하지 않을 때 처리해주는 구문이 없음
    def post(self, request):
        current_user = User.objects.get(pk=request.user.pk)
        user_form = UserForm(request.POST, instance=current_user)

        if user_form.is_valid():
            user_form.save()
  • 이 부분에서 user_form의 이메일 input이 유효하지 않기 떄문에 그냥 통과
  • 그 후 마지막 줄 return redirect로 프로필 페이지로 이동
  • 결과적으로 user_form이 DB에 저장되지 않고 리다이렉트 됨

시도

  • 일단 유저폼과 프로필폼 유효성 검사문을 하나로 묶었음
  • 그리고 폼 2개가 모두 유효할 때만 DB에 저장하고 프로필 페이지로 리다이렉트
  • 유효하지 않다면 input next에 담긴 이전 페이지로 리다이렉트
  if profile_form.is_valid() and user_form.is_valid():
      # PROFILE CREATE의 경우 USER와 연결이 필요함
      profile = profile_form.save(commit=False)
      profile.user = current_user                 # Profile 모델의 user에 current_user 지정
      profile.slug = request.POST.get('nickname')
      profile.save()

      user_form.save()

      return redirect("accounts:profile", slug=request.user.profile.slug)

  next = request.POST.get('next', '/')
  return HttpResponseRedirect(next)
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
	{% render_field profile_form.profile_photo class="profile_photo" %}
	<ul>
		<li class="input-data"><label for="name">성</label>{% render_field user_form.first_name class="name" %}</li>
		<li class="input-data"><label for="name">이름</label>{% render_field user_form.last_name class="name" %}</li>
		<p>사람들이 이름, 별명 또는 비즈니스 이름 등 회원님의 알려진 이름을 사용하여 회원님의 계정을 찾을 수 있도록 도와주세요</p>
		<li class="input-data"><label for="name">사용자 이름</label>{% render_field profile_form.nickname class="nickname" %}</li>
		<li class="input-data"><label for="email"">이메일</label>{% render_field user_form.email class="email" %}</li>
		<li class="input-data"><label for="submit"></label><input type="submit" value="제출" /></li>
	</ul>
	<input type="hidden" name="next" value="{{ request.path }}">
</form>
  • 그리고 redirect로 에러메시지를 정달해줘야해서 구글링을 해봤지만 실패...
  • redirect로는 값을 전달 못한다고 함
  • render로 해도 되지만 다시 get 메소드처럼 코드를 만들고 싶지 않았음
  • next로 이전페이지로 리다이렉트되는걸 유지하면서 메시지를 표시하고 싶었음
  • 좀 더 찾아보니 장고에는 messages라는 프레임워크가 있음
  • 프론트페이지에서 전역적으로 사용할 수 있는 듯함
  • 자세한 내용은 여기
  • 중요도별로 메시지 등급을 나눌 수 있고 try except 문으로 감싸서 에러가 나면 사용할 수 있는듯함

해결

    def post(self, request):
        try:
            current_user = User.objects.get(pk=request.user.pk)
            user_form = UserForm(request.POST, instance=current_user)

            # PROFILE UPDATE
            if hasattr(current_user, "profile"):
                profile = current_user.profile
                profile_form = ProfileForm(
                    request.POST, request.FILES, instance=profile)

            # PROFILE CREATE
            else:
                profile_form = ProfileForm(request.POST, request.FILES)

            # PROFILE CREATE의 경우 USER와 연결이 필요함
            profile = profile_form.save(commit=False)
            profile.user = current_user                 # Profile 모델의 user에 current_user 지정
            profile.slug = request.POST.get('nickname')
            profile.save()

            user_form.save()

            return redirect("accounts:profile", slug=request.user.profile.slug)

        except Exception:
            messages.add_message(request, messages.ERROR, "형식이 올바르지 않습니다.")
            next = request.POST.get('next', '/')
            return HttpResponseRedirect(next)
  • try문으로 묶어서 폼이 유효하지 않으면 오류가 나도록 if valid 부분을 없앰
  <input type="hidden" name="next" value="{{ request.path }}">
  {% if messages %}
      {% for message in messages %}
          <p{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{message}}</p>
      {% endfor %}
{% endif %}
</form>
  • messgae가 하나라도 for문 돌려야 된다고 함
  • 이유는 그렇지 않으면 이전 message가 깨끗하게 정리되지 않는다고 함

유효하지 않은 이메일을 적고 제출버튼을 누르니 메시지가 잘 나옴


배운점

  • 리다이렉트로는 추가적인 정보를 전달하지 못함
  • 장고에 내장된 messages 프레임워크을 잘 활용하자