
: 웹 애플리케이션의 전체적인 구조를 담당하는 최상위 수준의 구성 요소
django-admin startproject config . : 장고 프로젝트 생성python manage.py runserver : 장고 프로젝트 구동cd \mkdir django_workspacecd django_workspaceC:\virtual\mysite\Scripts\activatemkdir projcd projdjango-admin startproject config .python manage.py runservermkdir django_workspacecd django_workspacesource 가상환경 경로/bin/activatemkdir projcd projdjango-admin startproject config .python manage.py runserver

http://127.0.0.1:8000/으로 시작되었다는 것과 서버를 중지시키기 위해 CONTROL-C를 입력하라는 내용: 프로젝트에 기능을 추가하기 위한 요소
django-admin startapp 앱이름 : 앱 생성django-admin startapp app1: URL과 뷰를 연결하는 역할
# proj/config/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# path('앱명/', include('앱명.urls'),
path('app1/', include('app1.urls')),
# 다른 앱의 URLconf도 추가할 수 있음
]
# proj/app1/urls.py
from django.urls import path
from . import views
# app_name = '앱명'
app_name = 'app1' # 앱 이름 등록
urlpatterns = [
# path("'앱명/'다음에 오는 경로", views.함수명, name='url별칭'),
path("", views.index, name='index'), # URL이 app1/
############### GET방식 공부 ###############
path("add", views.add), # url이 app1/add 인 경우인 경우
path("sub/<int:x>/<int:y>", views.sub), # url이 app1/sub/x/y 인 경우
############### 템플릿 파일 관련 공부 ###############
path('list', views.list, name = 'list'), # url별칭을 list로 지정
path('write', views.write),
path('save', views.save),
# 다른 URL 패턴과 뷰를 추가할 수 있음
]
" " 인 이유 : config/urls.py 파일에서 이미 app1/로 시작하는 URL이 app1/urls.py 파일과 매핑되었기 때문"app1/" 와 app1/urls.py 파일에서 매핑된 ""이 더해져 "app1/" 완성url 매핑을 분리하는 이유
: 앱에 관한 URL 매핑을 추가할 때마다 config/urls.py 파일(프로젝트 성격의 파일)을 수정해야하는 것을 예방
: 웹 요청을 처리하고 응답을 생성하는 역할
# proj/app1/views.py
from django.shortcuts import render # html과 연동할 때 사용
from django.shortcuts import redirect # 특정 페이지로 이동할 때 사용
from django.http import HttpResponse # 요청에 대한 응답할 때 사용
# URL이 'app1/' 인 경우
def index(request):
return HttpResponse("Hello Django") # 문자열을 브라우저에 출력
############### GET방식 공부 ###############
# URL이 'app1?x=1&y=2' 인 경우 (Get방식, 쿼리스트링)
def add(request):
x = int(request.GET.get('x'))
y = int(request.GET.get('y'))
response = HttpResponse(f"{x} + {y} = {x+y}")
return response
# URL이 'app1/sub/3/4' 인 경우 (Get방식, 경로변수)
def sub(request, x, y):
result = f"{x} - {y} = {x-y}"
response = HttpResponse(result)
return response
############### 템플릿 파일 관련 공부 ###############
personList = [
{'id':0, 'name':'김민지', 'phone':'010-2900-4039'},
{'id':1, 'name':'김은지', 'phone':'010-4055-4039'},
]
# URL이 'app1/list'인 경우 (render함수, 템플릿 파일 연동)
def list(request):
data = {'dataList':personList}
return render(request, 'app1/person_list.html', data) # 탬플릿(html)파일과 연동
# URL이 'app1/write'인 경우 (render함수, 템플릿 파일 연동)
def write(request):
# 보낼 데이터가 없다면 생략 가능
return render(request, 'app1/person_write.html')
# URL이 'app1/save'인 경우 (redirect함수, 특정 페이지로 이동)
def save(request):
name = request.POST.get('name')
phone = request.POST.get('phone')
personList.append({'name':name, 'phone':phone})
return redirect('app1:list') # 'app1/list'URL로 이동
request.GET.get('파라미터이름') : GET 파라미터의 값을 가져올 수 있음 (쿼리스트링의 경우에 해당)render(request, '템플릿 파일명', context={데이터이름:값}) : 파이썬 데이터를 템플릿에 적용하여 html로 반환하는 함수 {’html에서 사용할 데이터명’ : 실제 데이터}redirect(’앱명:url별칭’)app_name = '앱명' 을 통해 등록해 줘야 하고, url별칭은 path(’’, views.함수명, name=’url별칭’) 의 name 으로 지정해줘야 함: 템플릿은 사용자에게 보여지는 웹 페이지의 모습을 정의하는 데 사용
: 프로젝트 디렉토리(proj) 안에 템플릿 파일을 저장할 템플릿 디렉토리(templates) 생성
→ 템플릿 디렉토리 안에 앱이름과 같은 디렉토리 생성 후, 그 안에 템플릿 파일을 생성
# config/settings.py
(생략)
import os
(생략)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
(생략)
os.path.join(BASE_DIR, 'templates')는 templates 디렉터리의 절대 경로를 반환BASE_DIR은 settings.py 파일에서 이미 정의된 프로젝트의 기본 경로{{ 변수 }} : 변수 출력
{{ 객체.속성 }} : 객체의 속성 값 출력
{% 템플릿 태그 %} : 템플릿 태그 작성
{% if 조건1 %}
실행할 코드
{% elif 조건2 %}
다른 조건일 때 실행할 코드
{% else %}
모든 조건이 거짓일 때 실행할 코드
{% endif %}{% for 변수 in 반복_대상 %}
반복할 코드
{% empty %}
반복 대상이 비어있을 때 실행할 코드
{% endfor %}{% 변수명 = 값 %}{% extends "부모_템플릿" %}{% block 블록_이름 %}
블록 내용
{% endblock %}블록 정의 예시
부모 템플릿<!DOCTYPE html> <html> <head> <title>{% block title %}기본 제목{% endblock %}</title> </head> <body> <header> {% block header %} <h1>기본 헤더</h1> {% endblock %} </header> <main> {% block content %} <p>기본 내용</p> {% endblock %} </main> <footer> {% block footer %} <p>기본 푸터</p> {% endblock %} </footer> </body> </html>자식 템플릿
{% extends "parent.html" %} {% block title %}새로운 제목{% endblock %} {% block header %} <h1>새로운 헤더</h1> {% endblock %} {% block content %} <p>새로운 내용</p> <p>추가적인 내용</p> {% endblock %}
{{ 변수|필터 }} : 변수의 값을 특정한 방식으로 변환하여 출력할 때 사용하는 필터
{{ name|upper }}는 name 변수의 값을 대문자로 변환하여 출력{# 주석 내용 #} : 주석
<!-- templates/app1/person_list.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Person list</h1>
<ul>
{% for person in dataList %}
<li>{{person.name}} {{person.phone}}</li>
{% endfor %}
</ul>
</body>
</html>
<!-- templates/app1/person_write.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form method="post" action="/app1/save">
<!-- post방식으로 서버에 전송하고 전송된 정보를 받아서 /app1/save 처리 -->
{% csrf_token %} <!-- post방식으로 데이터 보낼 때 반드시 필요 -->
이름 : <input type="text" name="name"> <br>
전화번호 : <input type="text" name="phone"> <br>
<button type="submit">등록</button>
</form>
</body>
</html>
: 데이터베이스의 테이블과 대응되는 개념으로, 데이터의 구조를 정의하고 데이터베이스와의 상호작용을 처리
# config/settings.py
(생략)
INSTALLED_APPS = [
"앱명.apps.앱명Config", # 앱을 등록해야 Model객체 생성 가능
(생략)
][앱명/models.py] 파일에 모델 클래스 정의
# 앱명/models.py
from django.db import models
class 모델_클래스명(models.Model):
속성1 = models.CharField('객체명', max_length=n) # 길이가 제한된 텍스트 속성
속성2 = models.TextField('객체명') # 길이 제한 없는 텍스트 속성
속성3 = models.DateTimeField() # 날짜,시간 관련 속성
속성4 = models.IntegerField() # 정수 속성
python manage.py makemigrations : 필요한 쿼리를 생성
python manage.py sqlmigrate 앱명 일련번호 : 실행되는 쿼리를 확인 (수행x)
python manage.py migrate : 테이블 생성
python manage.py migrate --fake-initialDjango Shell : Django 환경에서 Python 인터프리터를 실행하는 대화형 콘솔
python manage.py shell : 장고 셀 실행from 앱명.models import 모델명 : 정의한 모델 클래스 불러오기모델명.objects.all() : 모델의 모든 데이터를 조회모델명.objects.filter(조건) : 조건을 만족하는 데이터 조회 모델명.objects.get(조건) : 조건을 만족하는 단일 데이터 조회 변수명 = 모델명(속성1=값1, 속성2=값2, 속성3=값3, 속성4=값4) : 모델 클래스의 인스턴스를 생성변수명.save() : 저장 (데이터 1건 생성)변수명.id : 인스턴스의 id값 확인 (데이터가 1건 생성되면 반드시 id값 생성됨)조회된변수명.속성 = 값 : 데이터 수정조회된변수명.save() : 저장조회된변수명.delete() : 데이터 삭제 (save() 필요 없음)quit() ( 또는 Ctrl+Z ) : 장고 셀 종료조회 결과는 QuerySet 객체로 반환
⇒ 모델 클래스 안에 __str__메서드를 추가하면 조회 결과는 쿼리셋 대신 해당 모델의 객체를 나타내는 문자열로 표현
표현만 문자열로 나타날 뿐, 조회 결과는 그대로 쿼리셋 형태로 반환def __str__(self): return self.속성
장고 셀 참고 사이트 : 예제로 배우는 파이썬 프로그래밍 - Django 모델 API
# config/settings.py
DATABASES = {
"default" : {"ENGINE" : 'django.db.backends.oracle',
"NAME" : 'XE', # 오라클은 특별히 바꾸지 않으면 이름이 XE로 되어있음
"USER" : '오라클 사용자계정', # 유저이름
"PASSWORD" : '비밀번호', # 비밀번호
"HOST" : '127.0.0.1', # 호스트 주소
"PORT" : '1521' # 포트번호
}
}-- Cmd에서 수행 (sqlplus에서는 conn으로 접속)
splplus sys/oracle as sysdba -- sysdba권한으로 접속
alter session set "_ORACLE_SCRIPT" = true; -- 세션 변경
create user 사용자이름 identified by 비밀번호; -- 사용자 생성
grant connect, resource to 사용자이름; -- 사용자에게 권한 부여
alter user 사용자이름 default tablespace users quota unlimited on users; -- 계정권한 문제 해결# 터미널에서 수행( Mac )에서 sysdba권한으로 접속하는 방법 (sqlplus실행하는 방법)
docker exec -it --user=oracle oracle sqlplus sys/oracle as sysdba-- SQL plus
conn 사용자이름/비밀번호;
select table_name from tabs; -- 테이블이름 조회
desc 생성한 테이블; -- 생성한 테이블 정보 확인insert into 테이블명(속성1, 속성2, ...) values(값1, 값2, ...);
commit; -- 커밋해야 저장됨(필수!!)Generic View 방식
ORM (Object-Relational Mapping) 방식
쿼리 직접 실행 방식
각 방식의 간단한 예시
# 앱명/urls.py
from django.urls import path
from . import views
## 1) Generic View 사용한 경우
from 앱명.views import 클래스명1, 클래스명2
urlpatterns = [
path("list", 클래스명1.as_view()), # /앱명/앱명_list.html 에 연결
path("detail/<int:pk>", 클래스명2.as_view()), # /앱명/앱명_detail.html
## 2),3) ORM방식 과 직접쿼리실행 방식
urlpatterns = [
path("list/", views.함수명),
]
# 앱명/views.py
from django.shortcuts import render
from 앱명.models import 모델명
## 1) Generic View 사용한 경우
from django.views.generic import ListView, DetailView
class 클래스명1(ListView): # 목록자료 : object_list로 전달
model = 모델명
class 클래스명2(DetailView): # 상세자료 : object로 전달
model = 모델명
## 2) ORM 방식
def 함수명(request):
dataList = 모델명.objects.all() # 모든 요소 가져오기
return render(request, "앱명/템플릿파일명.html", {'html에서이름':dataList})
## 3) 직접 쿼리 실행 방식
from django.db import connection # config/settings.py 에서 지정한 디비 연결자 가져옴
def dictfetchall(cursor):
columns = [col[0].lower() for col in cursor.description]
return [dict(zip(columns,row)) for row in cursor.fetchall()]
def 함수명(request):
cursor = connection.cursor() # cursor : db에 데이터 읽고 쓰기 담당
sql = "쿼리문장(ex. select * from 테이블명 order by id desc)"
cursor.execute(sql) # 쿼리 실행
dataList = dictfetchall(cursor)
return render(request, "앱명/템플릿파일명.html", {'html에서이름':dataList})
: 사용자로부터 입력을 받고 처리하는 데 사용
: 페이지 요청 시 전달되는 파라미터들을 쉽게 관리하기 위해 사용하는 클래스
# 앱명/forms.py
from django import forms
from 앱명.models import 모델_클래스명
class 폼_클래스명(forms.ModelForm):
class Meta:
model = 모델_클래스명
fields = ['속성1','속성2',...] # 폼에서 사용할 모델 클래스의 속성명
labels = {'속성1':'표시값1', '속성2':'표시값2',...} # 폼에서 각 속성을 표시할 문자열
# 앱명/views.py
from django.shortcuts import render
from 앱명.forms import 폼_클래스명
################## 방법1) 폼 입력과 입력된 데이터 저장 함수를 따로 ##################
def 작성함수명(request):
return render(request, "앱명/템플릿명.html", {'form':폼_클래스명()})
def 저장함수명(request):
form = 폼_클래스명(request.POST)
변수명 = form.save(commit=False) # 임시저장(실제 데이터가 db에 아직 저장X)
변수명.속성 = 값 # 폼으로 입력받지 않는 데이터는 따로 입력 (ex. 작성한 시간)
변수명.save() # 실제로 저장
return redirect("등록한 앱명 : url 별칭")
################## 방법2) 입력과 저장 함수를 한꺼번에 ##################
def 함수명(request):
# POST방식 (폼에 값을 입력한 후 저장버튼을 누르면)
if request.method == 'POST':
form = 폼명(request.POST) # 폼에 입력한 데이터 가져오기
if form.is_valid(): # form이 유효한지(form에 저장된 값이 올바르지 않으면 다시 질문 등록 화면을 렌더링)
변수명 = form.save(commit=False)
변수명.속성 = 값
변수명.save()
return redirect("등록한 앱명 : url 별칭")
# GET방식(인수없이 생성, 폼 페이지를 들어갈 때)
else: # 링크를 통한 페이지 요청은 무조건 GET방식 사용됨
form = 폼_클래스명()
return render(request, '앱명/템플릿명.html', {'form':form})
<!-- templates/앱명/템플릿명.html -->
<form method="post" action="저장 시 실행되는 페이지">
{% csrf_token %}
{{ form.as_p }} <!-- 함수에서 전달한 폼의 객체 -->
<button type="submit">저장</button>
</form>
request.POST : 화면에서 사용자가 입력한 내용들이 담겨있음{% csrf_token %} : CSRF(Cross-Site Request Forgery) 공격으로부터 보호하기 위해 사용{{ form.as_p }}: 웹 애플리케이션의 정적인 파일로, CSS, JavaScript, 이미지 파일 등이 포함
# config/settings.py
(생략)
STATIC_URL = 'static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
(생략){% load static %}
<link ... href="{% static '스타일파일.확장자' %}">
(생략){% load static %} : 템플릿 최상단에 삽입해야하는 코드<script src="{% static 'js/파일명.js' %}"></script><link rel='stylesheet' href="{% static 'css/파일명.css' %}"><img src="{static 'img/파일명.png' %}">