5. 테이블 생성하기
(1) 테이블의 개념, 생성
- 테이블의 생성
python manage.py migrate
로 기본적인 테이블, 앱들이 설치됨
- 이렇게 설치된 앱들은 setting.py 파일에서 확인
- setting.py 내 DATABASES 설정
- application.yml의 spring.datasource 느낌인듯
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
(2) 데이터 모델
- 모델의 개념
- 어떤 프로그램을 만들 때 데이터가 저장되고 관리되는 것이 필요한데 이런 것을 처리하기 위한 표본(모델)이 필요 -> 데이터 모델, 데이터베이스 모델
- 어떤 필드(컬럼)들이 필요하고 필드 타입은 어떻게 할 것인지 등등...
- 이를 통해 만들어진 데이터 모델 -> 테이블
- 앱 모델 관련 설정 - models.py에서
from django.db import models
class Memo(models.Model):
description = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
- 모델 설정을 해당 앱 어드민에 연동 (admin.py)
from django.contrib import admin
from onememos.models import Memo
admin.site.register(Memo)
INSTALLED_APPS = [
'onememos.apps.OnememosConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
- migrations 파일 생성
py manage.py makemigrations
- makemigrations 이후 앱 디렉토리 내 migrations에 새 파일 추가됨
- models.py 설정을 바꾸고 migrations 할 때 마다 새 설정 파일이 계속 생성됨
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Memo',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('description', models.CharField(max_length=200)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
),
]
- migrate 하여 테이블 생성
py manage.py migrate
- 어드민 사이트 접속 시 생성된 테이블 확인 가능


- 테이블 생성 흐름 정리
- 최상위 환경 설정 폴더 -> settings.py 작성
py manage.py makemigrations
: 앱 내 migrations 생성
- migrate
6. URL Patterns 설정
- URL Patterns 설정 : 최상단 디렉터리의
urls.py
- 슬래시(/)는 기본적으로 장고가 알아서 처리하기는 하지만 특별한 경우가 아닐 경우 꼭 붙여준다
- 마지막 단은 콤마를 생략해도 되고 붙여도 됨
- 서버 구동 시 변화가 감지되면 자동으로 리로딩
- 잘못된 코드로 오류가 날 경우 서버 구동이 자동적으로 감지하고 에러를 내며 수정되면 다시 재구동
- 초기화의 경우 view.index 또는 views.main 등으로 해도 됨
- 앱 내 urls.py, views.py 수정
from django.urls import path
from . import views
urlpatterns = [
path('', views.main),
path('createMemo/', views.createMemo),
path('detail', views.detail, name='detail')
]
from django.shortcuts import render
from django.http import HttpResponse
def main(request):
return HttpResponse("안녕 my 월드야")
def detail(request):
return HttpResponse("안녕 my detail 월드야")
def createMemo(request):
memoContent = request.GET['memoContent']
return HttpResponse("create memo = " + memoContent)
7. 템플릿 생성하기
(1) render 함수 vs template 파일
- render 함수와 template 파일의 관계
- 웹사이트 개발 시 파이썬 코드와 데이터를 템플릿 파일로 만들어주는 함수
- HTML로 변환해서 적용해주는 함수라고 보면 됨
- 결국 views는 템플릿을 리턴하게 됨 (템플릿 파일이 HTML 파일은 아님. 프레임 워크 전용 파일의 개념)
- 자바 스프링 진영의 템플릿은 JSP, Thymeleaf
- 템플릿 파일에는 템플릿 관련 문법 또는 태그를 적용해야 하므로 순수 HTML 파일은 아님
(2) template 폴더 생성
- 템플릿 폴더 생성 방법 2가지
- 프로젝트 루트 폴더에 templates 폴더 만들어 사용 -> settings.py -> 템플릿 경로 추가
- 생성한 앱 폴더 하위에 templates 폴더 만들어 사용 -> 앱별로 템플릿 사용 가능
- 앱 폴더 하위의 templates 폴더 생성 시 별다른 설정 없이 템플릿 디렉토리를 인식하게 됨. 대신 서버 재시작 필요
- render 함수 사용
def main(request):
return render(request, 'main.html')
(3) 뷰 페이지 템플릿 생성
- 관리자 모드에서 DB 조작
- admin 페이지에서 직접 데이터를 생성할 수 있음

- CMD 명령 프롬프트에서의 DB 조작 (dbshell)
- sqlite tool 설치 필요 (sqlite-tools-win32-x86-3410000.zip)
- sqlite3.exe 실행파일을 생성한 프로젝트 루트 폴더에 넣어놓고 sqlite DB에 접속
py manage.py dbshell
- 관련 이슈 : 지난번 Git bash 관련 동일한 이슈가 발생하여 winpty 옵션 적용

- 툴을 통해 DB의 테이블 정보 확인 및 테이블 규칙성 확인 -> 실제 테이블명 확인
- sqlite에서
.table
입력 시 전체 테이블 조회 가능

앱명_테이블명
으로 테이블이 생성됨
- SQL 쿼리로 DB 조회 가능

- Form 작성 및 DB 입출력
- views.py 에서 HTTP 메서드로 전달 받은 객체를 다룰 수 있음
def createMemo(request):
memoContent = request.POST['memoContent']
return HttpResponse("create memo = " + memoContent)
...
<form action="http://localhost:8000/onememos/createMemo" method="POST" id="memoWriteForm">
<label for="memo">메모 입력</label>
<input type="text" id="memo" name="memoContent" size="100" placeholder="내용을 입력하세요" autocomplete="false">
</form>
- CSRF 토큰 처리
- CSRF(Cross Site Request Forgery) : 특정 사용자가 마치 접속하여 요청값을 보낸 것처럼 글 작성, 즉 위조된 요청 액션을 보내 악의적으로 요청을 이용하는 행위
- 예시 : iframe 등을 몰래 삽입하여 로그인 사용자가 본인도 모르게 글 작성을 요청 넣는 것처럼 하는 행위
- 장고에서는 가장 편리하게 토큰을 이용하여 대비할 수 있음
- CSRF 토큰은 발급 시 매번 값이 변경되며 뷰가 호출되기 전 해당 토큰을 통해 유효성을 검증
- POST 방식을 사용하는 템플릿 form 태그 쪽에
{% csrf_token %}
태그 사용
<body>
<h1>메모 작성 폼</h1>
<form action="http://localhost:8000/onememos/createMemo/" method="POST" id="memoWriteForm">
{% csrf_token %}
<label for="memo">메모 입력</label>
<input type="text" id="memo" name="memoContent" size="100" placeholder="내용을 입력하세요" autocomplete="false">
</form>
<div>
<button type="submit" form="memoWriteForm">메모 등록</button>
</div>
</body>
8. 게시판 기능 구현
(1) 데이터베이스 Article 입력
- views.py에서 바로 저장할 article 객체를 만들어서 저장
def createMemo(request):
memoContent = request.POST['memoContent']
article = Memo(description = memoContent)
article.save()
return HttpResponse("create memo = " + memoContent)
- 만약 저장이 안된다면
- models.py에서 필요한 모든 것을 import 했는지 체크
- NOT NULL 필드 입력했는지 체크
- 오타 체크
(2) 리스트 뷰 만들기
- redirect와 reverse
- django.urls 에서 reverse를 import
- redirect() : 특정 URL로 리다이렉션
- reverse() : URL을 역으로 계산해서 path가 변경되어도 URL을 외울 필요가 없음
- urls.py에서 만든 URL Patterns들의 name을 사용해서 해당 name의 url을 반환
- name 정보가 틀릴 경우 페이지 에러 발생
- return 타입을 HttpResponseRediect로
def createMemo(request):
memoContent = request.POST['memoContent']
article = Memo(description = memoContent)
article.save()
return HttpResponseRedirect(reverse('main'))
- objects.all()
- DB에서 전체 데이터를 조회하는 메서드 (findAll())
- DB로부터 전체 데이터를 가져온 후 템플릿 파일로 전달(변수)할 때 all() 메서드 사용
def main(request): # 기본적인 요청 흐름 url 요청 -> urls.py -> main()
lists = Memo.objects.all() # Memo 객체 전부 조회
data = {'lists' : lists} # 반드시 딕셔너리 형태로 저장하여 템플릿 파일로 전달해야 함 (map.addAttribute() 느낌)
return render(request, 'main.html', data) # 템플릿 파일명 (앱 폴더 하위 templates에 있다면 경로 지정 하지 않아도 됨)
- 템플릿 태그 및 출력
{% %}
: 템플릿 태그, 안쪽에 파이썬 문법을 사용
- 반복 처리나 조건 처리 등을 위해 사용
- 예시 : for article in lists
- 직접적인 딕셔너리 이름(data)을 사용하지 않고 key를 사용 (lists)
- 즉, key(=lists) 이름을 통해 value 값에 접근
{{ }}
: 템플릿 태그, 데이터 값을 화면에 출력할 때 사용
- 반복 처리 시 하나하나의 item(=article, object) 항목에 들어 있는 속성값을 꺼내서 화면에 출력시키고자 할 때 사용
<div style="padding-left: 50px;">
<ul style="line-height: 2em;">
{% for article in lists %}
<li>
<b>{{article.id}}</b>
{{article.description}}
<small style="color:deeppink">
({{article.created_at | date:'y-m-d'}})
</small>
</li>
{% endfor %}
</ul>
</div>
- 결과
