Skip to content

6-5. Account 어플리케이션 작성

INFO

회원가입, 로그인, 로그아웃 기능

6-5-1. Account 어플리케이션 만들기

  1. startapp accounts 생성
windows command
C:\hyungsik74\pycharm\dstagram-project> python manage.py startapp accounts
linux command 
$/home/hyungsik74/pycharm/dstagram-project> python manage.py startapp accounts

ch06-05-01_01.png 그림6-5-3

  1. config/setting.py 추가
py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'photo',
    'accounts',   #accounts app 추가
]
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'photo',
    'accounts',   #accounts app 추가
]

6-5-2. 로그인, 로그아웃 기능 추가

1. URL 추가

py
from django.urls import path
from django.contrib.auth import views as auth_view
from .views import *

# http://127.0.0.1:8000/accounts/profile/
# 1. profile 만들기
# 2. profile 페이지가 아닌 페이지로 보내기(a. 장고 설정변경, b. 웹 서버에서 설정)
urlpatterns = [
    path('login/',    auth_view.LoginView.as_view(), name="login"),
    path('logout/',   auth_view.LogoutView.as_view(template_name='registration/logout.html'), name="logout"),
    path('register/', register, name='register'),
]
from django.urls import path
from django.contrib.auth import views as auth_view
from .views import *

# http://127.0.0.1:8000/accounts/profile/
# 1. profile 만들기
# 2. profile 페이지가 아닌 페이지로 보내기(a. 장고 설정변경, b. 웹 서버에서 설정)
urlpatterns = [
    path('login/',    auth_view.LoginView.as_view(), name="login"),
    path('logout/',   auth_view.LogoutView.as_view(template_name='registration/logout.html'), name="logout"),
    path('register/', register, name='register'),
]
py
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('photo.urls')),
    # accounts 부분 추가
    path('accounts/', include('accounts.urls')),
]
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('photo.urls')),
    # accounts 부분 추가
    path('accounts/', include('accounts.urls')),
]

2. templates/base.html 수정

  • config/setting.py LOGIN_REDIRECT_URL = '/'
html
<div class="container">
    <header class="header clearfix">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="/">Dstagram</a>
            <ul class="nav">
                <li class="nav-item"><a href="/" class="active nav-link ">Home</a></li>
                <!-- 아래와 같이 수정합니다. -->
                {% if user.is_authenticated %}
                    <li class="nav-item"><a href="#" class="nav-link">Welcome, {{user.get_username}}</a></li>
                    <li class="nav-item"><a href="{% url 'photo:photo_upload' %}" class="nav-link">Upload</a></li>
                    <li class="nav-item"><a href="{% url 'logout' %}" class="nav-link">Logout</a></li>
                {% else %}
                    <li class="nav-item"><a href="{% url 'login' %}" class="nav-link">Login</a></li>
                    <li class="nav-item"><a href="{% url 'register' %}" class="nav-link">Signup</a></li>
                {% endif %}
            </ul>
        </nav>
    </header>
    {% block content %}
    {% endblock %}

    <footer class="footer">
        <p>&copy; 2023 Powered By Django.</p>
    </footer>
</div>
<div class="container">
    <header class="header clearfix">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="/">Dstagram</a>
            <ul class="nav">
                <li class="nav-item"><a href="/" class="active nav-link ">Home</a></li>
                <!-- 아래와 같이 수정합니다. -->
                {% if user.is_authenticated %}
                    <li class="nav-item"><a href="#" class="nav-link">Welcome, {{user.get_username}}</a></li>
                    <li class="nav-item"><a href="{% url 'photo:photo_upload' %}" class="nav-link">Upload</a></li>
                    <li class="nav-item"><a href="{% url 'logout' %}" class="nav-link">Logout</a></li>
                {% else %}
                    <li class="nav-item"><a href="{% url 'login' %}" class="nav-link">Login</a></li>
                    <li class="nav-item"><a href="{% url 'register' %}" class="nav-link">Signup</a></li>
                {% endif %}
            </ul>
        </nav>
    </header>
    {% block content %}
    {% endblock %}

    <footer class="footer">
        <p>&copy; 2023 Powered By Django.</p>
    </footer>
</div>

3. login, logout HTML 생성

  • accounts/templates/registration/login.html
  • accounts/templates/registration/logout.html
html
{% extends 'base.html' %}
{% block title %}- Login{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">Please enter your login information.</div>
            <form action="" method="post">
                {{form.as_p}}
                {% csrf_token %}
                <input class="btn btn-primary" type="submit" value="Login">
            </form>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}- Login{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">Please enter your login information.</div>
            <form action="" method="post">
                {{form.as_p}}
                {% csrf_token %}
                <input class="btn btn-primary" type="submit" value="Login">
            </form>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
html
{% extends 'base.html' %}
{% block title %}- Logout{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">You have been successfully logged out.</div>
            <a class="btn btn-primary" href="{% url 'login'%}">Click to Login</a>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}- Logout{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">You have been successfully logged out.</div>
            <a class="btn btn-primary" href="{% url 'login'%}">Click to Login</a>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}

4. setting.py 수정

  • config/setting.py LOGIN_REDIRECT_URL = '/'
py
# reverse_lazy 함수를 사용해서 다른 뷰를 적용할 수 있다.
LOGIN_REDIRECT_URL = '/'
# reverse_lazy 함수를 사용해서 다른 뷰를 적용할 수 있다.
LOGIN_REDIRECT_URL = '/'

6-5-3. 회원가입기능

  • 신규 및 수정이 필요한 파일 목록
1) accounts/forms.py
2) accounts/views.py
3) accounts/urls.py
4) accounts/templates/registration/register.html
5) accounts/templates/registration/register_done.html
6) templates/base.html
1) accounts/forms.py
2) accounts/views.py
3) accounts/urls.py
4) accounts/templates/registration/register.html
5) accounts/templates/registration/register_done.html
6) templates/base.html
  1. accounts/forms.py
py
from django.contrib.auth.models import User
from django import forms

# 폼 : 폼태그 -> HTML의 태그 -> 프론트단에서 사용자의 입력을 받는 인터페이스
# 장고의 폼 : HTML의 폼 역할, 데이터 베이스에 저장할 내용을 형식, 제약조건
class RegisterForm(forms.ModelForm):
    password = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email']

    def clean_password2(self):
        cd = self.cleaned_data
        if cd['password'] != cd['password2']:
            raise forms.ValidationError('Passwords not matched!')
        return cd['password2']
from django.contrib.auth.models import User
from django import forms

# 폼 : 폼태그 -> HTML의 태그 -> 프론트단에서 사용자의 입력을 받는 인터페이스
# 장고의 폼 : HTML의 폼 역할, 데이터 베이스에 저장할 내용을 형식, 제약조건
class RegisterForm(forms.ModelForm):
    password = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email']

    def clean_password2(self):
        cd = self.cleaned_data
        if cd['password'] != cd['password2']:
            raise forms.ValidationError('Passwords not matched!')
        return cd['password2']
  1. accounts/views.py
py
from django.shortcuts import render
from .forms import RegisterForm
# Create your views here.
# CRUD Create, Update

def register(request):
    if request.method == "POST":
        # 회원 가입 데이터 입력 완료
        user_form = RegisterForm(request.POST)
        if user_form.is_valid():
            new_user = user_form.save(commit=False)
            new_user.set_password(user_form.cleaned_data['password'])
            new_user.save()
            return render(request, 'registration/register_done.html',{'new_user':new_user})
    else:
        # 회원 가입 내용을 입력하는 상황
        user_form = RegisterForm()
    return render(request, 'registration/register.html', {'form':user_form})
from django.shortcuts import render
from .forms import RegisterForm
# Create your views here.
# CRUD Create, Update

def register(request):
    if request.method == "POST":
        # 회원 가입 데이터 입력 완료
        user_form = RegisterForm(request.POST)
        if user_form.is_valid():
            new_user = user_form.save(commit=False)
            new_user.set_password(user_form.cleaned_data['password'])
            new_user.save()
            return render(request, 'registration/register_done.html',{'new_user':new_user})
    else:
        # 회원 가입 내용을 입력하는 상황
        user_form = RegisterForm()
    return render(request, 'registration/register.html', {'form':user_form})
  1. accounts/urls.py
py
from django.urls import path
from django.contrib.auth import views as auth_view
from .views import *

# http://127.0.0.1:8000/accounts/profile/
# 1. profile 만들기
# 2. profile 페이지가 아닌 페이지로 보내기(a. 장고 설정변경, b. 웹 서버에서 설정)
urlpatterns = [
    path('login/',    auth_view.LoginView.as_view(), name="login"),
    path('logout/',   auth_view.LogoutView.as_view(template_name='registration/logout.html'), name="logout"),
    path('register/', register, name='register'),
]
from django.urls import path
from django.contrib.auth import views as auth_view
from .views import *

# http://127.0.0.1:8000/accounts/profile/
# 1. profile 만들기
# 2. profile 페이지가 아닌 페이지로 보내기(a. 장고 설정변경, b. 웹 서버에서 설정)
urlpatterns = [
    path('login/',    auth_view.LoginView.as_view(), name="login"),
    path('logout/',   auth_view.LogoutView.as_view(template_name='registration/logout.html'), name="logout"),
    path('register/', register, name='register'),
]
  1. accounts/templates/registration/register.html
py
{% extends 'base.html' %}
{% block title %}- Registration{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">Please enter your account information.</div>
            <form action="" method="post">
                {{form.as_p}}
                {% csrf_token %}
                <input class="btn btn-primary" type="submit" value="Register">
            </form>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}- Registration{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">Please enter your account information.</div>
            <form action="" method="post">
                {{form.as_p}}
                {% csrf_token %}
                <input class="btn btn-primary" type="submit" value="Register">
            </form>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
  1. accounts/templates/registration/register_done.html
py
{% extends 'base.html' %}
{% block title %}- Registration Done{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">Registration Success. Welcome, {{new_user.username}}</div>
            <a class="btn btn-info" href="/">Move to main</a>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}- Registration Done{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <div class="alert alert-info">Registration Success. Welcome, {{new_user.username}}</div>
            <a class="btn btn-info" href="/">Move to main</a>
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
  1. templates/base.html
py
<div class="container">
    <header class="header clearfix">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="/">Dstagram</a>
            <ul class="nav">
                <li class="nav-item"><a href="/" class="active nav-link ">Home</a></li>
                {% if user.is_authenticated %}
                <li class="nav-item"><a href="#" class="nav-link">Welcome, {{user.get_username}}</a></li>
                <li class="nav-item"><a href="{% url 'photo:photo_upload' %}" class="nav-link">Upload</a></li>
                <li class="nav-item"><a href="{% url 'logout' %}" class="nav-link">Logout</a></li>
                {% else %}
                <li class="nav-item"><a href="{% url 'login' %}" class="nav-link">Login</a></li>
                <li class="nav-item"><a href="{% url 'register' %}" class="nav-link">Signup</a></li>
                {% endif %}
            </ul>
        </nav>
    </header>
    {% block content %}
    {% endblock %}

    <footer class="footer">
        <p>&copy; 2020 Baepeu. Powered By Django 3</p>
    </footer>
</div>
<div class="container">
    <header class="header clearfix">
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="/">Dstagram</a>
            <ul class="nav">
                <li class="nav-item"><a href="/" class="active nav-link ">Home</a></li>
                {% if user.is_authenticated %}
                <li class="nav-item"><a href="#" class="nav-link">Welcome, {{user.get_username}}</a></li>
                <li class="nav-item"><a href="{% url 'photo:photo_upload' %}" class="nav-link">Upload</a></li>
                <li class="nav-item"><a href="{% url 'logout' %}" class="nav-link">Logout</a></li>
                {% else %}
                <li class="nav-item"><a href="{% url 'login' %}" class="nav-link">Login</a></li>
                <li class="nav-item"><a href="{% url 'register' %}" class="nav-link">Signup</a></li>
                {% endif %}
            </ul>
        </nav>
    </header>
    {% block content %}
    {% endblock %}

    <footer class="footer">
        <p>&copy; 2020 Baepeu. Powered By Django 3</p>
    </footer>
</div>

6-5-4. 댓글 기능 구현하기

기존에 구현되어 있는 댓글 앱 (disqus)

  1. python -m pip install django-disqus
windows command
C:\hyungsik74\pycharm\dstagram-project> python -m pip install django-disqus
C:\hyungsik74\pycharm\dstagram-project> python -m pip install six
linux command 
$/home/hyungsik74/pycharm/dstagram-project> python -m pip install django-disqus
$/home/hyungsik74/pycharm/dstagram-project> python -m pip install six
  1. config/setting.py
py
INSTALLED_APPS = [
    ...
    # 추가 부분
    'disqus',
    'django.contrib.sites',
]

# 추가 부분
DISQUS_WEBSITE_SHORTNAME = 'dstagram-django3'
SITE_ID = 1
INSTALLED_APPS = [
    ...
    # 추가 부분
    'disqus',
    'django.contrib.sites',
]

# 추가 부분
DISQUS_WEBSITE_SHORTNAME = 'dstagram-django3'
SITE_ID = 1
  1. python manage.py migrate
windows command
C:\hyungsik74\pycharm\dstagram-project> python manage.py migrate
linux command 
$/home/hyungsik74/pycharm/dstagram-project> python manage.py migrate
  1. photo/templates/photo/detail.html 수정
html
{% extends 'base.html' %}
{% block title %}
    {{object.text|truncatechars:10}}
{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <p><img src="{{object.photo.url}}" style="width:100%;"></p>
            <button type="button" class="btn btn-xs btn-info">
                {{object.author.username}}
            </button>
            <p>{{object.text|linebreaksbr}}</p>
            <a href="{% url 'photo:photo_delete' pk=object.id %}" class="btn btn-outline-danger btn-sm float-right">Delete</a>
            <a href="{% url 'photo:photo_update' pk=object.id %}" class="btn btn-outline-success btn-sm float-right">Update</a>
        </div>
        <div class="col-md-2"></div>
    </div>
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8">
            {% load disqus_tags %}
            {% disqus_show_comments %}
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}
    {{object.text|truncatechars:10}}
{% endblock %}

{% block content %}
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8 panel panel-default">
            <p><img src="{{object.photo.url}}" style="width:100%;"></p>
            <button type="button" class="btn btn-xs btn-info">
                {{object.author.username}}
            </button>
            <p>{{object.text|linebreaksbr}}</p>
            <a href="{% url 'photo:photo_delete' pk=object.id %}" class="btn btn-outline-danger btn-sm float-right">Delete</a>
            <a href="{% url 'photo:photo_update' pk=object.id %}" class="btn btn-outline-success btn-sm float-right">Update</a>
        </div>
        <div class="col-md-2"></div>
    </div>
    <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8">
            {% load disqus_tags %}
            {% disqus_show_comments %}
        </div>
        <div class="col-md-2"></div>
    </div>
{% endblock %}
  1. 권한제어 photo/views.py 수정
py
@login_required
def photo_list(request):
    # 보여줄 사진 데이터
    photos = Photo.objects.all()
    return render(request, 'photo/list.html', {'photos':photos})
@login_required
def photo_list(request):
    # 보여줄 사진 데이터
    photos = Photo.objects.all()
    return render(request, 'photo/list.html', {'photos':photos})
  1. 아마존 연동 Pass

아마존 AWS에 연동해서 파일을 저장하는 부분은 이 강의에서 생략하도록 하겠습니다. 추후 다른 방법으로 설명하도록 하게습니다.

  1. 헤로쿠

최근 헤로쿠 사이트 유로화로 인하여, 헤로쿠 연동 부분도 생략 하도록 하겠습니다. 배포 관련해서는 별도로 설명 하도록 하겠습니다.

Released under the MIT License.