🤦♂️ django의 user model 사용
🤷♂️ 내가 만든 user model과 비교
- 데이터베이스 창을 열어보면 굉장히 많은 db 파일들이 존재한다. 내가 이번에 만든
my_user
와 tweet
을 제외한 파일들은 django에서 기본적으로 제공하는 db 파일들이다.
- django에서 기본적으로 제공하는 user model은
auth_user
다.
- 따라서 나는
my_user
와 auth_user
를 비교해보도록 하겠다.

- 우리가
auth_user
를 사용하게 된다면, django에서 기본적으로 제공하는 기능들을 사용할 수 있기 때문에 로그인 및 로그아웃
이 굉장히 쉬워진다.
🤷♂️ 나의 user model 업그레이드
- 클래스의 상속
- class B에서 class A의 기능들을 사용하고 싶다면 다음과 같이 괄호 안에 A를 넣어주면 된다.
class B(A):
def 기능_B_1:
return '기능_B_1'
- 우리가
user/models.py
에서 선언했던 UserModel
또한 위와 같은 구조로 이루어져 있다.
class UserModel(models.Model)
과 같이 작성함으로 인해 UserModel
에서 우리는 임포트 받아온 models의 Model 클래스의 기능을 사용할 수 있는 것이다.
from django.db import models
class UserModel(models.Model):
class Meta:
db_table = "my_user"
username = models.CharField(max_length=20, null=False)
password = models.CharField(max_length=256, null=False)
bio = models.CharField(max_length=256, default='')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
- 업그레이드
- 우리는 기본적으로 django에서 제공하는
auth_user
를 사용할 것이며, 그 테이블에 없는 내용인 bio
를 추가해 my_user
를 사용할 것이다.
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserModel(AbstractUser):
class Meta:
db_table = "my_user"
bio = models.CharField(max_length=256, default='')
- 이렇게 모델을 수정하고 나서
djangoProject/settings.py
로 들어가 내용을 수정해주어야 한다. (해당 파일 맨 밑으로 내려가 작성)
AUTH_USER_MODEL = 'user.UserModel'
🤷♂️ user model을 db에 적용시키기
- 우리가 맨처음
user
와 tweet
모델을 각각의 models.py
에 입력하고 난 후 한 작업이 있다.
- 터미널에 아래의 코드들을 입력하여 그 작업을 진행하고, django에게 우리의 db가 바뀐 것을 알려주도록 하겠다.
$ python manage.py makemigrations
# python manage.py migrate

- 위의 사진을 통해 확인할 수 있듯이
UserModel
의 값들 중 우리가 삭제한 값이 삭제되거나 변경되고, auth_user
에만 있던 값들이 우리의 모델에 추가되는 것을 볼 수 있다.
- 데이터베이스 창에서도 변경이 잘 되었는지 확인해보도록 하겠다.

🤷♂️ 회원가입 수정하기
- django의
get_user_model
을 사용해 회원가입을 수정해보도록 하겠다.
get_user_model
: 사용자가 데이터베이스 안에 있는지 검사하는 함수
- 회원가입을 할 때, django 서버로
POST
요청이 들어오게 된다. 따라서 우리는 POST
요청을 받는 부분을 수정할 것이다.
from django.shortcuts import render, redirect
from .models import UserModel
from django.http import HttpResponse
from django.contrib.auth import get_user_model
def sign_up_view(request):
if request.method == 'GET':
return render(request, 'user/signup.html')
elif request.method == 'POST':
username = request.POST.get('username', None)
password = request.POST.get('password', None)
password2 = request.POST.get('password2', None)
bio = request.POST.get('bio', None)
if password != password2:
return render(request, 'user/signup.html')
else:
not_new_user = get_user_model().objects.filter(username=username)
if not_new_user:
return render(request, 'user/signup.html')
else:
UserModel.objects.create_user(username=username, password=password, bio=bio)
return redirect('/sign-in')
- 위의 코드를 입력한 후, 회원가입 테스트를 진행하고 데이터베이스를 한 번 확인해 보았다.
- 방금 테스트를 진행했던
wjdeorms2
의 비밀번호가 자동으로 암호화된 것을 볼 수 있다.

🤷♂️ 로그인 수정하기
- 현재 모델은 로그인에 성공하게 되더라도 페이지 전환이 되지 않는다. 그 이유는 우리가
auth_user
를 우리의 UserModel
에 사용하게 되면서 비밀번호의 암호화
가 진행되었기 때문이다.
- 바로 위의 사진에서 보이듯 3번 row의 password가 암호화된 것을 볼 수 있다. 즉, db에서 사용자가 입력한 비밀번호에 대조하는 것이 저 암호화된 password이고, 사용자가 입력한 값은 암호화하기 전 비밀번호이기 때문에 항상 오류가 날 수 밖에 없다.
from django.contrib import auth
def sign_in_view(request):
if request.method == 'POST':
username = request.POST.get('username', None)
password = request.POST.get('password', None)
me = auth.authenticate(request, username=username, password=password)
if me is not None:
auth.login(request, me)
return HttpResponse(f'반갑습니다, {me.username} 님!')
else:
return redirect('/sign-in')
elif request.method == 'GET':
return render(request, 'user/signin.html')
🤦♂️ 로그인 이후 기능 다듬기
- 우리는 로그인이 되고 나서 하는 모든 행위들을
tweet
app과 관련된 페이지에서 진행할 것이다. 따라서 우리는 url을 연결하거나 어떤 행위들을 정의하는 것들 전부를 tweet
app 안에서 해결할 것이다.
🤷♂️ 로그인 성공 시 페이지 생성
- 우리가 로그인에 성공하더라도 지금까지는 사용자의 이름과 간단한 메세지만 빈 화면에서 보여주었기 때문에 그 부분을 수정하였다.
- 위에서 만든 회원가입과 로그인에 관한 페이지처럼
template 문법
을 사용해 작성해 우리가 base.html
의 내용을 다른 html 파일에 옮겨놓지 않더라도 base.html
의 내용 아래에 다른 html 파일들이 붙일 수 있다.
- 우선,
home
함수를 만들어 사용자 인증이 완료된다면 url
연결을 통해 화면을 이동시켜 준다.
tweet
함수를 통해 html로 연결시켜준다.
from django.shortcuts import render, redirect
def home(request):
user = request.user.is_authenticated
if user:
return redirect('/tweet')
else:
return redirect('/sign-in')
def tweet(request):
if request.method == 'GET':
return render(request, 'tweet/home.html')
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('tweet/', views.tweet, name='tweet'),
]
- djangoProject/urls.py
- 위와 같이 세팅을 다 마무리해도 막상 로그인을 해보면 페이지가 적용되지 않는 것을 알 수 있다.
- 맨 처음
user
app을 적용할 때를 생각해보자. 우리는 그때 user
app 안에 생성했던 user/urls.py
를 djangoProject/urls.py
에 include
함수를 사용해 추가해 주었다. 이번에도 같은 작업을 진행하도록 하겠다.
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('user.urls')),
path('', include('tweet.urls')),
]
- user/views.py
- 추가적으로 나의 경우 실수로
user/views.py
를 수정하지 않아서 계속 사용자의 이름만 로그인을 하면 나왔다. 아래 부분을 수정해야 한다.
if me is not None:
auth.login(request, me)
return redirect('/')
else:
return redirect('/sign-in')
🤷♂️ 사용자 정보 보여주기
- 로그인에 성공하게 되면 아래와 같은 화면이 나오게 된다. 하지만 빨간 네모 박스에서와 같이 로그인에 성공하게 되어도 사용자의 정보가 나오지 않고 있다.

- 따라서 해당 부분을 수정해보도록 하겠다.
- 사용자의 정보를 띄워줄 공간을 확보하기 위해 원래 있던 값들을 조금 수정하도록 하겠다.
<div class="col-md-3">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ user.username }}</h5>
<p class="card-text">{{ user.bio }}</p>
</div>
</div>
</div>

- templates/base.html
- 위의 사진에서도 볼 수 있듯이 우리가 이미 로그인을 한 상태임에도 불구하고 현 페이지에서는 우상단에서
Sign In
과 Sign Up
버튼을 볼 수 있다.
base.html
을 수정해 해당 현상을 고쳐보도록 하겠다.
template 문법
을 사용해 조건문을 형성해 주었고, 사용자 인증이 되지 않은 경우에만 우상단에 Sign In
과 Sign Up
버튼이 보이도록 조치하였다.
<form class="form-inline my-2 my-lg-0">
{% if not user.is_authenticated %}
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="/sign-in"> Sign In <span class="sr-only"></span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="/sign-up"> Sign Up <span class="sr-only"></span></a>
</li>
</ul>
{% else %}
{{ user.username }} 반갑습니다!
{% endif %}
</form>

🤷♂️ 로그인 오류
- 이번 오류를 수정하는 부분들은 전부 url을 통짜로 입력해 이동하는 것이므로 둘 다
GET
요청을 사용하는 부분들이다.
- 로그인을 하지 않아도 시크릿 모드를 통해 url을 작성해
http://127.0.0.1:8000/tweet/
에 들어가게 되면 로그인을 해야만 들어갈 수 있던 페이지에 들어갈 수 있게 된다.
- 해당 문제를 해결하기 위해 다음 페이지를 수정하도록 하겠다.
- 무작정 이 페이지로 들어온 것이 아니라, 우리는 url을 추적해서 들어오게 되었다.
tweet/
이 뚫렸기 때문에 tweet/urls.py
로 들어가 보았다.
- 해당 url은
tweet/views.py
의 tweet
함수를 실행하게 해준다. 따라서 tweet/views.py
로 들어왔고, 해당 함수를 수정하도록 하겠다.
def tweet(request):
if request.method == 'GET':
user = request.user.is_authenticated
if user:
return render(request, 'tweet/home.html')
else:
return redirect('/sign-in')
- 두 번째로 우리는 로그인을 이미 한 사용자이더라도 url에
/sign-up
이랑 /sign-in
을 입력하면 회원가입 및 로그인 페이지로 이동하는 것을 알 수 있다. 이 부분에 대한 수정도 진행하도록 하겠다.
- 아래 사진을 보면 이미 로그인을 했기 때문에 우상단에 아이디가 나오는데 로그인을 다시 할 수 있는 것을 볼 수 있다.

- user/views.py
- 위에서와 마찬가지로 사용자 인증이 완료된 경우에는 기본 url로 리다이렉트 시켜주어 사용자가 다른 페이지로 셀 수 없도록 하였다.
def sign_up_view(request):
if request.method == 'GET':
user = request.user.is_authenticated
if user:
return redirect('/')
else:
return render(request, 'user/signup.html')
def sign_in_view(request):
if request.method == 'POST':
username = request.POST.get('username', None)
password = request.POST.get('password', None)
me = auth.authenticate(request, username=username, password=password)
if me is not None:
auth.login(request, me)
return redirect('/')
else:
return redirect('/sign-in')
elif request.method == 'GET':
user = request.user.is_authenticated
if user:
return redirect('/')
else:
return render(request, 'user/signin.html')
- 여기서
/
을 사용한 이유는 tweet/views.py
에 있는 home
함수가 /
를 가지고 있기 때문이다. (`tweet/urls.py에서 기본 url 확인해봐)
- 아래의
home
함수를 보면 알 수 있듯이 사용자 인증이 완료되어 있는 경우에는 /tweet
으로 연결시켜 주기 때문에 기본 url을 적용해주었다.
def home(request):
user = request.user.is_authenticated
if user:
return redirect('/tweet')
else:
return redirect('/sign-in')
🤷♂️ 로그아웃 기능
- user/views.py
- django를 사용하기 때문에 세션이고 뭐고 다 때려치우고 이거 한줄이면 가능하다.
- 로그인을 한 사용자만이 접근할 수 있도록 조치를 하였다.
from django.contrib.auth.decorators import login_required
@login_required
def logout(request):
auth.logout(request)
return redirect('/')
- user/urls.py
- 위에서 생성한 함수에 접근할 수 있도록 url을 생성해보도록 하겠다.
- 그리고 이제 해당 url에 접근할 수 있는 트리거를 만들면 될 것 같다.
from django.urls import path
from . import views
urlpatterns = [
path('sign-up/', views.sign_up_view, name='sign-up'),
path('sign-in/', views.sign_in_view, name='sign-in'),
path('logout/', views.logout, name='logout'),
]
- templates/base.html
- 로그아웃 버튼을 상단 네비게이션 바에 만들고 싶기 때문에 우리는
base.html
로 이동해 작업을 진행하도록 하겠다.
- 아래와 같이 구조를 변경하여 이름 옆에 로그아웃 링크가 위치하게 하였고, 색을 빨간색으로 변경해 사용자가 잘 인식할 수 있도록 하였다.
{% else %}
<ul class="navbar-nav mr-auto">
<li class="nav-item disabled">
<span class="nav-link">
{{ user.username }} 님 반갑습니다!!
</span>
</li>
<li class="nav-item active">
<a style="color: red;" class="nav-link" href="/logout"> LOGOUT </a>
</li>
</ul>
{% endif %}

🤦♂️ 게시글 관리
🤷♂️ 게시글 쓰기
- 우선 어떤 html 파일에서 우리가 게시글을 쓸 수 있는지 파악해보자.
- 위의 사진을 보니 우리는
templates/tweet/home.html
에서 게시글을 쓸 수 있다. 그러므로 해당 파일로 가서 작업을 진행하도록 하겠다.
<form>
태그를 사용하므로 action과 method를 설정해주었다.
<div class="media-body">
<h5 class="mt-0">나의 이야기를 적어주세요</h5>
<p>
<form action="/tweet/" method="post">
{% csrf_token %}
<div class="form-group mb-2">
<textarea class="form-control" style="resize: none" name='my-content' id="my-content"></textarea>
</div>
<button type="submit" class="btn btn-primary" style="float:right;">작성하기</button>
</form>
</p>
</div>
- 우리가 위의
action
에서 정의했던 것과 같이 현재 사용하려는 url은 tweet/
이다. 그리고 이것을 tweet/urls.py
파일을 통해 확인해보면 이미 해당 url을 사용하고 있는 것을 알 수 있다.
- 그러므로 프론트에서
POST
방식으로 보내는 정보를 받아주고, 글을 쓰기 위해 필요한 동작을 정의해주는 함수를 views.py
에 있는 내용을 통해 수정해보도록 하겠다.
- 그 전에 어떤 정보가 넘어오는지 확인하도록 하겠다.
<textarea class="form-control" style="resize: none" name='my-content' id="my-content"></textarea>
- 우리는 textarea에 입력된 것을 가져오고, 해당 정보의 이름은
my-content
이다.
- 화면에서 입력한 정보를
POST
형식을 통해 가져오고, 이것을 db에 저장하는 코드를 작성하였다.
def tweet(request):
if request.method == 'GET':
user = request.user.is_authenticated
if user:
return render(request, 'tweet/home.html')
else:
return redirect('/sign-in')
elif request.method == 'POST':
user = request.user
my_tweet = TweetModel()
my_tweet.author = user
my_tweet.content = request.POST.get('my-content', '')
my_tweet.save()
return redirect('/tweet')
- 이렇게 하고 화면에 게시글을 입력해보면 화면에는 표시가 되지 않는 것을 알 수 있다. 반면
tweet
db에는 저장이 잘 된것을 알 수 있다. 따라서 우리는 화면에 GET 요청으로 데이터를 보내주는 것에 대한 수정을 진행해야 한다.

GET
요청을 통해 모든 트윗의 내용을 화면으로 넘겨주었다.
def tweet(request):
if request.method == 'GET':
user = request.user.is_authenticated
if user:
all_tweet = TweetModel.objects.all().order_by('-created_at')
return render(request, 'tweet/home.html', {'tweet': all_tweet})
else:
return redirect('/sign-in')
elif request.method == 'POST':
user = request.user
my_tweet = TweetModel()
my_tweet.author = user
my_tweet.content = request.POST.get('my-content', '')
my_tweet.save()
return redirect('/tweet')
- 이제 화면단으로 넘어가 작성된 글이 나오는 곳을 수정해보도록 하겠다.
<div class="row">
{% for tw in tweet %}
<div class="col-md-12 mb-2">
<div class="card">
<div class="card-body">
<div class="media">
<div class="media-body">
<h5 class="mt-0">{{ tw.content }}</h5>
</div>
<div style="text-align: right">
<span style="font-size: small">{{ tw.author.username }}-{{ tw.created_at|timesince }} 전</span>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
🤷♂️ 게시글 삭제
- 게시글이 가지고 있는 각자의 고유
id
값을 삭제하는 방법을 사용할 것이다.
- 우리는 글을 관리하는
tweet/views.py
에 들어가서 delete
함수를 생성할 것이다. 고고
from django.contrib.auth.decorators import login_required
@login_required
def delete_tweet(request, id):
my_tweet = TweetModel.objects.get(id=id)
my_tweet.delete()
return redirect('/tweet')
- 함수를 생성하였으니, 이제 이 함수를 사용할 수 있도록
tweet/urls.py
에 가서 url을 설정하도록 하겠다.
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('tweet/', views.tweet, name='tweet'),
path('tweet/delete/<int:id>', views.delete_tweet, name='delete-tweet'),
]
- 이제 화면으로 가서 해당 url을 사용할 수 있는 트리거를 만들어 보도록 하겠다.
<div class="row">
{% for tw in tweet %}
<div class="col-md-12 mb-2">
<div class="card">
<div class="card-body">
{% if tw.author == user %}
<div style="text-align: right">
<a href="/tweet/delete/{{ tw.id }}">
<span class="badge rounded-pill bg-danger">삭제</span>
</a>
</div>
{% endif %}
<div style="text-align: right">
<a href="#">
<span class="badge rounded-pill bg-success">보기</span>
</a>
</div>
<div class="media">
<div class="media-body">
<h5 class="mt-0">{{ tw.content }}</h5>
</div>
<div style="text-align: right">
<span style="font-size: small">{{ tw.author.username }}-{{ tw.created_at|timesince }} 전</span>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
- 위와 같이 코드를 작성하게 되면 아래와 같은 화면이 생성된다. 아래의 화면은 로그인한 사용자가 본인이 작성한 게시글을 볼 때의 화면이다.

🤦♂️ 3주차 숙제
templates/tweet/tweet_detail.html
파일 생성 후, 제공받은 코드를 입력해, 사용자가 보기
버튼을 누르게 되면 나오는 페이지를 생성했다.
- 현재 우리는 게시글의
보기
버튼을 눌러 해당 게시글에 대한 댓글을 작성하고 볼 수 있게 하는 것이 목표다. 따라서 나는 모델을 먼저 생성해보도록 하겠다.
class TweetComment(models.Model):
class Meta:
db_table = "comment"
tweet = models.ForeignKey(TweetModel, on_delete=models.CASCADE)
author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
comment = models.CharField(max_length=256)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
- 이제 모델을 사용하기 위해 모델을 등록해보도록 하겠다.
$ python manage.py makemigrations
$ python manage.py migrate

🤷♂️ url 연결
views.py
를 수정하기 전에, 어떤 url이 필요할지 생각해보자.
보기
버튼을 누르면 상세 페이지로 이동할 수 있는 url
- 상세 페이지에서
댓글을 작성
할 수 있는 url
- 작성한
댓글을 지울 수 있는
url
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('tweet/', views.tweet, name='tweet'),
path('tweet/delete/<int:id>', views.delete_tweet, name='delete-tweet'),
path('tweet/<int:id>', views.tweet_detail, name='tweet-detail'),
path('tweet/comment/<int:id>', views.write_comment, name='write-comment'),
path('tweet/comment/delete/<int:id>', views.delete_comment, name='delete-comment'),
]
🤷♂️ views.py 수정
- 위에서 url을 만들고, 각 url에서 쓰일 함수 이름을 정의하였다. 이제 그 이름에 맞는 함수를 만들고 기능을 정의해보록 하겠다.
@login_required
def tweet_detail(request, id):
my_tweet = TweetModel.objects.get(id=id)
comment = TweetComment.objects.filter(tweet_id=id).order_by('-created_at')
return render(request, 'tweet/tweet_detail.html', {'tweet': my_tweet, 'comment': comment})
@login_required
def write_comment(request, id):
if request.method == 'POST':
comment = request.post.get("comment", '')
current_tweet = TweetModel.objects.get(id=id)
tweet_comment = TweetComment()
tweet_comment.comment = comment
tweet_comment.author = request.user
tweet_comment.tweet = current_tweet
tweet_comment.save()
return redirect('/tweet/'+str(id))
@login_required
def delete_comment(request, id):
comment = TweetComment.objects.get(id=id)
current_tweet = comment.tweet.id
comment.delete()
return redirect('/tweet/'+str(current_tweet))
🤷♂️ home.html의 버튼 링크 수정
- 마지막으로
상세 페이지
에 들어가기 위해 링크를 설정해주어야 한다. 아직은 #
으로 설정되어 있다.
<div class="row">
{% for tw in tweet %}
<div class="col-md-12 mb-2">
<div class="card">
<div class="card-body">
{% if tw.author == user %}
<div style="text-align: right">
<a href="/tweet/delete/{{ tw.id }}">
<span class="badge rounded-pill bg-danger">삭제</span>
</a>
</div>
{% endif %}
<div style="text-align: right">
<a href="/tweet/{{ tw.id }}">
<span class="badge rounded-pill bg-success">보기</span>
</a>
</div>
<div class="media">
<div class="media-body">
<h5 class="mt-0">{{ tw.content }}</h5>
</div>
<div style="text-align: right">
<span style="font-size: small">{{ tw.author.username }}-{{ tw.created_at|timesince }} 전</span>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
