회원가입 기능을 구현해보자.
users - views.py
class SignUpView(FormView):
pass
users - urls.py
urlpatterns = [path("signup", views.SignUpView.as_view(), name="signup")]
templates - partials - nav.html
<a href="{% url 'core:home' %}">Hairbnb</a>
<ul>
{% if user.is_authenticated %}
<li><a href="{% url 'users:logout' %}">Log out</a></li>
{% else %}
<li><a href="{% url 'users:login' %}">Login</a></li>
<li><a href="{% url 'users:signup' %}">Sign Up</a></li>
{% endif %}
</ul>
메인에 sign up이 떴다.

Sign Up 페이지는 아직 안열림.

templates - users - signup.html
{% extends "base.html" %}
{% block page_title %}
Sign Up
{% endblock page_title %}
{% block search-bar %}
{% endblock search-bar %}
{% block content %}
<form method="POST" action="{% url 'users:signup' %}">
{% csrf_token %}
{{form.as_p}}
<button>Sign Up</button>
</form>
{% endblock content %}
views.py에서 SignUp클래스를 추가한다.
users - views.py
class SignUpView(FormView):
template_name = "users/signup.html"
form_class = forms.SignUpForm
success_url = reverse_lazy("core:home")
users - forms.py
class SignUpForm(forms.Form):
pass
오 ㅋ

users - forms.py
class SignUpForm(forms.Form):
first_name = forms.CharField(max_length=80)
last_name = forms.CharField(max_length=80)
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
password1 = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")

Sign Up 화면에 정보를 입력할 칸이 나타나도록 하자.
users - views.py
class SignUpView(FormView):
template_name = "users/signup.html"
form_class = forms.SignUpForm
success_url = reverse_lazy("core:home")
initial = {
"first_name": "Jaewhoon",
"last_name": "Cho",
"email": "123@123.com",
"password": "123",
"password1": "123",
}

password는 입력해도 안되서 그냥 지워버렸다.
여기서 반드시 입력해야하는 정보는 Email과 Password이며, Password와 Confirm Password는 일치해야한다.
users - forms.py
class SignUpForm(forms.Form):
first_name = forms.CharField(max_length=80)
last_name = forms.CharField(max_length=80)
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
password1 = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")
def clean_email(self):
email = self.cleaned_data.get("email")
try:
models.User.objects.get(email=email)
raise forms.ValidationError("User already exists with that email")
except models.User.DoesNotExist:
return email
def clean_password1(self):
password = self.cleaned_data.get("password")
password1 = self.cleaned_data.get("password1")
if password != password1:
raise forms.ValidationError("Password confirmation does not match")
else:
return password
오 ㅋ

users - forms.py
class SignUpForm(forms.Form):
first_name = forms.CharField(max_length=80)
last_name = forms.CharField(max_length=80)
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
password1 = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")
def clean_email(self):
email = self.cleaned_data.get("email")
try:
models.User.objects.get(email=email)
raise forms.ValidationError("User already exists with that email")
except models.User.DoesNotExist:
return email
def clean_password1(self):
password = self.cleaned_data.get("password")
password1 = self.cleaned_data.get("password1")
if password != password1:
raise forms.ValidationError("Password confirmation does not match")
else:
return password
def save(self):
first_name = self.cleaned_data.get("first_name")
last_name = self.cleaned_data.get("last_name")
email = self.cleaned_data.get("email")
password = self.cleaned_data.get("password")
user = models.User.objects.create_user(email, email, password)
user.first_name = first_name
user.last_name = last_name
user.save()
users - views.py
class SignUpView(FormView):
template_name = "users/signup.html"
form_class = forms.SignUpForm
success_url = reverse_lazy("core:home")
initial = {
"first_name": "Jaewhoon",
"last_name": "Cho",
"email": "123@123.com",
}
def form_valid(self, form):
form.save()
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
user = authenticate(self.request, username=email, password=password)
if user is not None:
login(self.request, user)
return super().form_valid(form)

관리자로 로그인되어있던 admin이 로그아웃되고 권한없는 사용자가 로그인중이라고 뜬걸 보니 제대로 되었다.

comment, review, message 등 여러 기능을 추가할건데 매번 이렇게 model로 가서 요소들 다 복사한 다음에 붙여넣고 하기가 번거롭다. ModelForm이란걸 써서 간단하게 하자. 말 그대로 Model에 연결된 Form이다.
users - forms.py
class SignUpForm(forms.ModelForm):

그리고 내부에 Meta class를 선언해주자.
users - forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = models.User


흠.... ModelForm을 구성하는데 fields나 execlude가 없어서는 안된다고 한다.

Meta 클래스에 fields를 추가했고 그 아래에 fields에 추가한 변수들은 지워보았다.
users - forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = models.User
fields = ("first_name", "last_name", "email")
# first_name = forms.CharField(max_length=80)
# last_name = forms.CharField(max_length=80)
# email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)
password1 = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")
전혀 지장없이 잘 나타난다.

그러면 이제 ModelForm이 email을 자동으로 clean시킬테니 clean_email이 필요가 없어진다. save도 ModelForm에 있는 기능이긴 한데 일단 중복되는건 지우고서 해보자.
users - forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = models.User
fields = ("first_name", "last_name", "email")
password = forms.CharField(widget=forms.PasswordInput)
password1 = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")
def clean_password1(self):
password = self.cleaned_data.get("password")
password1 = self.cleaned_data.get("password1")
if password != password1:
raise forms.ValidationError("Password confirmation does not match")
else:
return password
이 상태에선 유저가 생성은 되는데 Username이 비어있다.

save함수를 override해서 기능을 조정해보자.

commit=False => object를 생성하지만 db에는 등록하지 마라
users - forms.py
class SignUpForm(forms.ModelForm):
class Meta:
model = models.User
fields = ("first_name", "last_name", "email")
password = forms.CharField(widget=forms.PasswordInput)
password1 = forms.CharField(widget=forms.PasswordInput, label="Confirm Password")
def clean_password1(self):
password = self.cleaned_data.get("password")
password1 = self.cleaned_data.get("password1")
if password != password1:
raise forms.ValidationError("Password confirmation does not match")
else:
return password
def save(self, *args, **kwargs):
user = super().save(commit=False)
email = self.cleaned_data.get("email")
password = self.cleaned_data.get("password")
user.username = email
user.set_password(password)
user.save()
User 생성해보면 자동으로 username에 email이 들어간 것을 볼 수 있다.
