회원가입, 로그인기능 추가
190410
__init__.py
: 패키지화 시켜줌
fake-insta3
-
회원가입 / 로그인 기능 추가
-
회원가입
- 새로운 app을 만들면서 시작 :
$ django-admin startapp accounts
- 앱 만들면
settings.py
에installed_apps
에 추가해 줘야 함- 원래 앱을
accounts
로 추가하는걸 권장하지 않음 :accounts.app.AccountsConfig
- 원래 앱을
- 혹시 app이름을 잘못한 경우 해당 앱에
apps.py
에 들어가서 클래스 이름과 안의 이름을 같이 수정해야 함
- 앱 만들면
- 새로운 app을 만들면서 시작 :
1
2
3
# insta-urls.py
## 추가
path('accounts/', include('accounts.urls')),
accounts
에urls.py
생성
1
2
3
4
5
6
7
8
9
10
# accounts-urls.py
from django.urls import path
from . import views
app_name = "accounts"
urlpatterns = [
# 회원가입
path('signup/', views.signup, name="signup"),
]
- 모델 정의
- 기존에 만들어진걸 가져다 씀, 나중에 커스터마이징
- 장고에서는 암호화 과정이 잘 되어 있어서 따로 라이브러리를 불러서 암호화 할 필요가 없음
- password는 안건드림
1
2
3
4
5
6
7
8
9
10
11
# accounts-views.py
## 라이브러리 불러오기
from django.contrib.auth.forms import UserCreationForm
def signup(request):
if(request.method == "POST"):
pass
else:
form = UserCreationForm()
return render(request, "accounts/signup.html", {"form":form})
UserCreationForm
에 저장되어있는 정보들
1
2
3
<tr><th><label for="id_username">Username:</label></th><td><input type="text" name="username" maxlength="150" autofocus required id="id_username"><br><span class="helptext">Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.</span></td></tr>
<tr><th><label for="id_password1">Password:</label></th><td><input type="password" name="password1" required id="id_password1"><br><span class="helptext"><ul><li>Your password can't be too similar to your other personal information.</li><li>Your password must contain at least 8 characters.</li><li>Your password can't be a commonly used password.</li><li>Your password can't be entirely numeric.</li></ul></span></td></tr>
<tr><th><label for="id_password2">Password confirmation:</label></th><td><input type="password" name="password2" required id="id_password2"><br><span class="helptext">Enter the same password as before, for verification.</span></td></tr>
1
2
3
4
5
6
7
8
9
# signup.html
{% extends "base.html" %}
{% block body %}
<form action="" method="post">
{% csrf_token %}
<input type="submit" name=""/>
</form>
{% endblock %}
form
은 왜form태그
와csrf_token
를 포함하지 않고 있을까?- 하나의 폼에서
post_form
과image_form
을 동시에 보여줄 때 포함하고 있으면 안됨 - 따라서 여러개의 폼을 필요로 할 때를 위해
input
만 가지고 있음
- 하나의 폼에서
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# accounts-views.py
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
def signup(request):
if(request.method == "POST"):
# post방식
form = UserCreationForm(request.POST)
if(form.is_valid()):
form.save()
return redirect("posts:list")
else:
# get방식
form = UserCreationForm()
return render(request, "accounts/signup.html", {"form":form})
-
회원가입 test해보고
admin페이지
에서 확인 -
signup.html 꾸미기
1
2
3
4
5
6
7
8
9
10
# singup.html
{% extends "base.html" %}
{% load bootstrap4 %}
{% block body %}
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" name=""/>
</form>
{% endblock %}
- 한글로 하고싶으면
settings.py
에서language code
를ko-kr
로 수정- 국제화 : Internationalization
-
commit
-
로그인
- migrate할 때 사용자 로그인 정보를 저장하기위해
django_sessions
라는 테이블을 만듦 - session을 이용해 로그인 로그아웃관리
- django의 default설정인
login
으로 .. - Authentication : 인증
- Authorization : 권한부여
- signup.html을 form.html로 수정해서 하나의 html로 회원가입과 로그인을 사용
- 이때 하나의 페이지를 공유하는데 어떻게
login
페이지 인지singup
페이지인지 ?- 분기처리를 통해서
- 아니면 html페이지를 두개 만들면 해결~
- 이때 하나의 페이지를 공유하는데 어떻게
- migrate할 때 사용자 로그인 정보를 저장하기위해
1
2
# accounts-urls.py
path('login/', views.login, name="login"),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# accounts-views.py
## 라이브러리 가져오기
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login as auth_login
def login(request):
if(request.method == "POST"):
form = AuthenticationForm(request, request.POST) # AuthenticationForm은 앞에 request를 넣어줘야 함
if(form.is_valid()):
auth_login(request, form.get_user())
return redirect("posts:list")
else:
form = AuthenticationForm()
return render(request, "accounts/form.html", {"form":form})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# accounts-form.html
{% extends "base.html" %}
{% load bootstrap4 %}
{% block body %}
{% if request.resolver_match.url_name == 'signup' %}
<h1>signup</h1>
{% else %}
<h1>login</h1>
{% endif %}
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" name=""/>
</form>
{% endblock %}
-
로그아웃
- 유저가 가지고 있는 session을 없애는것
1
2
# accounts-urls.py
path('logout/', views.logout, name="logout"),
1
2
3
4
5
6
# accounts-views.py
from django.contrib.auth import logout as auth_logout
def logout(request):
auth_logout(request)
return redirect("posts:list")
- 상태바 꾸미기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Instagram</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
</head>
<body>
<nav class="navbar sticky-top navbar-expand-lg navbar-light bg-light px-5">
<a class="navbar-brand" href="{% url 'posts:list' %}">
<i class="fab fa-instagram"></i> | Instagram
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarSupportedContent">
<ul class="navbar-nav">
{% if user.is_authenticated %}
<!--글쓰기, 마이페이지, 로그아웃-->
<li class="nav-item">
<a class="nav-link" href="{% url 'posts:create' %}">New</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">MyPage</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:logout %}">Logout</a>
</li>
{% else %}
<!--로그인, 회원가입-->
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:login %}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'accounts:signup %}">Signup</a>
</li>
{% endif %}
</ul>
</div>
</nav>
<div class="container">
{% block body %}
{% endblock %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
-
commit
-
로그인한 상태에서 게시물 불러올수있게
- 이제
create
는 로그인을 하지 않으면 접근할 수 없게 바뀜
- 이제
1
2
3
4
5
6
7
# posts-views.py
from django.contrib.auth.decorators import login_required
## 요기에 데코레이터를 붙여주면 됨
### create를 실행하기 전에 login_required를 실행시켜줌
@login_required
def create(request):
-
사용자가 자기가 게시물을 여러개 가질 수 있게 관계 설정
1
2
3
4
5
6
7
8
9
# posts-models.py
from django.conf import settings
class Post(models.Model):
content = models.CharField(max_length=100)
# 추가
## 실제로 user = settings.AUTH_USER_MODEL는 user = 'User'와 같은 말
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
- makemigrations -> 하고나면 오류가 나옴
- 그 이유는 이미 게시물이 생성되어있고 거기에 추가로 넣어줘야 하는데
1
2
3
4
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 1
# 1은 유저의 값이 없을 때 default값을 1로 주겠다라는 의미
1
2
3
# insta-forms.py
## '__all__'을 수정
fields = ['content',]
- 누가 작성했는지에 대한 정보를 추가
1
2
3
4
5
6
# posts-views.py
## 수정
if(post_form.is_valid()):
post = post_form.save(commit=False)
post.user = request.user
post.save()
1
2
3
4
5
# _post.html
## 추가
<div class="card-header">
<h5 class="card-text"></h5>
</div>
- 수정요청을 자기 자신거만 가능하게끔
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# posts-views.py
## 추가
@login_required
def update(request, id):
post = Post.objects.get(id=id)
if(post.user == request.user):
if(request.method == "POST"):
post_form = PostForm(request.POST, instance=post)
if(post_form.is_valid()):
post_form.save()
return redirect("posts:list")
else:
# post를 인스턴스로
post_form = PostForm(instance=post)
return render(request, 'posts/form.html', {"post_form":post_form})
else:
# 다른사람이 수정 요청을 보냈을 때
return redirect('posts:list')
- 권한이 있는 사람에게만 수정요청을 가능하게
1
2
3
4
5
6
# _post.html
{% if %}
<a href="{% url 'posts:update' post.id %}" class="btn btn-warning">수정</a>
<a href="{% url 'posts:delete' post.id %}" class="btn btn-danger">삭제</a>
{% endif %}
1
2
3
4
5
6
7
8
9
10
11
# posts-views.py
## delete
@login_required
def delete(request, id):
post = Post.objects.get(id=id)
if (post.user == request.user):
post.delete()
else:
# 다른 사람일 때
return redirect("posts:list")
return redirect("posts:list")