실용주의 프로그래머님의 인프런 강의를 듣고 작성하였습니다.
출처: https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-%ED%95%80%ED%84%B0%EB%A0%88%EC%8A%A4%ED%8A%B8/lecture/62871?tab=note&speed=1.25
CreateView 사용
class AccountCreateView(CreateView):
model = User
form_class = UserCreationForm
success_url = reverse_lazy('accountapp:hello_world')
template_name = 'accountapp/create.html'
urlpatterns = [
path('hello_world/', hello_world, name='hello_world')
# "127.0.0.1:8000/account/hello_world"
path('create/', AccountCreateView.as_view(), name='create')
]
{% extends 'base.html' %}
{% block content %}
<div style="text-align: center">
<form action="{% url 'accountapp:create' %}" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary">
</form>
</div>
{% endblock %}
header.py에서 회원 가입 경로 추가
{% if not user.is_authenticated %}
<a href="{% url 'accountapp:login' %}?next={{ request.path }}">
<span>login</span>
</a>
<a href="{% url 'accountapp:create' %}">
<span>Sign Up</span>
</a>
{% else %}
urls.py에 경로 추가
urlpatterns = [
path('hello_world/', hello_world, name='hello_world'),
# "127.0.0.1:8000/account/hello_world"
path('login/', LoginView.as_view(template_name="accountapp/login.html"), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),
path('create/', AccountCreateView.as_view(), name='create')
]
로그인 뷰와 로그아웃 뷰에서 경로를 지정해 주어야 한다.
1. next
2. LOGIN_REDIRECT_URL
3. Default
아무것도 지정해 주지 않으면 Default로 간다. 따라서 위의 우선순위대로 경로를 지정해주자.
next는 ?next={{ request.path }} 구문을 통해 현재 url로 돌아오도록 해준다.
LOGIN_REDIRECT_URL은 leebook/settings.py에서 설정해준다.
LOGIN_REDIRECT_URL = reverse_lazy('accountapp:hello_world')
LOGOUT_REDIRECT_URL = reverse_lazy('accountapp:login')
메인 페이지에 로그인, 로그아웃 버튼
{% if not user.is_authenticated %}
<a href="{% url 'accountapp:login' %}?next={{ request.path }}">
<span>login</span>
</a>
{% else %}
<a href="{% url 'accountapp:logout' %}?next={{ request.path }}">
<span>logout</span>
</a>
{% endif%}
login.html 생성
{% extends 'base.html'%}
{% block content %}
<div style="text-align: center">
<div>
<h4>Login</h4>
</div>
<div>
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary">
</form>
</div>
</div>
{% endblock %}
설치
pip install django-bootstrap4
setting.py에 bootstrap4 추가
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'bootstrap4',
'accountapp',
]
create.html
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
<div style="text-align: center; max-width: 500px; margin: 4rem auto">
<div class="mb-4">
<h4>
SignUp
</h4>
</div>
<form action="{% url 'accountapp:create' %}" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
</form>
</div>
{% endblock %}
login.html
{% extends 'base.html'%}
{% load bootstrap4 %}
{% block content %}
<div style="text-align: center; max-width: 500px; margin: 4rem auto">
<div>
<h4>Login</h4>
</div>
<div>
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
</form>
</div>
</div>
{% endblock %}
다운받은 폰트 static/fonts에 저장
head.html 파일에 추가해서 어디서든 font 사용할 수 있도록 하기
<style>
@font-face {
font-family: 'NanumSquareR';
src: local('NanumSquareR'),
url("{% static 'fonts/NanumSquareR.ttf' %}") format("opentype");
}
@font-face {
font-family: 'NanumSquareEB';
src: local('NanumSquareEB'),
url("{% static 'fonts/NanumSquareEB.otf' %}") format("opentype");
}
@font-face {
font-family: 'NanumSquareB';
src: local('NanumSquareB'),
url("{% static 'fonts/NanumSquareB.otf' %}") format("opentype");
}
@font-face {
font-family: 'NanumSquareR';
src: local('NanumSquareR'),
url("{% static 'fonts/NanumSquareR.otf' %}") format("opentype");
}
</style>
base.html에서 적용
<body style="font-family: 'NanumSquareR';">
중간에 css를 변경해도 적용되지 않는 오류가 있어서 head.html에서 base.css를 적용하는 링크에 ?after을 적어주니 해결되었다.
<!-- DEFAULT CSS LINK --> <link rel="stylesheet" type="text/css" href="{% static 'base.css' %}?after">
사용자의 상세 정보를 확인하는 개인 페이지를 만든다.
이를 위해 그 사용자의 primary key가 필요하다. 특정 유저 객체에 부여된 고유한 키가 필요.
class AccountDetailView(DetailView):
model = User
template_name = 'accountapp/detail.html'
{% extends 'base.html' %}
{% block content %}
<div style="text-align: center; max-width: 500px; margin: 4rem auto;">
<div>
<p>
{{ user.date_joined }}
</p>
<h2 style="font-family: 'NanumSquareB'">
{{ user.username }}
</h2>
</div>
</div>
{% endblock %}
path('detail/<int:pk>', AccountDetailView.as_view(), name='detail')
이제 header.html에서 로그인이 안돼있으면 원래 그대로, 로그인이 되어 있으면 Mypage로 향하는 링크를 만들어 준다.
{% else %}
<a href="{% url 'accountapp:detail' pk=user.pk %}">
<span>Mypage</span>
</a>
<a href="{% url 'accountapp:logout' %}?next={{ request.path }}">
<span>logout</span>
</a>
{% endif%}
context_object_name이라는 것을 통해서 template에서 사용하는 user 객체 이름을 다르게 설정할 수 있다. 다른 사람이 우리 페이지를 오더라도 우리 페이지의 정보를 볼 수 있게 된다.
class AccountDetailView(DetailView):
model = User
context_object_name = 'target_user'
template_name = 'accountapp/detail.html'
<div>
<p>
{{ target_user.date_joined }}
</p>
<h2 style="font-family: 'NanumSquareB'">
{{ target_user.username }}
</h2>
</div>
UpdateView를 이용한 비밀번호 변경 구현하기
view.py에서 class 추가
class AccountUpdateView(UpdateView):
model = User
context_object_name = 'target_user'
form_class = UserCreationForm
success_url = reverse_lazy('accountapp:hello_world')
template_name = 'accountapp/update.html'
urls.py에서 경로 추가
path('update/<int:pk>', AccountUpdateView.as_view(), name='update')
update.html 생성
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
<div style="text-align: center; max-width: 500px; margin: 4rem auto">
<div class="mb-4">
<h4>
Change Info
</h4>
</div>
<form action="{% url 'accountapp:update' pk=target_user.pk %}" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
</form>
</div>
{% endblock %}
이제 detail 페이지에서 수정하는 주소로 가는 링크를 작성한다.
{% if target_user == user %}
<a href="{% url 'accountapp:update' pk=user.pk %}">
<p>
Change Info
</p>
</a>
{% endif %}
여기서 문제점은 아이디를 바꿔도 바뀐다는 것이다. 아이디는 바꿀 수 없도록 비활성화 해주는 작업을 한다.
accountapp에 forms라는 파일을 만들어서 views에서 작성을 했던 UpdateView에서 쓰인 form, 즉 UserCreationForm을 상속받아서 forms에서 커스터마이징을 한다.
from django.contrib.auth.forms import UserCreationForm
class AccountUpdateForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].disabled = True
이제 UpdateView의 form_class를 AccountUpdateForm로 바꿔준다.
이렇게 비활성화를 해도 전문가 모드에서 그 내용을 바꿀 수 있다. 하지만 그렇게 제출을 해도 아이디는 바뀌지 않는다.
DeleteView를 이용하여 회원 탈퇴 기능을 구현한다.
view.py
class AccountDeleteView(DeleteView):
model = User
context_object_name = 'target_user'
success_url = reverse_lazy('accountapp:login')
template_name = 'accountapp/delete.html'
urls.py
path('delete/<int:pk>', AccountDeleteView.as_view(), name='delete')
delete.html 생성
{% extends 'base.html' %}
{% block content %}
<div style="text-align: center; max-width: 500px; margin: 4rem auto">
<div class="mb-4">
<h4>
Quit
</h4>
</div>
<form action="{% url 'accountapp:delete' pk=user.pk %}" method="post">
{% csrf_token %}
<input type="submit" class="btn btn-danger rounded-pill col-6 mt-3">
</form>
</div>
{% endblock %}
detail.html에 링크 추가
<a href="{% url 'accountapp:delete' pk=target_user.pk %}">
<p>
Delete
</p>
</a>