본문 바로가기

LIKELION 9th

[멋쟁이 사자처럼] Django로 블로그 만들기2 (회원가입, 로그인, 로그아웃)

지난 이야기🌿

7주 차에는 장고(Django)에서 CRUD기능을 구현했다.

 

 

8주 차(2021.05.17-2021.05.20)

8주 차에는 프로젝트에 새 앱을 만들어 회원가입, 로그인, 로그아웃 기능을 만들었다. 그리고 모델에 Comment 클래스를 추가해 댓글 기능을 추가했다. 이번 포스팅에서는 회원가입, 로그인, 로그아웃 기능을 만들어보자.

 

1. 새로운 앱 만들기

  • 유저 관련 기능을 담당할 새로운 앱 accounts를 만들었다.
  • 기능별로 앱을 만들면 유지 보수하기 좋다.
$ python manage.py startapp accounts

 

 

앱을 만든 후에는 꼭 프로젝트 폴더 settings.py에 아래와 같이 등록해주자.

#settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'main',
    'accounts',
]

 

2. urls.py - views.py - templates

1) urls.py

  • 지난 주차 까지는 프로젝트 폴더의 urls.py에서 모든 url을 관리했다.
  • 앱 별로 효율적인 url 관리를 위해 include를 활용해 urls.py를 분리해보자.
  • 각각의 앱에 urls.py를 만들고 아래와 같이 include를 사용하면 프로젝트의 urls.py와 연결할 수 있다. 
#firstproject/urls.py
from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('accounts/',include('accounts.urls')),
    path('',include('main.urls')),
]

* 프로젝트(firstproject)에 앱(main, accounts) 연결

 

#main/urls.py
from django.urls import path
from . import views

app_name="main"

urlpatterns = [
    path('', views.index, name='index'),
    path('create/', views.create, name='create'),
    path('detail/<int:write_id>', views.detail, name='detail'),
    path('update/<int:write_id>', views.update, name='update'),
    path('delete/<int:write_id>', views.delete, name='delete'),
]

* 게시판 기능(CRUD)을 가진 main 앱

 

#accounts/urls.py
from django.urls import path
from . import views

app_name = "accounts"

urlpatterns=[
    path('signup/',views.signup, name='signup'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
]

 

 

url을 분리하면 url name을 사용하는 템플릿 파일과 views.py를 수정해줘야 한다.

#main/views.py
def create(request):
    if request.method == "POST":
        create_form = WriteForm(request.POST)
        if create_form.is_valid():
            create_form.save()
        return redirect('main:index') #index에서 main:index로 변경
    else:
        create_form = WriteForm()
<!-- main/templates/index.html -->
···
    {% for write in all_write %}
    <div class="all_write">
        <a href = "{% url 'main:detail' write.id %}">
        <div>{{write.id}}</div><br>
        <div>{{write.title}}</div><br>
        <div>{{write.contents}}</div><br>
        <div>{{write.updated_at|date:"Y.m.d"}}</div><br>
        <a>
    </div>
    {% endfor %}
···

 

2) views.py

장고의 auth 기능에서 제공하는 User 객체를 사용했다.

#accounts/views.py
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib import auth
# Create your views here.

def signup(request):
    if request.method == "POST":
        if request.POST["password"] == request.POST["password2"]:
            user = User.objects.create_user(
                username=request.POST['username'], password=request.POST['password'],
            )
            user.save()
            auth.login(request,user)
            return redirect('main:index')
    else:
        return render(request,'signup.html')

def login(request):
    if request.method == "POST":
        username = request.POST["username"]
        password = request.POST["password"]
        user = auth.authenticate(request, username=username, password=password)
        if user is not None:
            auth.login(request,user)
            return redirect('main:index')
        else:
            message = '아이디 혹은 비밀번호가 틀렸습니다'
            return render(request, 'login.html', {'message':message})
    else:
        return render(request, 'login.html')

def logout(request):
    auth.logout(request)
    return redirect('main:index')

 

3) accounts/signup.html

{% extends 'base.html' %}
{% block title %}회원가입{% endblock %}
{% block content %}

<form method="POST" action="{% url 'accounts:signup'%}">
    {% csrf_token %}
    <label for="username">아이디:</label>
    <input type="text" name="username">
    
    <label for="password">비밀번호:</label>
    <input type="password" name="password">
    
    <label for ="password2">비밀번호 확인:</label>
    <input for="password2" name="password2">

    <button type="submit">회원가입하기</button>
</form>
{% endblock %}

signup.html

  • "POST"요청에 대해 장고에서 기본으로 제공하는 보안 수단인 {% csrf_token %} 태그 사용
  • <label>과 <input> 태그를 사용하여 아이디, 비밀번호, 비밀번호 확인 구현

* <label> 요소의 for 속성 값은 결합하고자 하는 요소의 id 속성 값과 같아야 한다.

 

 

4) accounts/login.html

{% extends 'base.html' %}
{% block title %}로그인{% endblock %}
{% block content %}
{% if message %}
<h1>{{message}}</h1>
{% endif %}

<form method="POST" action="{% url 'accounts:login'%}">
    {% csrf_token %}
    <label for="username">아이디:</label><br>
    <input type="text" name="username"><br>
    <label for="password">비밀번호:</label><br>
    <input type="text" name="password"><br>
    <button type="submit">로그인</button>
</form>
{% endblock %}

login.html

user 값이 None인 경우 만들었던 메시지(views.py) 출력

 

base.html

base를 사용해 templates를 관리하면 페이지를 이동해도 계속 존재하는 것들(nav bar 등)을 반복해서 작성하지 않아도 된다. 

#base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Document{% endblock %}</title>
</head>
<body>
    {% block content %}
    {% endblock %}
</body>
</html>

 

 

#base.html 활용
{% extends 'base.html' %} #base.html 상속받기

{% block static %}
<!-- static 코드(css 파일 연결 등) 작성 -->
{% endblock %}

{% block content %}
<!-- 내용 작성 -->
{% endblock %}

 

 

3. index.html 수정

  • 웹페이지 첫 화면(index.html)에서 로그인, 회원가입, 로그아웃 기능을 사용할 수 있도록 버튼으로 연결했다.
  • 유저 정보를 확인할 수 있도록 views.py의 index 함수에 user 변수를 추가하고 html 파일에서 표시했다.
#main/views.py
···
def index(request):
    user = request.user
    all_write = Write.objects.all()
    return render(request, 'index.html', {'all_write':all_write, 'user':user})
···
<!-- main/templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Donghae Blog</h1>
    <h2>{{user}}</h2>
    <button type="submit" class="create_btn"><a href="{% url 'accounts:login'%}">로그인</a></button>
    <button type="submit" class="create_btn"><a href="{% url 'accounts:signup'%}">회원가입</a></button>
    <button type="submit" class="create_btn"><a href="{% url 'accounts:logout'%}">로그아웃</a></button>
    
    <div class="create_write">
        <a href="{% url 'main:create'%}"><div class="create_btn">🙋‍♂️글쓰기🙋‍♂️</div></a>
    </div>

    {% for write in all_write %}
    <div class="all_write">
        <a href = "{% url 'main:detail' write.id %}">
        <div>{{write.id}}</div><br>
        <div>{{write.title}}</div><br>
        <div>{{write.contents}}</div><br>
        <div>{{write.updated_at|date:"Y.m.d"}}</div><br>
        <a>
    </div>
    {% endfor %}

</body>
</html>

 

마지막으로 결과 확인!

 

main/index.html
accounts/signup.html
로그인 후 index.html

 

로그아웃 후 index.html

 

 다음 글은 댓글 쓰기,,,🦁🔥

 

 


참고자료

 

django 기초 - templates 관리하기 (base.html)

base.html {% load static %} Document {% block style %} {% endblock %} {% block content %} {% endblock %} 기본적인 틀은 위와 같다. 여기에 필요에 따라 코드를 수정 및 추가하게 된다. 추..

inuplace.tistory.com

 

django urls include를 여러개 써서 효율적인 관리

2020-02-10-django url include multiple​ django를 쓸 때, 프로젝트의 url을 include를 써서 고정적인 url을 쉽게 관리하거나, 앱별로 url을 관리 할 수 있는 강력한 기능이 있다. 하지만 나는 사용하면서 하나의

velog.io

 

[Django] render 와 redirect 의 차이

render render(request, template_name, context=None, content_type=None, status=None, using=None) render 는 다음과 같은 파라미터들을 가집니다. 이 중에서 request 와 template_name 은 필수적으로 필요합니..

ssungkang.tistory.com

 

django login 유저 확장 방법 - 김땡땡's blog

장고의 auth 기능은 User 객체를 제공한다. 우리는 기본 default로 이 User 객체로 여러 인증을 구현할 수 있다. User model User model의 기본적으로 있는 여러 필드들이 있다. username 필수사항이다. 150자 이

yonghyunlee.gitlab.io