2016-04-07

(Python) pyenv 를 이용한 설치

  • pyenv 설치
    $ cd
    $ git clone git://github.com/yyuu/pyenv.git .pyenv
    $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
    $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
    $ echo 'eval "$(pyenv init -)"' >> ~/.profile
    $ source ~/.profile
  • 설치된 Python 목록 표시
    $ pyenv versions
  • 설치 가능한 Python 목록 표시
    $ pyenv install --list
  • Python 설치
    $ pyenv install -v 3.5.1
    $ pyenv rehash
  • pyenv-virtualenv 설치
    $ git clone git://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
  • 업그레이드
    $ cd ~/.pyenv
    $ git pull
    $ cd ~/.pyenv/plugins/pyenv-virtualenv
    $ git pull
  • venv27 가상환경 생성
    $ pyenv virtualenv 3.5.1 venv35
  • 가상환경 보기
    $ pyenv virtualenvs
  • 현재 디렉토리 이하에 가상환경 venv35 설정
    $ pyenv local venv35
    .python-version 파일이 생성됨.

(Django) Simple Tutorial (v1.9.5)

  • pyenv 로 원하는 python 버전을 설치한다.
    $ pyenv install -v 3.5.1
  • 프로젝트 디렉토리를 만들고 환경변수를 등록한다. ( export PRJNAME=/opt/project/prjname )
  • 프로젝트를 위한 python 가상환경을 생성한다.
    $ pyenv virtualenv 3.5.1 prjname
  • 프로젝트 디렉토리에 새로 생성한 가상환경을 적용한다.
    $ cd $PRJNAME
    $ pyenv local prjname
  • django, pycrypto 를 설치한다.
    $ cd $PRJNAME
    $ pip install django
    $ pip install pycrypto
    $ pip list
  • django 프로젝트를 생성한다.
    $ cd $PRJNAME
    $ django-admin startproject web
  • $PRJNAME/web 디렉토리에 다음 파일들을 만든다.
    makemigrations.sh
    python manage.py makemigrations prjname
    migrate.sh
    python manage.py migrate
    runserver.sh
    python manage.py runserver 0.0.0.0:8080
  • admin 앱 비활성화 하기.
    settings.py
    ...
     
    INSTALLED_APPS = [
        # 'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]
     
    ...
    urls.py
    ...
     
    from django.conf.urls import url
    # from django.contrib import admin
     
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
    ]
     
    ...
  • runserver.sh 를 실행하고 웹브라우저에서 잘 되는지 확인한다.
    $ cd $PRJNAME/web
    $ ./runserver.sh
  • 프로젝트에서 메인으로 사용할 앱을 생성한다.
    $ cd $PRJNAME/web
    $ python manage.py startapp prjname
  • $PRJNAME/web/web/settings.py 의 INSTALLED_APPS 에 'prjname.apps.PrjnameConfig' 을 추가한다.
  • models.py 를 삭제하고, models 디렉토리를 생성한다.
    $ cd $PRJNAME/web/prjname
    $ rm -rf models.py
    $ mkdir models
    $ cd models
    $ touch __init__.py
  • models 디렉토리에 crypto.py 를 생성한다.
    crypto.py
    # -*- coding: utf-8 -*-
    # prjname/models/crypto.py
     
    # 참고 :
    # http://third9.tistory.com/261
    # http://blog.dokenzy.com/archives/1997
     
    import base64
    from Crypto.Cipher import AES
     
    from django.conf import settings
     
     
    class MyCrypto:
        def __init__(self):
            BLOCK_SIZE = 32
            PADDING = '|'
            # The key argument should be the AES key,
            # either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
            # secret = "140b41b22a29beb4061bda66b6747e14"
            secret = settings.SECRET_KEY[:32] # AES-256
            cipher = AES.new(secret)
     
            pad = lambda s: s + (BLOCK_SIZE - len(s.encode('utf-8')) % BLOCK_SIZE) * PADDING
     
            self.encodeAES = lambda s: base64.b64encode(cipher.encrypt(pad(s)))
            self.decodeAES = lambda e: cipher.decrypt(base64.b64decode(e)).decode("utf-8").rstrip(PADDING)
     
        def encodeAES(self, data):
            encoded = self.encodeAES(data)
            return encoded
     
        def decodeAES(self, data):
            decoded = self.decodeAES(data)
            return decoded
  • Admin 모델을 생성한다. models 디렉토리에 admin.py 를 생성하고, __init.py__ 에 추가한다.
    admin.py
    # -*- encoding: utf-8 -*-
    # prjname/models/admin.py
     
    # 참고 :
    # http://third9.tistory.com/261
    # http://blog.dokenzy.com/archives/1997
     
     
    import hashlib
     
    from django.conf import settings
    from django.db import models
     
    from .crypto import MyCrypto
     
     
    class AdminModel(models.Model):
        userid     = models.CharField(max_length=255, unique=True)
        password   = models.CharField(max_length=255) # Hash
        nick       = models.CharField(max_length=255, unique=True)
        mobile     = models.CharField(max_length=255) # Encrypt
        reg_date   = models.DateField(auto_now_add=True)
        last_login = models.DateTimeField(null=True)
     
     
        class Meta:
            db_table = 'TB_ADMIN'
            app_label = 'prjname'
     
     
        def _get_mobile(self):
            crypto = MyCrypto()
            return crypto.decodeAES(self.mobile)
     
        def _set_mobile(self, value):
            crypto = MyCrypto()
            self.mobile = crypto.encodeAES(value)
     
        def _get_password(self):
            return self.password
     
        def _set_password(self, passwd):
            self.password = hashlib.sha256(passwd.encode('utf-8')).hexdigest()
     
     
        enc_mobile = property(_get_mobile, _set_mobile)
        hashed_password = property(_get_password, _set_password)
    __init__.py
    from prjname.models.admin import AdminModel
  • migration 을 생성하고, migrate를 실행한다.
    $ cd $PRJNAME/web
    $ ./makemigrations.sh
    $ ./migrate.sh
    이렇게 하면 $PRJNAME/web 에 db.sqlite3 DB에 TB_ADMIN 이라는 테이블이 생성될 것이다.
  • views.py 를 삭제하고, views 디렉토리를 생성한다.
    $ cd $PRJNAME/web/prjname
    $ rm -rf views.py
    $ mkdir views
    $ cd views
    $ touch __init__.py
    $ mkdir mgmt
    $ cd mgmt
    $ touch __init__.py
  • $PRJNAME/web/prjname/views/mgmt 에 helper.py 를 생성한다.
    # coding: utf-8
    # ------------------------------------------------------------------------------
    # mgmt/views/helper.py
    # ------------------------------------------------------------------------------
     
    import hashlib
    import datetime
    from functools import wraps
     
    from django.shortcuts import redirect
    from django.contrib import messages
     
     
    def login_required(f):
        @wraps(f)
        def decorated_function(request, *args, **kwargs):
            if "admin_login_yn" not in request.session:
                # messages.add_message(request, messages.INFO, '불법적인 접근입니다. 먼저 로그인하세요~!!!')
                # return redirect('login_form')
                # return redirect('http://naver.com/')
                return f(request, *args, **kwargs)
            return f(request, *args, **kwargs)
        return decorated_function
  • $PRJNAME/web/prjname/views/mgmt 에 admin.py 를 생성한다.
    # -*- encoding: utf-8 -*-
    # prjname/views/mgmt/admin.py
     
    from django.contrib import messages
    from django.shortcuts import render, redirect
     
    from ...models.admin import *
    from ...forms.mgmt.admin import *
    from .helper import login_required
     
     
    # 관리자 목록
    @login_required
    def index(request):
        admins = AdminModel.objects.all()
        return render(request, 'mgmt/admin/index.html', {'menu': 'admin', 'admins': admins})
     
     
    # 관리자 추가 폼
    @login_required
    def insert_form(request):
        form = AdminInsertForm()
        return render(request, 'mgmt/admin/insert_form.html', {'form': form})
     
     
    # 관리자 추가
    @login_required
    def insert(request):
        form = AdminInsertForm(request.POST)
        if form.is_valid():
            if form.cleaned_data['passwd1'] != form.cleaned_data['passwd2']:
                messages.add_message(request, messages.INFO, '비밀번호가 다릅니다. 관리자 비밀번호를 다시 입력해주세요.')
                return redirect('mgmt_admin_index')
     
            admin, dummy = AdminModel.objects.get_or_create(
                userid=form.cleaned_data['userid'],
                nick=form.cleaned_data['nick'],
            )
            admin.enc_mobile = form.cleaned_data['mobile']
            admin.hashed_password = form.cleaned_data['passwd1']
            admin.save()
            messages.add_message(request, messages.INFO, '관리자가 정상적으로 추가되었습니다.')
        else:
            # messages.add_message(request, messages.INFO, '입력 값을 다시 한번 확인하시어 관리자를 추가해주세요.')
            messages.add_message(request, messages.INFO, form.errors)
        return redirect('mgmt_admin_index')
     
     
    # 관리자 수정 폼
    @login_required
    def update_form(request, id):
        admin = AdminModel.objects.get(id=id)
        data = { 'id': admin.id,
                 'userid': admin.userid,
                 'nick': admin.nick,
                 'mobile': admin.enc_mobile }
        form = AdminUpdateForm(data)
        return render(request, 'mgmt/admin/update_form.html', {'form': form, 'admin_id': id})
     
     
    # 관리자 수정
    @login_required
    def update(request):
        form = AdminUpdateForm(request.POST)
        if form.is_valid():
            admin_id     = form.cleaned_data['id']
            admin_nick   = form.cleaned_data['nick']
            admin_mobile = form.cleaned_data['mobile']
     
            admin = AdminModel.objects.get(id=admin_id)
            admin.nick = admin_nick
            admin.enc_mobile = admin_mobile
            admin.save()
     
            messages.add_message(request, messages.INFO, '관리자가 정상적으로 수정되었습니다.')
        else:
            # messages.add_message(request, messages.INFO, '관리자 입력폼의 값을 제대로 입력해주세요.')
            messages.add_message(request, messages.INFO, form.errors)
        return redirect('mgmt_admin_index')
     
     
    # 비밀번호 수정 폼
    @login_required
    def password_form(request, id):
        admin = AdminModel.objects.get(id=id)
        data = {'id': admin.id,
                'userid': admin.userid,
                'nick': admin.nick }
        form = AdminPasswordForm(data)
        return render(request, 'mgmt/admin/password_form.html', {'form': form})
     
     
    # 비밀번호 수정 폼
    @login_required
    def change_password(request):
        form = AdminPasswordForm(request.POST)
        if form.is_valid():
            id      = form.cleaned_data['id']
            passwd1 = form.cleaned_data['passwd1']
            passwd2 = form.cleaned_data['passwd2']
            if passwd1 != passwd2 :
                messages.add_message(request, messages.INFO, '새로운 비밀번호와 다시 입력한 비밀번호가 일치하지 않습니다.')
                return redirect('mgmt_admin_index')
     
            admin = AdminModel.objects.get(id=id)
            admin.hashed_password = passwd1
            admin.save()
            messages.add_message(request, messages.INFO, '관리자 비밀번호가 정상적으로 수정되었습니다.')
        else:
            messages.add_message(request, messages.INFO, '입력 데이터가 올바르지 않습니다. 다시 변경해주세요.')
        return redirect('mgmt_admin_index')
     
     
    # 관리자 삭제
    @login_required
    def delete(request, id):
        AdminModel.objects.filter(id=id).delete()
        messages.add_message(request, messages.INFO, '해당 관리자를 정상적으로 삭제하였습니다.')
        return redirect('mgmt_admin_index')
  • forms 디렉토리를 생성한다.
    $ cd $PRJNAME/web/prjname
    $ mkdir forms
    $ cd forms
    $ touch __init__.py
    $ mkdir mgmt
    $ cd mgmt
    $ touch __init__.py
  • $PRJNAME/web/prjname/forms/mgmt 에 admin.py 를 생성한다.
    # -*- coding: utf-8 -*-
    # ----------------------------------------------------------------------------
    # File : prjname/forms/admin.py
    # Create Date : 2016-01-22
    # ----------------------------------------------------------------------------
     
    # import re
    # from django.core.exceptions import ObjectDoesNotExist
    from django import forms
    # from ..models.users import UserModel
     
     
     
    class AdminInsertForm(forms.Form):
        userid  = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'pattern':'[a-zA-Z0-9]+', 'required':True, 'autofocus':True, }))
        passwd1 = forms.CharField(max_length=255, widget=forms.PasswordInput(attrs={'class':'form-control', 'pattern':'[a-zA-Z0-9]+', 'required':True, }))
        passwd2 = forms.CharField(max_length=255, widget=forms.PasswordInput(attrs={'class':'form-control', 'pattern':'[a-zA-Z0-9]+', 'required':True, }))
        nick    = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'required':True, }))
        mobile  = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'required':True, }))
     
     
     
    class AdminUpdateForm(forms.Form):
        id     = forms.CharField(widget=forms.HiddenInput)
        userid = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'readonly':True, }))
        nick   = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'required':True, }))
        mobile = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'required':True, }))
     
     
     
    class AdminPasswordForm(forms.Form):
        id      = forms.CharField(widget=forms.HiddenInput)
        userid  = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'readonly':True, }))
        nick    = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'readonly':True, }))
        passwd1 = forms.CharField(max_length=255, widget=forms.PasswordInput(attrs={'class':'form-control', 'pattern':'[a-zA-Z0-9]+', 'required':True, }))
        passwd2 = forms.CharField(max_length=255, widget=forms.PasswordInput(attrs={'class':'form-control', 'pattern':'[a-zA-Z0-9]+', 'required':True, }))
  • $PRJNAME/web/web/urls.py 에 다음과 같이 추가해준다.
    urls.py
    from django.conf.urls import include, url
    # from django.contrib import admin
     
    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'', include('prjname.urls')),
    ]
  • $PRJNAME/web/prjname 에 urls.py 를 생성한다.
    urls.py
    from django.conf.urls import url
     
    from .views.mgmt import admin as mgmt_admin
     
    urlpatterns = [
        url(r'^mgmt/admin/$', mgmt_admin.index, name='mgmt_admin_index'),
        url(r'^mgmt/admin/insert_form$', mgmt_admin.insert_form, name='mgmt_admin_insert_form'),
        url(r'^mgmt/admin/insert$', mgmt_admin.insert, name='mgmt_admin_insert'),
        url(r'^mgmt/admin/update_form/(?P<id>[0-9]+)$', mgmt_admin.update_form, name='mgmt_admin_update_form'),
        url(r'^mgmt/admin/update$', mgmt_admin.update, name='mgmt_admin_update'),
        url(r'^mgmt/admin/password_form/(?P<id>[0-9]+)$', mgmt_admin.password_form, name='mgmt_admin_password_form'),
        url(r'^mgmt/admin/change_password$', mgmt_admin.change_password, name='mgmt_admin_change_password'),
        url(r'^mgmt/admin/delete/(?P<id>[0-9]+)$', mgmt_admin.delete, name='mgmt_admin_delete'),
    ]
  • templates 디렉토리를 만들어보자.
    $ cd $PRJNAME/web/prjname
    $ mkdir templates
    $ cd templates
    $ mkdir mgmt
    $ cd mgmt
  • $PRJNAME/web/prjname/templates/mgmt 에 base.html 을 생성한다.
    base.html
    <!DOCTYPE html>
    <html lang="ko">
    <head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Management</title>
     
    <link href="/static/b/css/bootstrap.min.css" rel="stylesheet">
     
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
     
    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="/static/b/js/bootstrap.min.js"></script>
    </head>
    <body>
    <!--
    <div class="alert alert-success alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    </div>
    <div class="alert alert-warning alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    </div>
    -->
    {% if messages %}
    <div class="alert alert-success alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      {% for message in messages %}
      {{ message }}
      {% endfor %}
    </div>
    {% endif %}
    <nav class="navbar navbar-inverse navbar-static-top">
      <div class="container">
        <div class="navbar-header"> <a class="navbar-brand" href="#">XManagement</a> </div>
     
        <div class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li {% if menu == 'admin' %}class="active"{% endif %}><a href="{% url 'mgmt_admin_index' %}">Admin</a></li>
            <li {% if menu == 'user'  %}class="active"{% endif %}><a href="">User</a></li>
            <li {% if menu == 'notice'  %}class="active"{% endif %}><a href="">Notice</a></li>
            <li {% if menu == 'faq'  %}class="active"{% endif %}><a href="">FAQ</a></li>
            <li {% if menu == 'qna'  %}class="active"{% endif %}><a href="">Q&A</a></li>
          </ul>
     
          <ul class="nav navbar-nav navbar-right">
            <li><a href="">Logout</a></li>
          </ul>
        </div>
      </div>
    </nav>
     
    <div class="container">
    {% block content %}{% endblock %}
    </div>
     
    <script>
    // Modal Remote Reload
    $(document).on('hidden.bs.modal', function (e) {
        $(e.target).removeData('bs.modal');
    });
     
    /*
    $("a[data-target=#updateModal]").click(function(ev) {
        ev.preventDefault();
        var target = $(this).attr("href");
     
        // load the url and show modal on success
        $("#updateModal .modal-body").load(target, function() {
             $("#updateModal").modal("show");
        });
    });
    */
    </script>
    </body>
    </html>
  • admin 디렉토리를 만들고, 그 안에 index.htmlinsert_form.htmlpassword_form.htmlupdate_form.html 파일을 생성한다.
    $ cd $PRJNAME/web/prjname/templates/mgmt
    $ mkdir admin
    index.html
    {% extends "mgmt/base.html" %}
    {% block content %}
    <div class="page-header">
      <h1>Administrator <small>(관리자)</small></h1>
    </div>
     
    <div style="text-align: right">
      <a href="{% url 'mgmt_admin_insert_form' %}" class="btn btn-default" data-toggle="modal" data-target="#myModal">관리자 추가</a>
    </div>
     
    <table class="table table-striped table-hover table-condensed" style="margin-top: 20px">
    <tr>
      <th style="text-align: center">아이디</th>
      <th style="text-align: center">별명</th>
      <th style="text-align: center">핸드폰</th>
      <th style="text-align: center">등록일</th>
      <th style="text-align: center">마지막접속시간</th>
      <th style="text-align: center">수정/삭제</th>
    </tr>
    {% for admin in admins %}
    <tr>
      <td style="text-align: center">{{ admin.userid }}</td>
      <td style="text-align: center">{{ admin.nick }}</td>
      <td style="text-align: center">{{ admin.enc_mobile }}</td>
      <td style="text-align: center">{{ admin.reg_date | date:"Y-m-d"}}</td>
      <td style="text-align: center">{% if admin.last_login != None %}{{ admin.last_login | date:"Y-m-d H:i:s" }}{% else %}-{% endif %}</td>
      <td style="text-align: center">
        <a href="{% url 'mgmt_admin_password_form' admin.id %}" class="btn btn-default btn-xs" data-toggle="modal" data-target="#myModal">비밀번호변경</a>
        <a href="{% url 'mgmt_admin_update_form' admin.id %}" class="btn btn-default btn-xs" data-toggle="modal" data-target="#myModal">수정</a>
        <button onclick="delete_admin('{% url 'mgmt_admin_delete' admin.id %}')" class="btn btn-default btn-xs">삭제</button>
      </td>
    </tr>
    {% endfor %}
    </table>
     
    <div id="myModal" class="modal fade" role="dialog" tabindex="-1" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
        </div>
      </div>
    </div>
     
    <script>
    function delete_admin(url) {
        var result = confirm("관리자를 정말로 삭제하시겠습니까?");
        if( result == false ) return;
        location.href = url;
    }
    </script>
    {% endblock %}
    insert_form.html
    <div class="modal-header">
      <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      <h4 class="modal-title">관리자 추가</h4>
    </div>
    <div class="modal-body">
      <form name="insert_form" action="{% url 'mgmt_admin_insert' %}" method="post">
        {% csrf_token %}
        <div class="form-group">
          <label>아이디 <small>(필수) 영문으로 입력해주세요.</small></label>
          {{ form.userid }}
        </div>
        <div class="form-group">
          <label>비밀번호 <small>(필수)</small></label>
          {{ form.passwd1 }}
        </div>
        <div class="form-group">
          <label>비밀번호 확인 <small>(필수)</small></label>
          {{ form.passwd2 }}
        </div>
        <div class="form-group">
          <label>별명 <small>(필수)</small></label>
          {{ form.nick }}
        </div>
        <div class="form-group">
          <label>핸드폰 <small>(필수)</small></label>
          {{ form.mobile }}
        </div>
        <div class="form-group" style="text-align: right">
          <input class="btn btn-primary" type="submit" value="관리자 추가" />
        </div>
      </form>
    </div>
    password_form.html
    <div class="modal-header">
      <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      <h4 class="modal-title">관리자 비밀번호 변경</h4>
    </div>
    <div class="modal-body">
      <form name="chg_passwd_form" action="{% url 'mgmt_admin_change_password' %}" method="post">
        {% csrf_token %}
        <div class="form-group">
          <label>아이디</label>
          {{ form.userid }}
          {{ form.id }}
        </div>
        <div class="form-group">
          <label>별명</label>
          {{ form.nick }}
        </div>
        <div class="form-group">
          <label>비밀번호 <small>(필수)</small></label>
          {{ form.passwd1 }}
        </div>
        <div class="form-group">
          <label>비밀번호 확인 <small>(필수)</small></label>
          {{ form.passwd2 }}
        </div>
        <div class="form-group" style="text-align: right">
          <input class="btn btn-primary" type="submit" value="관리자 비밀번호 변경" />
        </div>
      </form>
    </div>
    update_form.html
    <div class="modal-header">
      <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      <h4 class="modal-title">관리자 수정</h4>
    </div>
    <div class="modal-body">
      <form name="update_form" action="{% url 'mgmt_admin_update' %}" method="post">
        {% csrf_token %}
        <div class="form-group">
          <label>아이디</label>
          {{ form.userid }}
          {{ form.id }}
        </div>
        <div class="form-group">
          <label>별명 <small>(필수)</small></label>
          {{ form.nick }}
        </div>
        <div class="form-group">
          <label>핸드폰 <small>(필수)</small></label>
          {{ form.mobile }}
        </div>
        <div class="form-group" style="text-align: right">
          <input class="btn btn-primary" type="submit" value="관리자 수정" />
        </div>
      </form>
    </div>
  • runserver.sh 를 실행하고 http://IP주소:8080/mgmt/admin 으로 접속해보자.
    뭔가 화면이 나오긴 하는데, 디자인이 영 구리다. bootstrap 으로 디자인을 입혀보자.
    이미 base.html 에는 bootstrap 을 사용하도록 코딩이 되어 있으므로, bootstrap 을 다운 받아서 static 폴더에 복사만 해두면 된다.
    http://getbootstrap.com/ 에서 최신버전 (3.3.6)을 다운로드 받아서 풀어보자.
    $ cd $PRJNAME/web/prjname
    $ mkdir static
    $ cd static
    $ wget https://github.com/twbs/bootstrap/releases/download/v3.3.6/bootstrap-3.3.6-dist.zip
    $ unzip bootstrap-3.3.6-dist.zip
    $ mv bootstrap-3.3.6-dist b
    runserver.sh 를 실행하고 http://IP주소:8080/mgmt/admin 으로 접속해보면, 관리자 목록 화면이 나올 것이며, 추가/수정/삭제 작업을 할 수 있을 것이다.
  • 마지막으로, 로그인/로그아웃 처리를 하자.
    $PRJNAME/web/prjname/templates/mgmt 에 로그인화면 템플릿을 준비한다.
    index.html
    <!DOCTYPE html>
    <html lang="ko">
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="_xsrf" content="{{.xsrf_token}}" />
    <title>Management</title>
    <link rel="stylesheet" href="/static/b/css/bootstrap.min.css">
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    </head>
    <body>
    {% if messages %}
    <div class="alert alert-success alert-dismissible" role="alert">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
      {% for message in messages %}
      {{ message }}
      {% endfor %}
    </div>
    {% endif %}
     
    <div class="container">
      <div style="text-align:center; margin-top:150px; margin-bottom: 40px"><h1>Management</h1></div>
      <form action="{% url 'mgmt_login' %}" method="post" class="form-horizontal" style="margin: 0 auto; max-width: 360px;">
        {% csrf_token %}
        <div class="form-group">
          <label for="userid" class="col-sm-3 control-label">아이디</label>
          <div class="col-sm-9">
            {{ form.userid }}
          </div>
        </div>
        <div class="form-group">
          <label for="passwd" class="col-sm-3 control-label">비밀번호</label>
          <div class="col-sm-9">
            {{ form.password}}
          </div>
        </div>
        <input type="submit" class="btn btn-primary btn-block" value="로그인" />
      </form>
    </div>
     
    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="/static/b/js/bootstrap.min.js"></script>
    </body>
    </html>
  • $PRJNAME/web/prjname/views/mgmt 에 main.py 를 생성한다.
    # -*- encoding: utf-8 -*-
    # prjname/views/mgmt/main.py
     
    import hashlib
     
    from django.utils import timezone
    from django.contrib import messages
    from django.shortcuts import render, redirect
    from django.core.exceptions import ObjectDoesNotExist
     
    from ...models.admin import *
    from ...forms.mgmt.main import *
     
     
    def index(request):
        form = AdminLoginForm(request.POST)
        return render(request, 'mgmt/index.html', {'form': form})
     
     
    def login(request):
        form = AdminLoginForm(request.POST)
        if form.is_valid():
            try:
                hashed_password = hashlib.sha256(form.cleaned_data['password'].encode('utf-8')).hexdigest()
                admin = AdminModel.objects.get(userid=form.cleaned_data['userid'], password=hashed_password)
            except ObjectDoesNotExist:
                messages.add_message(request, messages.INFO, '아이디 또는 비밀번호가 틀렸습니다')
                return redirect('mgmt_index')
        else:
            messages.add_message(request, messages.INFO, '아이디 또는 비밀번호가 올바르지 않습니다.')
            return redirect('mgmt_index')
     
        admin.last_login = timezone.localtime(timezone.now())
        admin.save()
        request.session["admin_login_yn"] = "yes"
        request.session["admin_nick"] = admin.nick
        # request.session.set_expiry(0)
        return redirect('mgmt_admin_index')
     
     
    def logout(request):
        request.session["admin_login_yn"] = "no"
        del request.session["admin_login_yn"]
        return redirect('mgmt_index')
  • $PRJNAME/web/prjname/forms/mgmt 에 main.py 를 생성한다.
    # -*- coding: utf-8 -*-
    # ----------------------------------------------------------------------------
    # File : prjname/forms/mgmt/main.py
    # Create Date : 2016-01-26
    # ----------------------------------------------------------------------------
     
    # import re
    # from django.core.exceptions import ObjectDoesNotExist
    from django import forms
    # from ..models.users import UserModel
     
     
    class AdminLoginForm(forms.Form):
        userid   = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'class':'form-control', 'required':True, 'autofocus':True, 'placeholder':'당신의 ID를 입력하세요...', }))
        password = forms.CharField(max_length=255, widget=forms.PasswordInput(attrs={'class':'form-control', 'required':True, 'placeholder':'비밀번호를 입력하세요...', }))
  • $PRJNAME/web/prjname/urls.py 에 다음을 추가한다.
    ...
     
    from .views.mgmt import main  as mgmt_main
     
    ...
     
        url(r'^mgmt/$', mgmt_main.index, name='mgmt_index'),
        url(r'^mgmt/login$', mgmt_main.login, name='mgmt_login'),
        url(r'^mgmt/logout$', mgmt_main.logout, name='mgmt_logout'),
     
    ...
  • $PRJNAME/web/prjname/views/mgmt/helper.py 의 내용을 아래와 같이 변경한다.
    helper.py
    # coding: utf-8
    # ------------------------------------------------------------------------------
    # mgmt/views/mgmt/helper.py
    # ------------------------------------------------------------------------------
     
    import hashlib
    import datetime
    from functools import wraps
     
    from django.shortcuts import redirect
    from django.contrib import messages
     
     
    def login_required(f):
        @wraps(f)
        def decorated_function(request, *args, **kwargs):
            if "admin_login_yn" not in request.session:
                # messages.add_message(request, messages.INFO, '불법적인 접근입니다. 먼저 로그인하세요~!!!')
                return redirect('mgmt_index')
                # return redirect('http://naver.com/') # 인증되지 않은 접근을 시도하면 Naver 이로 이동한다.
            return f(request, *args, **kwargs)
        return decorated_function
  • base.html 의 Logout 부분을 아래와 같이 변경한다.
    base.html
    <li><a href="{% url 'mgmt_logout' %}">Logout</a></li>
    이제, http://IP주소:8080/mgmt/admin 으로 접근하면 Naver 로 이동하게 될 것이며, http://IP주소:8080/mgmt 으로 접근하면 로그인화면이 나오고, 로그인 처리도 될 것이다. 아울러, 관리자 화면의 우측 상단에 있는 Logout 을 클릭하면 로그아웃 처리되어서 로그인화면으로 이동할 것이다.