지난 포스팅에서 간단한 Diary web을 만들었고 이를 git에 올렸더니 위와 같은 경고 메세지가 떴다.
즉 내가 만든 github repository가 위험이 있다는 것이다. 즉 원래같으면
GitGuardian에서 위와 같이 떠야 하는데, At risk가 떴다는 것은 무엇인가를 해결해야 한다는 뜻이다.
자세히 에러 문구를 보면 위와 같이 open secret incident가 포함되어 있다고 나와있다. 에러 메세지를 더 클릭해보면 settings.py에서 SECRET_KEY가 포함되어 있고 이 secret_key는 비밀 값이기 때문에 프로젝트 코드에 포함되면 안되며, github에도 올리면 안된다.
그래서 우리는 이러한 시크릿 키를 별도의 JSON 파일에 적어서 별도로 관리해주게 된다. 먼저 그럼 우리는 secrets.json 파일을 만들어주도록 하자.
secrets.json 파일을 만들고 아래와 같이 코드를 추가해주자.
{
"SECRET_KEY": "<Django secret key>"
}
또는 settings.py에 원래 존재하던 secret_key 코드를 그대로 적어두어도 된다.
그리고 이제 settings.py에 들어가서 코드를 아래와 같이 수정해준다.
from pathlib import Path
import os
import json
from django.core.exceptions import ImproperlyConfigured
BASE_DIR = Path(__file__).resolve().parent.parent
ROOT_DIR = os.path.dirname(BASE_DIR)
secret_file = os.path.join(BASE_DIR, 'secrets.json') # secrets.json 파일 위치withopen(secret_file) as f:
secrets = json.loads(f.read())
defget_secret(setting, secrets=secrets):try:
return secrets[setting]
except KeyError:
error_msg = "Set the {} environment variable".format(setting)
raise ImproperlyConfigured(error_msg)
SECRET_KEY = get_secret("SECRET_KEY")
그런 다음에 이를 secret key를 git에는 ignore 해주겠다는 뜻으로 .gitignore에 다음과 같이 추가해준다.
# .gitignore
secrets.json
이런식으로 수정해주면 secret key를 별도로 관리할 수 있게 되며, git에서도 secret incident라는 알림이 사라지는 것을 볼 수 있다.
create 함수는 create.html 페이지로 render해주기 때문에 create.html 페이지를 새롭게 만들 필요가 있다. 미리 만들어놓은 templates/diary 폴더에 create.html 파일을 하나 만들어주고 새 일기를 추가할 때 화면을 작성해주면 된다.
먼저 사용자에게 보여줄 화면을 만들어주어야 한다. 사용자에게 보여줄 화면은 template이 담당하고 있고 특히나 중요한 것은 django에서는 무조건 html 파일을 templates 라는 폴더 안에서 찾기 때문에 templates라는 폴더를 하나 만들어주자. 그리고 전 포스팅에서도 언급했듯이, django에서는 여러 개의 앱을 같이 만들 수 있기 때문에 diary 폴더의 templates 안에 diary라는 이름의 폴더를 하나 더 만들어주자. 그리고 그 폴더 안에 index.html 파일을 하나 만들어주자. 그런 다음에 index.html 파일 안에 간단히 적어보자
를 적어보자. 위 명령어는 실제로 화면이 어떻게 나오는지를 살펴보기 위해 runserver를 해보겠다는 뜻이다.
그러면
위와 같이 나올 텐데 위 그림에서
빨간색으로 표시된 부분에 control을 누른 상태에서 클릭을 하면 인터넷 상에서 다음과 같은 창이 뜨는 것을 알 수 있을 것이다.
우리가 html 페이지를 작성했지만 아직 아무것도 나오지 않는 것을 알 수 있다. html 페이지가 보이기 위해서는 html 페이지를 보여달라고 요청하는 views.py가 필요하다.
따라서 diary/views.py에 들어가서 아래와 같이 index 함수를 작성해보자.
from django.shortcuts import render
# Create your views here.defindex(request):return render(request, 'diary/index.html')
다음으로 url 부분을 작성해주어야 한다. diary_project/urls.py에 들어가서 아래와 같이 코드를 수정해주자.
from django.contrib import admin
from django.urls import path
import diary.views
urlpatterns = [
path('admin/', admin.site.urls),
path('', diary.views.index, name='index')
]
즉 diary.views를 import 해주고 path를 하나 더 추가해준것이다. ' ' 라는 것은 기본 경로 (localhost:8000/) 로 url이 들어올 시에 두 번째 인자로 들어온 함수를 실행시켜주겠다는 것이다. 즉 만약 localhost:8000/ 로 들어오면 diary.views.index 함수를 실행시켜주는 것이고 diary.views.index 함수는 index.html 페이지를 render하고 있으니 index.html 페이지가 보이게 되는 것이다.
이렇게 하고 terminal에 python manage.py runserver를 입력하면,
이런식으로 html 페이지가 잘 나온 것을 알 수 있다.
다음 다시 diary_project의 urls.py 에 들어가서 urlpatterns에 하나를 더 추가해주도록 하겠다.
from django.contrib import admin
from django.urls import path
import diary.views
from django.conf.urls import include # 새로 추가
urlpatterns = [
path('admin/', admin.site.urls),
path('', diary.views.index, name='index'),
path('post/', include('diary.urls')), #새로 추가
]
이렇게 되면 localhost:8000/post/로 들어오는 것들은 diary.urls에서 처리해주겠다라는 말이 된다. 이렇게 코드를 작성해주면 diary/urls가 없기 때문에 에러가 나게 될 것이다.
따라서 diary 폴더 안에 urls.py를 새로 하나 만들어 주고 아래와 같이 코드를 적어준다.
from django.urls import path
from diary import views
urlpatterns = [
path('', views.index, name='index'), # 'localhost:8000/post/'
]
post/로 들어왔을 때도 views.index를 보여주겠다라는 것이므로 views.index함수를 두 번째 인자로 적어준다.
다음으로는 model을 작성해주어야 한다.
diary에 models.py 파일에 아래와 같이 코드를 작성해주자. 각각의 필드는 다른 것을 사용해도 된다. 나는 diary에 필요한 필드로 우선 제목, 내용, 그리고 만족도를 넣어주었고 title과 만족도는 굳이 길지 않아도 되니, max_length를 지정해주고 CharField 타입으로 정해주었다.
from django.db import models
from django.utils import timezone
# Create your models here.classPost(models.Model):
title = models.CharField(max_length=256)
content = models.TextField()
satisfaction= models.CharField(max_length=1)
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(blank=True, null=True)
defupdate_date(self):
self.updated_at = timezone.now()
self.save()
def__str__(self):return self.title
이제 모델이 바뀌었으니 다시 view.py와 index.html을 바꾸어주어야 한다. view.py에서는 각각의 post 객체를 모두 다 index.html로 넘겨주도록 하겠다.
그래서 우선 객체를 받아서 이를 넘겨주는 식으로 아래와 같이 view.py를 수정해주었다.
from django.shortcuts import render
from .models import Post
# Create your views here.defindex(request):
posts=Post.objects.all()
return render(request, 'diary/index.html', {'posts': posts})
그 다음에 template에 있는 index.html도 받은 post 객체를 화면에 띄울 수 있도록 수정해준다.
이렇게 하면 posts라는 모든 객체 중에 for문을 돌면서 하나의 객체 post에 대해 title, satisfaction, content를 출력해준다.
이렇게 해서 models, view, urls, templates 의 관계를 알아보았다. 이를 우리는 django에서 MTV 패턴이라고 한다. MTV 패턴은 Model, Template, View의 약자로 이 세 가지가 연계되는 패턴을 의미한다. 위의 설명을 잘 따라갔다면 이것이 무엇을 의미하는지 이해할 수 있을 것이다.
Model은 데이터를 저장하는 형태를 설정하고, Template 안에 있는 html 파일에서 유저에게 보여줄 화면을 설정하고, View에서 데이터를 처리하여 html 파일과 연결시켜준다.
이러한 django의 MTV 패턴을 잘 익혀두면 전반적인 큰 그림을 이해하기 쉽기 때문에 오래 걸리더라도 이해해보자.
여기까지 하면 django의 MTV 패턴을 이해할 수 있지만 새로운 posting을 추가하거나, 삭제하거나, 수정할 수 없다. 다음 포스팅에서는 diary의 추가적인 기능을 구현해보도록 하겠다.
sleep 함수는 파이썬에서 프로그램을 일시정시한다, 즉 재운다 (sleep)이라는 의미를 가지고 있다.
원하는 시간 후에 프로그램을 실행시키고 싶거나 thread에서 자주 사용되는 함수이다.
sleep 함수는 파이썬에서 프로그램을 일시정시한다, 즉 재운다 (sleep)이라는 의미를 가지고 있다.
원하는 시간 후에 프로그램을 실행시키고 싶거나 thread에서 자주 사용되는 함수이다.
먼저 sleep 함수를 사용하기 위해서는 time library를 import 해주어야 한다.
import time
이후에 sleep 함수의 () 안에 정지하고자 하는 초를 써주면 된다.
그리고 datetime library를 통해 sleep 함수를 더 잘 알아볼 수 있다.
import datetime # 날짜 시간 출력을 위한 importimport time # sleep 함수를 위한 importprint("#####test 시작#####")
now = datetime.datetime.now()
print("*show time before sleep:", now.strftime('%H:%M:%S')) # sleep 함수 사용 전 시간 출력#sleep 함수 적용
time.sleep(5) # 5 초 딜레이
now = datetime.datetime.now()
print("*show time after sleep:", now.strftime('%H:%M:%S')) #sleep 함수 사용 후 시간 출력
위의 예시의 코드 실행 결과는 아래와 같다.
이런식으로 출력된 것을 볼 수 있다. 정확히 우리가 sleep 시켰던 5초동안 delay가 있었던 것을 알 수 있다.
위에서는 5초 동안의 delay를 주기 위해서 time.sleep(5) 라는 식으로 적어주었지만,
time 함수가 꼭 정수로 1초,2초,3초... 만 가능한 것은 아니다.
time.sleep() 괄호 안에 들어가는 parameter는 정확히 말해 float 형태이기 때문에 0.1, 0.01 등과 같이 소수점이 있어도 parameter에 들어갈 수 있어, 정교한 작업이 가능하다.
예시로 0.125초 만큼 sleep을 시켜보도록 하겠다.
참고로 밀리세컨즈 단위를 출력하기 위해서는 추가로 .%f 를 쓰고 소수점 단위를 지정해주면 된다.
import datetime
print(now.strftime('%H:%M:%S.%f')[:-3]) # 현재 시간 소수점 아래 3자리까지 출력
위와 같이 원하는 소수점 단위를 출력해주면 되며, 이를 사용하여 0.125초만큼 sleep을 시켜주고 실제 time이 0.125초만큼 차이가 나는지 살펴보도록 하자.
import datetime
import time
print() #여백을 위해..print("##########test 시작##########")
now = datetime.datetime.now()
print("*show time before sleep:", now.strftime('%H:%M:%S.%f')[:-3]) # sleep 함수 사용 전 시간 출력
time.sleep(0.135) # 5 초 딜레이
now = datetime.datetime.now()
print("*show time after sleep:", now.strftime('%H:%M:%S.%f')[:-3]) # sleep 함수 사용 후 시간 출력print()
이런식으로 0.125초 동안 sleep이 잘 된 것을 알 수 있다.
time.sleep() 함수는 간단한 것처럼 보이지만 thread 등에서도 유용하게 활용될 수 있으니 잘 알아두도록 하자.
가장 대표적으로 예시를 생각해보았을 때, 만약 문자열이 띄어쓰기를 기준으로 "a b c d z k" 이런 식으로 있다면 우리는 이 문자열을 띄어쓰기를 기준으로 쪼개서 각각 list의 0번째에는 a가, list의 1번째에는 b가 2번째에는 c가...
이렇게 들어갈 수 있도록 만들고 싶은 것이다.
이처럼 파이썬은 이와 같은 경우에 split 함수를 사용한다.
split 함수도 간단해보이지만 parameter에 무엇이 들어가냐에 따라 조금씩 사용법이 달라지게 된다.
1. 문자열.split() => 디폴트로 띄어쓰기와 엔터에 의해 구분되는 경우
가장 대표적으로 split 함수를 적용할 수 있는 경우이다.
어떤 기준에 의해 split 되는지가 명시되어 있지 않은 경우에는 default로 띄어쓰기와 엔터에 의해 구분된다.
즉, 위에서 예시로 들었던 것과 같이
s= "a b c d e f g"
div= s.split()
이라고 했을 경우 div 에는 각각 a/b/c/d/e/f/g 로 쪼개진 배열이 만들어진다고 생각하면 된다.
2. 문자열.split( '구분자' ) => 원하는 구분자로 split하고 싶을 경우
반면 모든 문자열이 띄어쓰기로 구분이 되어있지 않을 수도 있다. 예를 들어 "a/b/c/d"라는 문자열이 있다면 우리는 "/" 에 의해 구분하고 싶을 것이다. 이처럼 띄어쓰기가 아닌 다른 구분자에 의해 문자열을 구분하고 싶다면 split 함수 괄호 안에 구분하고 싶은 구분자를 써준다.
마찬가지로 아주 간단한 예시를 들어보자.
s= "a.b.c.d.e.f.g"
div= s.split('.')
1번의 경우와 거의 동일하지만 이번에는 구분자가 띄어쓰기가 아닌 '.' 인것만 다르다. 이럴 경우에 split 함수 괄호 안에 ','를 써서 구분할 수 있다.
명시적으로 구분자가 '.' 다 라고 말하는 방법도 있다.
바로 split (sep ='.')를 사용하는 것이다.
s= "a.b.c.d.e.f.g"
div= s.split(sep= '.')
이는 위와 같은 문법이지만 조금 더 명시적으로 나는 점에 의해 구분하고 싶다라는 의미의 가독성을 높여준다.
3. 문자열.split(sep= '구분자', maxsplit = 숫자) => 모든 구분자로 split 하지 않고 나누는 최대 횟수를 제한하고 싶을 때
문자열을 구분하고는 싶으나 나누는 최대 횟수를 제한하고 싶을 때가 있다.
예를 들어 aa.bb.cc.dd.ee라는 문자열이 있는데 aa / bb/ cc/ dd.ee 이렇게 나누고 싶을 수 있다. 즉 모든 구분자 .에 의해 split하는 것이 아니라, 나누는 최대 횟수를 제한하는 경우이다.
이런 경우는 2번처럼 구분자 parameter 뒤에 maxsplit parameter를 하나 더 넣어주면 된다.