django 04. 장고 개인 프로젝트 1 - 개발과정 기록

|

django 04. 장고 개인 프로젝트 (메모 앱)

첫 장고 개인 프로젝트 진행 중 새롭게 배운 부분을 정리하였습니다.

결과물

장고 프로젝트 준비

  • 가상환경(virtualenv) 설치 및 장고 설치
  • 프로젝트 및 app 생성 (setting.py 수정)

Model 클래스 작성

DB 연동을 위한 model class를 작성한다.

  • 모델 내에 모델 클래스 작성 (models.py)후, 장고에 migrate - DB 테이블과 유사
  • admin superuser 등록 후, admin.py에 모델 클래스 등록
  • 장고 가이드 문서 Model field reference 를 통해 model field의 data type, optiond 을 참고할 수 있다.
  • models.py 에 모델 클래스 작성 후, 장고에게 모델을 만들었다는 걸 알려줘야 한다.
$ python manage.py makemigrations
$ python manage.py migrate
  • 클래스 대표 값은 __str__ 메소드를 통해서 정의한다.
def __str__(self):
      return '%s by %s' % (self.title, self.name)
  • 작성 시간은 timezone 모듈을 사용한다. (models.py 코드예시)
from django.db import models
from django.utils import timezone

# Create your models here.
class Memos(models.Model):
    name = models.CharField(max_length = 20, db_column='이름')
    title = models.CharField(max_length = 50, db_column='제목')
    text = models.TextField(max_length = 150, db_column='내용', help_text='메모 내용은 150자 이내로 입력 가능합니다.')
    update_date = models.DateTimeField()
    priority = models.BooleanField(db_column='중요')

    def generate(self):
        self.update_date = timezone.now()
        self.save()

    def __str__(self):
        return '%s by %s' % (self.title, self.name)

views와 템플릿, 템플릿과 정적파일 연동

  • 템플릿 폴더 및 html 파일 작성 후, views와 연동
  • 템플릿 html 파일과 static css 파일 연동
  • static 파일 작성 후 장고에게 알려준다 - collectstatic
  • 템플릿 파일(html) 경로 : memo_app/template/memo_app/default.html
  • 정적 파일(css) 경로 : memo_app/static/css/default-style.css

MTV 연동하기

  • view에 model 클래스를 import 하고 데이터 불러오기
  • view에서 불러온 model 클래스 데이터를 template파일에 for문으로 적용하기

입력 - form 만들기, post 처리

  • app 폴더 내부에 forms.py 작성, 모델 클래스 추가
  • form.html 템플릿 작성
  • urls.py 추가 후에 view 와 연결(forms.py 데이터 가져오기), view와 템플릿 연결
  • post 분기 처리를 위한 views.py 수정

수정 - modify 처리

가이드 문서 찾아보고 적용 하느라 오래걸렸다..ㅠㅠ 조만간 이런때도 있었지 하고 추억하는 날이 오겠지!

url 패턴 추가 (urls.py)

primary key를 url 일부분으로 갖는 url 패턴 추가

urlpatterns = [
    ...
    url(r'^(?P<memokey>[0-9]+)/modify/$', views.modify, name='modify_memo'),
]

view에 modify 메소드 추가 (views.py)

클래스 PostForm import 필요 수정하는 화면 / 수정후 저장하는 POST request 분기 필요 기존에 존재하는 데이터는 form = PostForm(instance = memo) 를 통해 다시 가져올 수 있음

from .forms import PostForm

def modify(request, memokey): #memokey 변수를 url에서 가져온다
    if request.method == "POST":
        #수정 저장
        memo = Memos.objects.get(pk = memokey)
        form = PostForm(request.POST, instance=memo) # 새로 입력된 인스턴스 데이터를 form 인스턴스에 새로 담는다.
        if form.is_valid():
             form.save() # 변경한 form을 저장한다 (수정, 업데이트)
             return redirect('index')
    else:
        #수정 입력
        memo = Memos.objects.get(pk = memokey) # 특정 데이터를 인스턴스에 담는다.
        form = PostForm(instance = memo) # 기존에 존재하는 데이터를 가져온다. (수정화면에 내용 포함)
        return render(request, 'memo_app/modify.html', {'memo' : memo, 'form' : form})

modify.html 탬플릿 추가

인스터스로 가져온 form을 그대로 표시한다. (입력화면과 동일)


<form method="POST" class="post-form">
  {%csrf_token%}
  {{form.as_ul}}
  <button type="submit" class="save btn btn-default">저장</button>
</form>

각 데이터의 primary key를 url로 받도록 처리


<a href="{% url 'modify_memo' memokey=memo.pk %}" class="btn btn-primary modify" role="button">수정</a>

삭제 - delete 처리

url 패턴 추가 (urls.py)

primary key를 url 일부분으로 갖는 url 패턴 추가

urlpatterns = [
    ...
    url(r'^(?P<memokey>[0-9]+)/delete/$', views.delete, name='delete_memo'),
]

view에 delete 메소드 추가 (views.py)

memokey 를 primary key로 갖는 특정 데이터를 인스턴스로 받고, 해당 인스턴스 데이터를 삭제

def delete(request, memokey):
    memo = Memos.objects.get(pk = memokey)
    memo.delete()
    return redirect('index')

각 데이터의 primary key를 url로 받도록 처리

삭제버튼 클릭시 confirm 결과에 따라 submit을 취소 할 수 있다.


<a href="{% url 'delete_memo' memokey=memo.pk %}" class="btn btn-default del" role="button" onclick="return confirm('정말 삭제하시겠습니까?')">삭제</a>

170228_TIL

|

오늘 한 일

  • django 강의 를 들었다. MTV 패턴에 대해서 배우고 실제로 적용해 보았다. 새로운 개념이고 전부터 궁금했던 내용이라 재미있었다. nodejs, php와 유사한 부분들이 보여서 신기했다.

오늘 느낀 것

  • 정호영님 강의는 기대했던 만큼 재미있게 듣고 있다. 이고잉님과 다른 점은 가이드 문서를 보는 법에 대한 설명은 아직까지 없었다는 점이다. 나중에 혼자 장고 가이드 문서를 보면서 원하는 기능을 추가할 수 있을지 걱정이 되기는 하지만, 지금은 우선 수업 내용에 집중해야겠다.

내일 할 일

  • 장고 강의 듣기

django 05. python anywhere를 이용한 쉬운 배포

|

django 05. python anywhere 를 이용한 쉬운 배포

파이썬 웹 프로그래밍 - Django로 웹 서비스 개발하기
https://www.pythonanywhere.com/

설치전 요구사항

  • 로컬에 git 또는 sourceTree 설치하기
  • github 계정 생성
  • 로컬 프로젝트 github 에 업로드
  • 참고 강좌
    • https://opentutorials.org/course/1492
    • https://backlogtool.com/git-guide/kr/

pythonanywhere 회원가입

이메일만으로 쉽게 가입 가능

bash 실행

$ git clone https://github.com/honux77/lotto-web
$ tree lotto-web

virtualenv 설정

$ virtualenv --python=python3.5 lottoenv
$ source lottoenv/bin/activate
$ pip install django==1.10 whitenoise

서버 설정

$ cd lotto-web
$ python manage.py collectstatic
$ python manage.py migrate
$ python manage.py createsuperuser

web 메뉴 - virtualenv 설정

/home/<your-username>/your-env-name/

web 메뉴 - WSGI 설정

import os
import sys

path = '/home/<your-username>/<your-project-folder>/'  
if path not in sys.path:
    sys.path.append(path)

os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(get_wsgi_application())

secret key 생성

$ python genkey.py
  • 코드 내용
"""
Pseudo-random django secret key generator.
- Does print SECRET key to terminal which can be seen as unsafe.
"""

import string
import random

# Get ascii Characters numbers and punctuation (minus quote characters as they could terminate string).
chars = ''.join([string.ascii_letters, string.digits, string.punctuation]).replace('\'', '').replace('"', '').replace('\\', '')

SECRET_KEY = ''.join([random.SystemRandom().choice(chars) for i in range(50)])

print(SECRET_KEY)

settings.py 수정

  • bash에서 vi settings.py 입력후 아래 SECRET_KEY 내용을 genkey.py로 생성한 내용으로 대체
DEBUG=False
ALLOWED_HOST=[honux.pythonanywhere.com]
SECRET_KEY= '....'

배포 후, 수정사항 pythonanywhere에 반영하기

git push

  • python manage.py collectstatic 수행
  • 수정사항을 git push

git pull

  • 사이트내 Your consoles bash 실행
  • virtualenv 가 실행되어 있는지 확인
  • 프로젝트 상위 폴더에서 git pull 실행
    $ git pull origin master
    
  • 오류 발생시 git stash 등으로 해결 후, 아래 절차대로 진행
  • python manage.py collectstatic
  • python manage.py makemigrations
  • python manage.py migrate

Reload

  • web 메뉴에서 Reload 버튼을 선택하여 동기화
  • 사이트에서 반영사항 확인

django 03. 첫번째 장고앱 9 - 앱 다듬기

|

django 03. 첫번째 장고앱 9 - 앱 다듬기

파이썬 웹 프로그래밍 - Django로 웹 서비스 개발하기

urls.py 추가 (위치 : 프로젝트 폴더 - mysite)

  • detail 페이지를 추가한다.
  • 정규표현식 사용, url에 입력된 해당 숫자를 lottokey 변수에 argument perameter 로 담는다.

urlpatterns = [
    ...
    ...
    #lottokey라는 변수에 숫자로 된 url 부분이 전달된다.
    #url에서 view로 전달할 때 해당 perameter를 함께 전달한다.  
    url(r'^lotto/(?P<lottokey>[0-9]+)/detail/$', views.detail, name = 'detail'),
]

views.py 수정 (위치 : 앱 폴더 - mylotto)


def detail(request, lottokey): # perameter 'lottokey'를 함께 전달
    #primary key가 lottokey 파라미터와 일치하는 오브젝트를 가져온다.
    #primary key는 클래스의 오브젝트 생성시 자동으로 생성, .py 를 통해 가져올 수 있다.
    lotto = GuessNumbers.objects.get(pk = lottokey)
    return render(request, 'lotto/detail.html', {'lotto' : lotto})

detail.html 탬플릿 작성

  • post 페이지로 이동하는 버튼을 작성한다.
  • detail 페이지 탬플릿을 작성한다.

  <!DOCTYPE html>
  {% load staticfiles %}
  <html lang="ko">
  <head>
    <link rel="stylesheet" href="{% static 'css/lotto.css'%}">
  </head>

  <body>
    <div class="page-header">
    <h1>My Lotto Page</h1>
    </div>
    <div class="container lotto">
      <h2>{{lotto.text}}</h2>
      <p> by {{lotto.name}}</p>
      <p> {{lotto.update_date}}</p>
      <p> {{lotto.lottos|linebreaksbr}}</p>
    </div>
  </body>

default.html 탬플릿 수정

  • post 템플릿으로 연결하는 버튼을 추가한다.

<a href="{% url 'new_lotto'%}">
  <span class="glyphicon glyphicon-plus btn btn-default"></span>
</a>

  • 각 제목에 detail 링크를 추가한다.

<div class="page-header">
<h1>My Lotto Page
  <a href="{% url 'new_lotto' %}"><span class="glyphicon glyphicon-plus btn btn-default"></span></a></h1>
</div>

<h2><a href="{% url 'lotto_detail' lottokey=lotto.pk  %}">{{lotto.text}}</a></h2>

django 03. 첫번째 장고앱 8 - form 만들기, post 처리

|

django 03. 첫번째 장고앱 8 - form 만들기, post 처리

파이썬 웹 프로그래밍 - Django로 웹 서비스 개발하기

form 만들기

  • 장고 가이드 문서
  • 데이터를 입력 받는 form을 작성한다.
  • 작성경로 : lotto/mylotto/forms.py (app 폴더 내부)
  • forms.py 코드
from django import forms
from .models import GuessNumbers
# 모델클래스 GuessNumbers로 부터 데이터를 입력 받을 폼을 작성한다.

class PostForm(forms.ModelForm): #forms의 ModelForm 클래스를 상속 받는다.

    class Meta:
        model = GuessNumbers #GuessNumbers와 연결
        fields = ('name', 'text', 'num_lotto', ) # 그 중에 입력 받을 것

urls.py 수정

  • 프로젝트 폴더 내의 (mysite) urls.py 파일에서 form 페이지 경로를 지정한다.
    (url : /lotto/new/)
from mylotto import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^lotto/$', views.index, name = 'lotto'),
    url(r'^$', views.index, name = 'index'),
    url(r'^lotto/new/$', views.post, name = 'new_lotto'),
]

views.py 수정

  • lotto/new/ url과 연결할 views 오브젝트의 post 메소드를 작성한다.
    (일반적으로 form은 메소드 이름으로 post를 갖는다)
from .forms import PostForm

def post(request):
    form = PostForm() #forms.py의 PostForm 클래스의 인스턴스
    return render(request, 'lotto/form.html', {'form' : form})  # 템플릿 파일 경로 지정, 데이터 전달

form.html 템플릿 작성


<!DOCTYPE html>
{% load staticfiles %}
<html lang="ko">
 <head>
  <title>My Little Lotto</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
  <link href="//fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet">
  <link rel="stylesheet" href="{% static 'css/lotto.css' %}">
 </head>
 <body>
  <div class="page-header">
   <h1>My Little New Lotto</h1>
  </div>
  <div class="container lotto">
   <form method="POST" class="post-form">
       {%csrf_token%}  <!-- 보안이슈로 입력 -->
       {{form.as_p}}
     <button type="submit" class="save btn btn-default">Save</button>
   </form>
  </div>
 </body>
</html>


- {{ form.as_table }} will render them as table cells wrapped in <tr> tags
- {{ form.as_p }} will render them wrapped in <p> tags
- {{ form.as_ul }} will render them wrapped in <li> tags

post 처리

  • get으로 접속했을 때 화면과, post로 접속했을 때 화면을 분기한다.
  • redirect를 위해서는 from django.shortcuts import redirect 모듈이 필요하다.
  • redirect를 위한 경로는 url 절대경로가 아닌, urls.py 의 url name을 입력하면 된다.

views.py 수정

from django.shortcuts import render, redirect
from .forms import PostForm

def post(request):
    if request.method == "POST":
         # create a form instance and populate it with data from the request:
        form = PostForm(request.POST) #PostForm으로 부터 받은 데이터를 처리하기 위한 인스턴스 생성
        if form.is_valid(): #폼 검증 메소드
            lotto = form.save(commit = False) #lotto 오브젝트를 form으로 부터 가져오지만, 실제로 DB반영은 하지 않는다.
            lotto.generate()
            return redirect('index') #url의 name을 경로대신 입력한다.
    else:
        form = PostForm() #forms.py의 PostForm 클래스의 인스턴스
        return render(request, 'lotto/form.html', {'form' : form})  # 템플릿 파일 경로 지정, 데이터 전달