Django - UserAuth

김병훈·2021년 3월 23일
0

Django

목록 보기
1/1
post-thumbnail

프로젝트 목적

Django auth 익히기

프로젝트 구조

- accounts/
- articles/
- config/
- templates/
	- base.html
	- components/
		- nav.html

특징

  1. Bootstrap을 적용하기 위해 accounts/forms.py에서 Auth Form을 커스텀

  2. 로그인, 회원가입, 회원정보 수정, 비밀번호 변경 등에 form이 공통적으로 사용되고 있어, 공용으로 사용할 수 있는 template을 만들었다.

난관

1. Form 커스텀

# vscode 자동완성으로 입력되는 `__init__`
class CustomAuthenticationForm(AuthenticationForm):
    def __init__(self, request=None, *args, **kwargs):
        super().__init__(request=request, *args, **kwargs)
        
# stackoverflow 참고 코드
class CustomAuthenticationForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
        super(CustomAuthenticationForm, self).__init__(*args, **kwargs)

자동완성으로 입력되는 함수로 상속을 진행하면, request관련 에러가 발생한다.

그래서 참고 코드를 살펴보며 조금씩 변화를 주었다.

  1. __init__에 인자로 전달되는 request=request 부분을 지워보았더니 에러는 발생하지 않았다.
    하지만, 로그인이 제대로 진행되지 않았다. (form.is_valid()가 False)

  2. __init__에 인자로 전달되는 request=None 부분을 지워보았더니 로그인도 제대로 진행되었다.
    Stackoverflow 코드는 super에 자기 클래스를 인자로 넣어주는 것이 이해가 되지 않았기 때문에 아래 코드로 작업을 이어서 진행한 뒤 문제가 생기면 다시 정리하려고 한다.

    class CustomAuthenticationForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

2. Update Form & Django Template filter(safe)

공통 form.html에 렌더링을 하려고 하였지만, {{ field.help_text }} 에 a tag(HTML)가 들어있어 제대로 렌더링되지 않음

해결방법
  • django filter인 safe를 사용하여, HTML이 그대로 렌더링 될 수 있도록

{{ field.help_text|safe }}


Accounts App

Form Template

{% extends 'base.html' %}

{% block content %}
<h1>{{ title }}</h1>
<hr>
<section>
  <form action="" method="POST">
    {% csrf_token %}
    {% for field in form %}
    <div class="mb-4">
      <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
      {{ field }}
      <div class="form-text">
        {{ field.help_text|safe }}
      </div>
    </div>
    {% endfor %}
    <button type="submit" class="btn btn-primary">{{ buttonText }}</button>
  </form>
  {% if deleteBtn %}
  <hr>
  <form action="{% url 'accounts:delete' %}" method="POST">
    {% csrf_token %}
    <button class="btn btn-danger" type="submit">회원탈퇴</button>
  </form>
  {% endif %}
</section>
{% endblock content %}

Login

accounts/forms.py

from django.contrib.auth.forms import AuthenticationForm

class CustomAuthenticationForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["username"].widget.attrs["class"] = "form-control"
        self.fields["password"].widget.attrs["class"] = "form-control"

accounts/views.py

from django.views.decorators.http import require_http_methods
from .forms import CustomAuthenticationForm


# GET, POST 방식의 요청만 받습니다.
# 다른 요청 방식은 Method not allowed Error(405)
@require_http_methods(["GET", "POST"])
def login(request):
    if request.method == "POST":
        # 입력받은 정보를 바탕으로 form 인스턴스 생성
        form = CustomAuthenticationForm(request, request.POST)
        # 생성한 form 인스턴스로 유효성 검사
        if form.is_valid():
            # 로그인
            auth_login(request, form.get_user())
            # 메인페이지로 이동
            return redirect("accounts:index")
    else:
        form = CustomAuthenticationForm()
	# GET method or form.is_valid() == False
    context = {
        "form": form,
        "title": "로그인",
        "buttonText": "로그인",
    }
    return render(request, "accounts/form.html", context)

Logout

accounts/views.py

from django.view.decorators.http import require_POST

@require_POST
def logout(request):
    # 로그인이 되어있는 상태라면,
    if request.user.is_authenticated:
        # 로그아웃!
        auth_logout(request)
    return redirect("accounts:index")

Create

accounts/forms.py

from django.contrib.auth.forms import UserCreationForm

class CustomUserCreationForm(UserCreationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["username"].widget.attrs["class"] = "form-control"
        self.fields["password1"].widget.attrs["class"] = "form-control"
        self.fields["password2"].widget.attrs["class"] = "form-control"

accounts/views.py

from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login as auth_login
from .forms import CustomUserCreationForm


@require_http_methods(["GET", "POST"])
@login_required
def create(request):
    if request.method == "POST":
        form = CustomUserCreationForm(request.POST)
        # 유효성 검사
        if form.is_valid():
            # 바로 로그인
            # save() 메서드는 생성한 user 인스턴스를 리턴합니다.
            user = form.save()
            auth_login(request, user)
            return redirect("accounts:index")
    else:
        form = CustomUserCreationForm()
    context = {
        "form": form,
        "title": "회원가입",
        "buttonText": "가입하기",
    }
    return render(request, "accounts/form.html", context)

Update

accounts/forms.py

from django.contrib.auth.forms import UserChangeForm


class CustomUserChangeForm(UserChangeForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["username"].widget.attrs["class"] = "form-control"
        self.fields["email"].widget.attrs["class"] = "form-control"

    class Meta(UserChangeForm.Meta):
        fields = (
            "username",
            "email",
        )

accounts/views.py

from django.view.decorators.http import require_http_methods
from .forms import CustomUserChangeForm


@require_http_methods(["GET", "POST"])
def update(request):
    if not request.user.is_authenticated:
        return redirect("accounts:login")

    if request.method == "POST":
        form = CustomUserChangeForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            return redirect("accounts:index")
    else:
        form = CustomUserChangeForm(instance=request.user)
    context = {
        "form": form,
        "title": "회원정보 수정",
        "buttonText": "수정하기",
        "deleteBtn": True,
    }
    return render(request, "accounts/form.html", context)

Delete

accounts/views.py

from django.view.decorator.http import require_POST

@require_POST
def delete(request):
    if request.user.is_authenticated:
        request.user.delete()
    return redirect("accounts:index")
profile
재밌는 걸 만드는 것을 좋아하는 메이커

0개의 댓글