코딩공부/홈페이지 만들기

Django로 홈페이지 만들기 - #2 회원가입, 로그인, 로그아웃

integerJI 2020. 5. 3. 23:45


참고 사이트

보고 배운 곳
https://code1018.tistory.com/244

 

model, admin 설정 
https://integer-ji.tistory.com/89

 

form을 이용한 글 수정 페이지 수정

https://integer-ji.tistory.com/102

 

오늘 사용한 App

myMember

 

설치해야 할pip

pip install django-betterforms
pip install Pillow

 

사용한 명령어

python manage.py createsuperuser
python manage.py makemigrations
python manage.py migrate

 

생성한 파일 & 폴더

myMember/templates/signup.html - 파일 생성

myMember/forms.py - 파일 생성

 

포인트

getbootstrap를 이용한 회원가입, 로그인 페이지 구축

usermodel의 확장

django form을 이용한 회원가입, 로그인 페이지 만들기

django에서 제공해주는 LoginView, LogoutView 사용

로그인할 때의 함수 로직

 

완성된 git ( 2020.06.18 키 노출로 인한 git 비공개 )

https://github.com/integerJI/int_1

 

aws key 노출되다.

https://integer-ji.tistory.com/200

 

aws key 생성시 주의 할점

https://integer-ji.tistory.com/208


사용한 디렉터리 계층구조 및 파일


myMember

<!-- myProject/myMember/templates/signup.html -->

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
        integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>
</head>

<body>
    <div class="mt-3 container">
        {% if messages %}
        <div class="alert alert-warning alert-dismissible fade show" role="alert">
            {% for message in messages %}
            <strong>{{ message.message }}</strong>
            {% endfor %}
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        {% endif %}
    </div>
    <div class="d-flex justify-content-center">
        <div class="mt-5 mb-5 text-muted text-center">
            <div class="card" style="width: 30rem;">
                <div class="card-body">
                    <h3 class="card-title">Eomu Hae</h5>
                        <hr>
                        <h5 class="card-subtitle mb-2 text-muted">Sign Up</h6>
                            <br>
                            <form class="form-signin" method="POST" action="{% url 'signup'%}"
                                enctype="multipart/form-data">
                                {%csrf_token%}
                                <div class="form-label-group">
                                    <input type="text" name="user-username" class="form-control" placeholder="Login Id"
                                        maxlength="15">
                                    <small class="text-muted">15자 이하 문자, 숫자 그리고 @/./+/-/_만 가능합니다.</small>
                                </div>
                                <br>
                                <div class="form-label-group">
                                    <input type="password" name="user-password1" class="form-control"
                                        placeholder="Password">
                                    <small class="text-muted">비밀번호는 최소 8자 이상이어야 합니다.</small>
                                </div>
                                <br>
                                <div class="form-label-group">
                                    <input type="password" name="user-password2" class="form-control"
                                        placeholder="Confirm Password">
                                    <small class="text-muted">비밀번호는 전부 숫자로 할 수 없습니다.</small>
                                </div>
                                <br>
                                <div class="form-label-group">
                                    <textarea class="form-control" id="id_profile-intro" rows="3" name="profile-intro"
                                        placeholder="About Me" maxlength="40"></textarea>
                                    <small class="text-muted">40자 이하 문자만 가능합니다.</small>
                                </div>
                                <br>
                                <div class="form-label-group">
                                    <input type="file" name="profile-profile_image" class="form-control-file"
                                        accept="image/*">
                                    <small class="text-muted">권장 크기 : 250 * 250</small>
                                </div>
                                <br>
                                <button type="submit" class="form-control">Sign Up</button>
                            </form>
                            <hr>
                            <a href="{% url 'signin' %}">
                                <button type="submit" class="form-control">Go back</button>
                            </a>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
<!-- myProject/myMember/templates/signin.html -->

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
        integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
        integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
        integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
        crossorigin="anonymous"></script>
</head>

<body>
    <div class="mt-3 container">
        {% if messages %}
        <div class="alert alert-warning alert-dismissible fade show" role="alert">
            {% for message in messages %}
            <strong>{{ message.message }}</strong>
            {% endfor %}
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        {% endif %}
    </div>
    <div class="d-flex justify-content-center">
        <div class="mt-5 mb-5 text-muted text-center">
            <div class="card" style="width: 30rem;">
                <div class="card-body">
                    <h3 class="card-title">Eomu Hae</h5>
                        <hr>
                        <h5 class="card-subtitle mb-2 text-muted">Sign In</h6>
                            <br>
                            <form class="form-signin" method="POST" action="{% url 'signin'%}">
                                {%csrf_token%}
                                <div class="form-label-group">
                                    <input type="text" name="username" class="form-control" placeholder="Id">
                                </div>
                                <br>
                                <input type="password" name="password" class="form-control" placeholder="Password">
                                <br>
                                <button type="submit" class="form-control">Sign In</button>
                            </form>
                            <hr>
                            <a href="{% url 'signup' %}">
                                <button type="submit" class="form-control">Sign Up</button>
                            </a>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
# myProject/myMember/admin.py

from django.contrib import admin
from .models import Profile

# Register your models here.
admin.site.register(Profile)
# myProject/myMember/forms.py

from django import forms
from django.db import models
from .models import Profile
from django.contrib.auth.models import User
from betterforms.multiform import MultiModelForm
from django.views.generic.edit import CreateView
from django.contrib.auth.forms import UserCreationForm

class DateInput(forms.DateInput):
    input_type = 'date'

class CreateUserForm(UserCreationForm):
    class Meta:
        model = User
        fields = ("username", "password1", "password2")
        widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control', 'placeholder':'15자 이내로 입력 가능합니다.'}),
            'password1' : forms.PasswordInput(attrs={'class': 'form-control'}),
            'password2' : forms.PasswordInput(attrs={'class': 'form-control'}),
        }

    def save(self, commit=True):
        user = super(CreateUserForm, self).save(commit=False) 
        if commit:
            user.save()
        return user

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['profile_image', 'intro',]

        widgets = {
            'intro': forms.TextInput(attrs={'class': 'form-control'}),
            'profile_image' : forms.ClearableFileInput(attrs={'class': 'form-control-file', 'onchange': 'readURL(this);'}),
        }

        labels = {
            'profile_image': '프로필 사진',
            'intro': '인사말',
        }

class UserCreationMultiForm(MultiModelForm):
    form_classes = {
        'user' : CreateUserForm,
        'profile' : ProfileForm,
    }
        
class LoginForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username', 'password']
# myProject/myMember/models.py

from django.db import models
from django.contrib.auth.models import User
from betterforms.multiform import MultiModelForm
from django import forms

class Profile(models.Model):
    class Meta:
        verbose_name = 'Profile'
        verbose_name_plural = 'Profile'

    user = models.OneToOneField(User, on_delete=models.CASCADE)
    nick = models.CharField(verbose_name='NickName', max_length=50, blank=True,)
    intro = models.TextField(blank=True, max_length=200, )
    profile_image = models.ImageField(blank=True, upload_to='usr')

    def __str__(self):
        return self.nick
# myProject/myMember/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('signup/', views.signup, name='signup'),
    path('signin/', views.signin, name='signin'),
    path('signout/', views.signout, name='signout'),
]
# myProject/myMember/views.py

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.contrib import auth
from django.contrib import messages
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.forms import UserCreationForm
from django.conf import settings
from django.views.generic.edit import CreateView
from django.views.generic.detail import DetailView
from django.urls import reverse_lazy
from django.views import generic, View
from django.contrib.auth.decorators import login_required
from .forms import UserCreationMultiForm, ProfileForm
from .models import Profile

def signup(request):
    if request.method == 'POST':
        if request.POST['user-password1'] == request.POST['user-password2']:
            form = UserCreationMultiForm(request.POST, request.FILES)
            if form.is_valid(): 
                user = form['user'].save()
                profile = form['profile'].save(commit=False)
                profile.user = user
                profile.nick = user
                profile.save()
                return redirect('signin')
            else:
                user = request.POST['user-username']
                user = User.objects.get(username=user)
                messages.info(request, '아이디가 중복됩니다.')
                return render(request, 'signup.html')
        else:
            messages.info(request, '비밀번호가 다릅니다.')
            return render(request, 'signup.html')
    return render(request, 'signup.html')


class Loginviews(LoginView):
    template_name = 'signin.html'

    def form_invalid(self, form):
        messages.error(self.request, '로그인에 실패하였습니다. Id 혹은 Password를 확인해 주세요.', extra_tags='danger')
        return super().form_invalid(form)

signin = Loginviews.as_view()


class LogoutViews(LogoutView):
    next_page = settings.LOGOUT_REDIRECT_URL
signout = LogoutViews.as_view()

 

myProject

# myProject/myProject/settings.py ( 추가 )

# 로그인 페이지 지정
LOGIN_URL = '/signin/'

# 로그인 완료 후 나올 페이지
LOGIN_REDIRECT_URL = 'index'

# 로그아웃 후 나올 페이지
LOGOUT_REDIRECT_URL = 'signin'

마무리