Mini Project: Pystagram 만들기
- 코드출처: 이한영의 Django 입문(디지털북스)
로그인/로그아웃 기능 구현
1. 로그인 기능
1.1 로그인 페이지
- 기본 구조 구성
- View: login_view
- Template: pystagram/templetes/users/login.html
- URL: pystagram/users/login/
templates/users/login.html
<!DOCTYPE html> <html lang="ko"> <body> <h1>로그인</h1> </body> </html>
users/views.py
from django.shortcuts import render def login_view(request): return render(request, 'users/login.html')
users/urls.py
from django.urls import path from users.views import login_view urlpatterns = [ path('login/', login_view), ]
config/urls.py
from django.urls import path, include urlpatterns = [ path("admin/", admin.site.urls), path("", index), path("users/", include("users.urls")), ]
1.2 로그인 여부에 따른 접속 제한
- 조건에 따른 View 동작 제어
- 이미 사용자가 브라우저에서 로그인을 했다면
- 피드 페이지로 이동
- 사용자가 로그인을 한 적이 없거나 로그아웃을 했다면
- 로그인 페이지로 이동
- 이미 사용자가 브라우저에서 로그인을 했다면
- 피드페이지 만들기
- 글 관리 앱(posts)을 생성한 후에는 posts 쪽의 페이지를 사용함 → 이 파일은 삭제될 예정임
templates/users/feeds.html
<!DOCTYPE html> <html lang="ko"> <body> <h1>피드 페이지</h1> </body> </html>
users/views.py
from django.shortcuts import render def feeds(request): return render(request, 'users/feeds.html')
users/urls.py
from django.urls import path from users.views import login_view, feeds urlpatterns = [ path('feeds/', feeds), ]
- 관리자 페이지를 사용한 로그인/로그아웃
- View 함수에 전달된 요청(reqest)에서 사용자 정보는 request.user 속성으로 가져올 수 있음
request.user 속성 중 is_authenticated 속성이 True이면 로그인 된 상태임
users/views.py
from django.shortcuts import render def feeds(request): user = request.user is_authenticated = user.is_authenticated print("user: ", user) print("is_authenticated: ", is_authenticated) return render(request, 'users/feeds.html')
- 터미널 콘솔에서 내용 확인 가능
- 로그인 여부에 따라 페이지 이동시키기
users/views.py
from django.shortcuts import render, redirect def login_view(request): if request.user.is_authenticated: return redirect("/users/feeds/") return render(request, 'users/login.html') def feeds(request): if not request.user.is_authenticated: return redirect("/users/login/") return render(request, 'users/feeds.html')
- 루트 경로에 접근 시, 로그인 여부에 따라 페이지 이동시키기
config/views.py
from django.shortcuts import redirect def index(request): if request.user.is_authenticated: return redirect("/users/feeds/") else: return redirect("/users/login/")
1.3 로그인 기능 구현
- Form 클래스를 사용한 로그인 페이지 구성
users/forms.py
from django import forms class LoginForm(forms.Form): username = forms.CharField(min_length=3) password = forms.CharField(min_length=4)
터미널에서 테스트하기
python manage.py shell
from users.forms import LoginForm login_data = {"username": "u", "password": "p"} form = LoginForm(data=login_data) form.is_valid() form.errors login_data2 = {"username": "Sample username", "password": "Sample password"} form2 = LoginForm(data=login_data2) form2.is_valid() form2.errors
Form 적용하기
users/views.py
from django.shortcuts import render, redirect from users.forms import LoginForm def login_view(request): if request.user.is_authenticated: return redirect("/users/feeds/") form = LoginForm() context = {"form": form} return render(request, 'users/login.html', context)
templates/users/login.html
... <body> <h1>로그인</h1> { { form.as_p }} </body> ...
- 웹 브라우저에서 확인해보기
- http://127.0.0.1:8000
- 생성(렌더링)된 HTML 살펴보기
- 화면은 잘 나오지만 <form> 태그가 포함되어있지 않음
- Form이 제대로 작동하려면 구성요소들이 <form> 태그 안에 있어야 함
- templates/users/login.html
- { % raw %} … { % endraw %} 구문은 블록코드 플러그인의 표기 문제 해결을 위한 것이므로 무시하도록 함
{ % raw %} ... <body> <h1>로그인</h1> <form method="POST"> { % csrf_token %} { { form.as_p }} <button type="submit">로그인</button> </form> </body> ... { % endraw %}
- View에 전달된 데이터를 Form으로 처리하기
users/views.py
def login_view(request): if request.user.is_authenticated: return redirect("/users/feeds/") if request.method == "POST": form = LoginForm(data=request.POST) print("form.is_valid(): ", form.is_valid()) print("form.cleaned_data: ", form.cleaned_data) context = {"form": form} return render(request, 'users/login.html', context) else: form = LoginForm() context = {"form": form} return render(request, "users/login.html", context)
- 터미널 콘솔에서 내용 확인 가능
- View에서 로그인 처리하기
users/views.py
from django.contrib.auth import authenticate, login from django.shortcuts import render, redirect from users.forms import LoginForm def login_view(request): if request.user.is_authenticated: return redirect("/users/feeds/") if request.method == "POST": form = LoginForm(data=request.POST) if form.is_valid(): username = form.cleaned_data["username"] password = form.cleaned_data["password"] user = authenticate(username=username, password=password) if user: login(request, user) return redirect("/users/feeds/") else: print("로그인에 실패했습니다.") context = {"form": form} return render(request, "users/login.html", context) else: form = LoginForm() context = {"form": form} return render(request, "users/login.html", context)
터미널에서 테스트하기
python manage.py shell
from django.contrib.auth import authenticate user = authenticate(username='a', password='b') print(user) user = authenticate(username='pystagram', password='1234') print(user)
2. 로그아웃 기능 구현
- 로그아웃 기본 구조 구현
- View: logout_view
- URL: /users/logout/
- Template: 없음
users/views.py
from django.contrib.auth import authenticate, login, logout from django.shortcuts import redirect ... def logout_view(request): logout(request) return redirect("/users/login/")
users/urls.py
from users.views import login_view, feeds, logout_view ... urlpatterns = [ path('login/', login_view), path('feeds/', feeds), path('logout/', logout_view), ]
templates/users/feeds.html
<!doctype html> <html lang="ko"> <body> <h1>피드 페이지</h1> <a href="/users/logout/">로그아웃</a> </body> </html>
3. 로그인 기능 개선
- 피드 페이지에 로그인 상태 표시
templates/users/feeds.html
<!doctype html> <html lang="ko"> <body> <h1>피드 페이지</h1> <div>{ { user.username }} (ID: { { user.id }})</div> <a href="/users/logout/">로그아웃</a> </body> </html>
- 로그인 실패 시 정보 표시
users/views.py
def login_view(request): ... if request.method == "POST": form = LoginForm(data=request.POST) if form.is_valid(): ... if user: ... else: form.add_error(None, "입력한 자격증명에 해당하는 사용자가 없습니다.")
- 로그인 페이지 CSS 스타일링, Form 기능 추가
templates/users/login.html
{ % raw %} { % load static %} <!doctype html> <html lang="ko"> <head> <link rel="stylesheet" href="{ % static 'css/style.css' %}"> </head> <body> <div id="login"> <form method="POST"> { % csrt_token %} { { form.as_p }} <button type="submit" class="btn btn-login">로그인</button> </form> </div> </body> </html> { % endraw %}
- style.css 다운로드
- 다운로드 후 /static/css/ 에 복사해 둘 것
users/forms.py
from django import forms class LoginForm(forms.Form): username = forms.CharField( min_length=3, widget=forms.TextInput( attrs={"placeholder": "사용자명 (3자리 이상)"}, ), ) password = forms.CharField( min_length=4, widget=forms.PasswordInput( attrs={"placeholder": "비밀번호 (4자리 이상)"}, ), )