C:\Users\r2com> cd c:\python\projects\mysite # 프로젝트 홈 디렉터리로 이동
C:\python\projects\mysite> c:\python\mysite\Scripts\activate # 가상 환경 활성화
(mysite) C:\python\projects\mysite> code . # VSCode 실행
(mysite) C:\python\projects\mysite> python manage.py runserver # 장고 개발 서버 실행
form
HTML 작성 시 사용자의 입력을 서버로 전달
action
사용자의 입력을 어느 페이지, 어느 서버에 전달할 것인지 목적지를 지정
get
사용자가 입력한 정보를 URL에 전달
post
주소가 아닌 요청 본문인 HTTP에 데이터를 담아 전달
redirection
방향 전환, 방향 변경
리다이렉트(redirect, 재지시)를 통해 추가된 내용을 가져감
: https://django-doc-test-kor.readthedocs.io/en/old_master/topics/templates.html#template-inheritance
변수, 필터, 태그, 주석
변수
: {{ 변수 }}
필터
: 변수의 값을 특정 형식으로 변환할 때 사용
: 변수 다음에 | (파이프)를 넣어서 필터를 명시
: 필터는 : 문자를 통해 인자를 받을 수 있음
: {{ text | escape | linebreaks }}
: {{ text | truncatewords:30 }}
: {{ text | default:"default value" }}
: {{ text | length }}
: {{ text | upper }}
태그
: {% 태그 %}
: if 문 또는 for 문과 처럼 흐름을 제어하기 위해 사용
: {% extends %}와 같이 단독으로 사용하는 템플릿 태그도 있고, {% if %} {% endif %} 처럼 반듯이 닫아줘야 하는 템플릿 태그도 있음
주석
: 주석 처리 시 사용
: {# 한 줄 주석 #}
: {% comment %}
: 여러 줄 주석
: {% endcomment %}
def index(request):
question_list = Question.objects.order_by('-create_date')
context = { 'question_list' : question_list }
return render(request, 'pybo/question_list.html', context)
{% if question_list %}
<ul>
{% for question in question_list %} # 뷰의 context 변수에 정의한 키 이름
<li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>질문이 없습니다.</p>
{% endif %}
/pybo/숫자/ 형식의 URL 패턴이 정의되어 있지 않음
from django.urls import path
from . import views # 현재 패키지에서 views 모듈을 가져옴
urlpatterns = [
path('', views.index),
path('<int:question_id>/', views.detail),
]
from django.shortcuts import render
from .models import Question
def index(request):
question_list = Question.objects.order_by('-create_date')
context = { 'question_list': question_list }
return render(request, 'pybo/question_list.html', context)
def detail(request, question_id):
question = Question.objects.get(id=question_id)
context = { 'question': question }
return render(request, 'pybo/question_detail.html', context)
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
오류 메시지에 시스템(프로그램) 내부 구조 및 로직이 포함되어 출력
→ 오류 메시지를 통해 정보를 수집해 추가 공격을 계획
모델의 기본키를 이용해서 모델 객체 한 것을 반환
from django.shortcuts import render, get_object_or_404
from .models import Question
def index(request):
question_list = Question.objects.order_by('-create_date')
context = { 'question_list': question_list }
return render(request, 'pybo/question_list.html', context)
def detail(request, question_id):
# question = Question.objects.get(id=question_id)
question = get_object_or_404(Question, pk=question_id)
context = { 'question': question }
return render(request, 'pybo/question_detail.html', context)
: 내부 정보가 포함되지 않는 단순한 메시지가 출력
<li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>
~~~~~~~~~~~~~~~~~~~~~~~~
질문 목록에서 제목(링크)을 클릭했을 때 이동하는 주소
→ 주소가 하드 코딩되어 있음
→ 변경을 일관되고 쉽게 반영하기가 어려움
from django.urls import path
from . import views
urlpatterns = [
# /pybo/ 형식의 주소에 index라는 이름 부여
path('', views.index, name='index'),
# /pybo/숫자/ 형식의 주소에 detail라는 이름 부여
path('<int:question_id>/', views.detail, name="detail"),
]
{% if question_list %}
<ul>
{% for question in question_list %}
{# <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li> #}
<li><a href="{% url 'detail' question.id %}">{{ question.subject }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>질문이 없습니다.</p>
{% endif %}
서로 다른 앱에서 같은 URL 별칭을 사용하면 중복 문제 발생
→ 네임스페이스(namespace: 각각의 앱이 관리하는 독립된 이름 공간)를 적용해서 해결 가능
from django.urls import path
from . import views
app_name = 'pybo'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name="detail"),
]
{% if question_list %}
<ul>
{% for question in question_list %}
{# <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li> #}
<li><a href="{% url 'pybo:detail' question.id %}">{{ question.subject }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>질문이 없습니다.</p>
{% endif %}
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
{% csrf_token %}
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변 등록"/>
</form>
URL 맵핑이 정의되지 않아 오류가 발생
from django.urls import path
from . import views
app_name = 'pybo'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name="detail"),
path('answer/create/<int:question_id>', views.answer_create, name='answer_create'),
]
from django.shortcuts import render, get_object_or_404, redirect
from .models import Question
from django.utils import timezone
def index(request):
question_list = Question.objects.order_by('-create_date')
context = { 'question_list': question_list }
return render(request, 'pybo/question_list.html', context)
def detail(request, question_id):
# question = Question.objects.get(id=question_id)
question = get_object_or_404(Question, pk=question_id)
context = { 'question': question }
return render(request, 'pybo/question_detail.html', context)
def answer_create(request, question_id):
# 답변을 추가할 질문을 조회
question = get_object_or_404(Question, pk=question_id)
question.answer_set.create(content=request.POST.get('content'), create_date=timezone.now())
# 답변 추가 후 상세 페이지로 리다이렉트
return redirect('pybo:detail', question_id=question.id)
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
{# 답변 내용을 출력 #}
<h5>{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div>
<ul>
{% for answer in question.answer_set.all %}
<li>{{ answer.content }}</li>
{% endfor %}
</ul>
</div>
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
{% csrf_token %}
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변 등록"/>
</form>
# 선택자 { 적용할 스타일; 적용할 스타일; ... }
→ https://poiemaweb.com/css3-selector 참고
textarea { # 요소(태그) 선택자 → textarea 태그에 적용할 스타일 지정
width: 100%;
}
input[type=submit] { # 속성 선택자 → input 태그 중
margin-top: 10px; type 속성의 값이 submit인 태그에 적용할 스타일 지정
}
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'style.css' %}">
<h1>{{ question.subject }}</h1>
<div>
{{ question.content }}
</div>
{# 답변 내용을 출력 #}
<h5>{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div>
<ul>
{% for answer in question.answer_set.all %}
<li>{{ answer.content }}</li>
{% endfor %}
</ul>
</div>
<form action="{% url 'pybo:answer_create' question.id %}" method="post">
{% csrf_token %}
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변 등록"/>
</form>
질문 내용을 입력하는 창(textarea 태그)의 넓이가 화면의 가로 100%를 차지하고 답변 등록 버튼(submit 버튼)의 윗쪽 바깥 여백이 10px 추가됐는지 확인
https://getbootstrap.com/docs/4.5/getting-started/download/
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'bootstrap.min.css' %}" >
{% if question_list %}
<ul>
{% for question in question_list %}
{# <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li> #}
<li><a href="{% url 'pybo:detail' question.id %}">{{ question.subject }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>질문이 없습니다.</p>
{% endif %}
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'bootstrap.min.css' %}" >
<div class="container my-3">
<table class="table">
<thead>
<tr class="thead-dark">
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
{% if question_list %}
{% for question in question_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>
<a href="{% url 'pybo:detail' question.id %}">
{{ question.subject }}
</a>
</td>
<td>{{ question.create_date }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="3">질문이 없습니다.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
협업, 분업, 의사소통을 위한 방법론
: 협업의 표면적인 이유
→ 상호작용, 분업, 빠른 처리가 가능하기 때문
: 협업의 본질적인 이유
→ "Schedule" # 빨라진 서비스 출시 일정
→ 서비스 하나 출시까지 평균적으로 약 4개월 정도 소요
→ 빠른 출시를 위한 업부 방법으로 협업이 있었던 것
→ 협업 시작 시 가장 먼저 하는 단계가 '요구사항 분석' 단계
폭포수 개발 방법론(waterfall) 방식
: 이전 단계가 끝날 때까지 다음 단계를 실행하지 않고 대기
절차
요구사항 분석 → 프로그램 설계 → 구현/코딩 → 테스팅 → 유지·보수
장점
Simple
: 단순한 선형 모델
Systematic
: 단계 별 정형화 된 접근
Clarity
: 명확한 진행 상황 파악
요즘은 에자일을 많이 쓴다고는 하지만 막상 파헤쳐보면 폭포수 방식을 많이 사용
Parallel
: 각 단계 병행이 불가능
Issue Check
: 중요 경함에 대한 대응이 어려움
Flexible
: 떨어지는 유연성
속도를 내기 위해선 다른 대안이 필요
→ Agile(날렵한, 민첩한) 방법론
→ 기민한(민첩한) Software Development
→ 이에 기인한 것이 애자일 방법론(Agile Software Development)
애자일 선언문
공정과 도구보다 "개인과 상호작용"
포괄적인 문서보다 "작동하는 소프트웨어"
계약 협상보다 "고객과의 협력"
계획을 따르기 보다 "변화에 대응하기"
→ 즉시 사용자의 피드백을 받을 수 있는 상황이 조성되어 보다 빠른 개발 가능
: XP, DevOps, DaD, Lean Startup, Scrum, Kaizen, Product Development 등
절차
Product Backlog → Sprint Planning → Sprint Backlog → Daily Scrum → Increment → Sprint Review → Sprint Retrospective
Product Backlog
: 프로젝트 이해도가 제일 높은 사람이 많이 작성 (>> 프로젝트 매니저)
: 시간이 가장 오래 걸리는 작업
: 추상적으로 크게 작성하기 보다는 자잘하게 작성하는 것이 좋음
: 더 이상 작성할 게 없을 때까지 작성
Sprint Planning
: 스프린트 기간은 보통 2주(3주는 너무 길고 보통은 1~2주)
Sprint Backlog
: 스프린트 기간에 수행되어야 하는 업무의 목록
: Product Backlog에서 해야 할 일을 선택해서 수행
Scrum Team
: 개발팀과 검증(테스트)팀, 매니징팀으로 구성
: 스크럼 팀을 구성할 때 제일 중요한 룰(Daily Scrum)
: 어제 한 일과 오늘 할 일을 매일 15분 정도로 짧게 팀에게 공유하고 회의하여 진척 사항을 검토
Increment
: 스프린트 프로덕트에서 새로 업데이트 되고 새로운 요소들이 증가된 산출물
Sprint Review
: 스프린트 종료 후, 구현된 산출물을 Review
: 잘 완수하지 못했거나 좀 미숙한 부분들은 Proudct Backlog에 쌓아놓음
Sprint Retrospective
: 다 같이 모여서 개선할 부분, 리스크가 있는 부분 등에 대해 복귀
: 개선점이나 미숙한 부분들을 반영해 Sprint Planning에 대해 쌓아두어 문제 개선
- 스크럼에서 제일 중요한 건 회고(Retrospective)
→ 회고를 하지 않고 계속 넘어간다면 어느 부분이 부족하고 어느 부분이 개선이 필요한 지에 대해 알기 어려워 팀의 발전이 어려움
: Development + Operate
: 개발과 운영을 하나로 합쳐놓은 합성어
DevOps가 필요한 이유
: 과거, 개발자와 운영자의 관점은 전혀 달랐음
: 이러한 관점의 차이에 대한 간극을 줄여줄 만한 것이 필요
→ DevOps
DevOps Tools
: 산업에서 사용되는 툴들
Plan
: 일의 진행 상태를 확인
: ex. draw.io, Google Drive, Trello
Build
: 컨테이너 같은 내용물을 저장하고 관리
: ex. git, kubernetes, docker, GitHub
Continuous Intergration
: 지속적인 통합
: ex. Jenkins, circleci, Github Actions, Travis CI
Deploy
: 배포로 인한 장애 요인 제거
: ex. argo(아르고), Google Cloud Platform, Microsoft Azure, amazon web service(AWS)
Operate
: 운영 관점
: ex. slack, New Relic, DATADOG, SENTR
: 업무의 효율성을 증진시키기 위해 현업에서 많이 사용하는 방식
미래형 회고
: 미래도 같이 예측
→ 초기 팀의 스타트, 처음 스프린트 시 좋음
현재형 회고
: 현재 수행한 내용만 집중
→ 스프린트를 많이 돌린 상태라면 현재형이 좋음
- Goal
: 목표- Idea
: 목표에 도달하기 위한 기획- Step
: 절차- Task
: 스텝을 수행하기 위한 업무
- 현재는 Now,
- 우리가 그 다음 해야하는 것을 Next,
- 그 다음에 해볼만한 것은 Later에 기입
- 프로젝트를 진행하며 좋았던 점 등은 열기구 위에 작성
- 프로젝트를 진행하면서 아쉬운 점, 프로젝트 지연 요소 등은 열기구 하단에 작성
- 프로젝트의 긍정적 요소
→ sunny Days(왼쪽)- 프로젝트의 리스크, 부정적 요소
→ Storm(오른쪽)
- 칭찬할만한 것 : Liked
- 프로젝트를 하며 배웠던 점 : Learned
- 부족했거나 아쉬웠던 부분 : Lacked
- 새로운 아이디어, 재활용 했으면 하는 아이디어, 버리면 했으면 하는 아이디어 기입
- 차의 엔진 쪽에 긍정적 영향 기입
- 차의 낙하산 쪽에 부정적 영향 기입
- 칭찬할만한 것 : Liked
- 프로젝트를 하며 배웠던 점 : Learned
- 부족했거나 아쉬웠던 부분 : Lacked
- 프로젝트에 바라는 점 : Longed for