== 요청 ==>
클라이언트 서버
(웹브라우저) <== 응답 == (Django)
웹 서비스를 만드는 데 필요한 도구들
프로그래밍에서 특정 운영 체제를 위한 응용 프로그램 표준 구조를 구현하는 클래스와 라이브러리 모임
재사용 할 수 있느 수많은 코드를 프레임워크로 통합함으로써, 개발자가 새로운 애플리케이션을 위한 표준 코드를 다시 작성하지 않아도 같이 사용할 수 있도록 도음
Application framework 라고도 함
웹 페이지를 개발하는 과정에서 어려움을 줄이는 것이 목적
데이터베이스 연동, 템플릿 형태의 표준, 세션 관리 , 코드 재사용등의 기능을 포함
동적 웹 페이지나, 웹 어플리케이션 , 웹 서비스 개발 보조용
manage.py 가 있는 위치 -> project root
def index(request):
# request 반드시 써줘야함
return render(request,'index.html')
# request 반드시 써줘야함
from articles import views # Application 에 views를 import 해줘야함
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index), # 파일의 주소, 끝난 뒤 , 꼭 찍어둘것
]
순서는 항상 URL -> VIEW => TEMPLATE
from django.http import HttpResponse
def welcome(request):
return HttpResponse('<h1> Hola ! <h1>')
>> Hola! 출력
Django Template에서 사용하는 built-in template system
조건, 반복, 변수 , 치환 , 필터 등의 기능을 제공
단순이 Python 이 Html 에 포함 된 것이 아니며,
프로그래밍 로직이 아닌 프레젠테이션을 표현하기 위한것
if , for 문 등이 사용 되긴 하지만 Python 코드로 실행되는 것이 아님
rander() 를 사용하여, views.py 에서 정의한 변수를 template파일로 넘겨 사용하는 것
변수 명은 영어, 밑줄을 포함 가능, 단 밑줄 시작은 안됨
dot(.) 을 사용하여 변수 속성에 접근 가능
render() 의 세번째 인자로 {'key' : value} 와 같이 딕셔너리 형태로 넘겨주며,
여기서 정의한 key에 해당하는 문자열이 template에서 사용 가능한 변수명이 됨
def greeting(request):
return render(request,'greeting.html',{'name' : 'Alice',})
# render 함수의 세번째 인자 값을 딕셔너리 형태로 저장 해야한다.
/* HTML 에서 DTL 변수를 사용하기 위해선 {{ 변수명 }} 와 같이 사용 */
<p>안녕하세요 저는 {{name}}입니다.</p>
def greeting(request):
# 관용적으론 변수는 context 라는 이름으로 사용
context=dict(name='Alice')
return render(request,'greeting.html',context)
def greeting(request):
foods = ['apple','banana','cocount',]
info={
'name':'Alice',
}
context={
'foods' : foods,
'info' : info,
}
return render(request,'greeting.html',context) # context 접근시 딕서녀리의 왼쪽 키 값을 통해 접근한다.
<p>안녕하세요 저는 {{info.name}}입니다.</p>
>>안녕하세요 저는 Alice입니다. # dot(.) 을 통해 접근
<p>제가 가장 좋아하는 음식은 {{ foods }} 입니다.</p>
>>제가 가장 좋아하는 음식은 ['apple', 'banana', 'cocount'] 입니다.
<p>저는 사실 {{ foods.0 }} 입니다.</p> # dot(.) 을 찍으면 인덱스 접근이 가능하다.
>>저는 사실 apple 입니다.
ex)
name 변수를 모두 소문자로 출력
<p>안녕하세요 저는 {{info.name|lower}}입니다.</p>
>> 안녕하세요 저는 alice입니다.
filter 는 chain 이 가능하다
def dinner(request):
foods = ['족발','햄버거','치킨','초밥']
pick = random.choice(foods)
context = {
'pick' : pick,
'foods' : foods,
}
return render(request,'dinner.html',context)
<p>오늘의 추천 음식은 {{pick}} 입니다!</p>
<p>{{pick}} 은 {{pick|length}} 글자 입니다</p>
<p>{{ foods|join:', '}}</p>
>> 족발,햄버거,치킨,초밥
<a href="/index/"> 뒤로 </a>
출력 텍스트를 만들거나 , 반복 또는 논리를 수행 하여 제어 흐름을 만드는등 변수보다 복잡한 일 들을 수행
일 부태그는 시작과 종료태그가 필요
<p> 메뉴판 </p>
<ul>
{% for food in foods %}
<li>{{food}}</li>
{% endfor %}
</ul>
메뉴판
족발
햄버거
치킨
초밥
약 24개
{# 이것은 한 줄 주석 입니다.#}
하나의 base.html 을 만들고 이를 상속받아서 사용할수 있는 자식 template를 사용
코드의 재사용성
모든 공통 요소를 포함하고, 하위 템플릿이 재정의 할 수 있는 블록을 정의하는
기본 "skeleton" 템플릿을 만들 수 있음
장고에게 추가 템플릿 경로 등록한다고 말해줘야한다. (우리만의 별도의 경로)
settings.py => TEMPLATES => DIR 에다 등록
# base.html 이 포함된 templates 폴더를 최상단에다가 생성 뒤 settings에 작성
'DIRS': [BASE_DIR / 'templates',],
{% extends ' 부모.html' %}
{% block content %} { % endblock % }
from django.shourtcuts import render
=> 화면을 렌더링 해서 사용한다.
#views.py
def index(request):
context = dict() # 딕셔너리 형태로 key 값이 템플릿의 변수명
return render(request,'A.html',context) # render 함수의 인자들
사용자에게 정보를 입력 받기 위해 사용
핵심 속성(attribute)
type 속성에 따라 동작 방식이 달라짐
핵심 속성(attribute)
name : 데이터의 이름을 지정
주요 용도는 GET/POST 방식으로 서버에 전달하는
파라미터 (name 은 key, value 는 value) 로 매핑 하는 것
GET 방식에서는 URL ?key=value&key=value 형식으로 데이터를 전달함
def throw(request):
return render(request,'throw.html')
def catch(request):
message = request.GET.get('message') # request 안에 있는 GET 방식에서 get('message') message로 된 이름의 것을 받아와
context = dict(
message = message,
)
return render(request,'catch.html',context)
# Throw
<form action="/catch/">
<label for="message">메시지</label>
<input type="text" id='message' name='message'>
<input type="submit">
</form>
# catch
{% extends 'base.html' %}
{% block content %}
<h1>Catch</h1>
<h2>{{message}}</h2>
<a href="/throw/"> throw 로 가자</a>
{% endblock content %}
URL 주소를 변수로 사용하는 것
URL 의 일부를 변수로 지정하여 view 함수의 인자로 넘길 수 있음
즉, 변수 값에 따라 하나의 path() 에 여러 페이지를 연결 시킬 수 있음
path ('accounts/user/<<int:user_pk>>/',...)
path ('hello/<<str:name>>',views.hello)
# urls.py
path('hello/<str:name>/',views.hello), # hello 다음 매칭 되는게 문자열일 때 , name이라는 변수 받아서 hello view 로 넘겨
path('intro/<str:name>/<int:age>/',views.intro),
# vies.py
def hello ( request, name):
context = dict(
name = name,
)
return render(request,'hello.html',context)
def intro (request,name,age):
context = dict(
name = name,
age = age,
)
return render(request,'intro.html',context)
{% extends 'base.html' %}
{% block content %}
<h1>Hello ! {{name}} </h1>
{% endblock content %}
{% extends 'base.html' %}
{% block content %}
<h1>안녕하세요 {{name}} 님 {{age}}살 입니다.</h1>
{% endblock content %}
app 의 view 함수가 많아지면서 사용하는 path() 또한 많아지고,
app 또한 더 많이 작성하기 때문에, url.py 에서 모두 관리하는 것은 유지보수에 좋지 않다.
각 app 에 urls.py를 작성하게 됨
## urls.py firstpjt
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('articles/', include('articles.urls')),
path('pages/',include('pages.urls')),
]
####################################################
## urls.py articles
from django.urls import path
from . import views
urlpatterns = [
path('index/', views.index),
path('greeting/',views.greeting),
path('dinner/', views.dinner),
path('hi/',views.hi),
path('throw/',views.throw),
path('catch/',views.catch),
path('hello/<str:name>/',views.hello), # hello 다음 매칭 되는게 문자열일 때 , name이라는 변수 받아서 hello view 로 넘겨
path('intro/<str:name>/<int:age>/',views.intro),
]
###################################################
## urls.py pages
from django.urls import path
from . import views
urlpatterns = [
path('index/', views.index),
]
## views.py pages
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request,'pages/index.html')
# render 안 경로도 app/A.html 형식으로 바꿔줘야 한다.
from django.urls import path
from . import views
urlpatterns = [
path('index/', views.index , name='index'),
path('greeting/',views.greeting , name = 'greeting'),
path('dinner/', views.dinner ,name = 'dinner'),
path('hi/',views.hi , name = 'hi'),
path('throw/',views.throw ,name = 'throw'),
path('catch/',views.catch ,name = 'catch'),
path('hello/<str:name>/',views.hello ,name = 'hello'), # hello 다음 매칭 되는게 문자열일 때 , name이라는 변수 받아서 hello view 로 넘겨
path('intro/<str:name>/<int:age>/',views.intro , name = 'intro'),
]
#####################################################
{% extends 'base.html' %}
{% block content %}
<h1>Throw</h1>
#{% url 'name' %}
<form action="{% url 'catch'%}">
<label for="message">메시지</label>
<input type="text" id='message' name='message'>
<input type="submit">
</form>
{% endblock content %}
from django.urls import path
from . import views
# app_name 을 작성
app_name = 'pages'
urlpatterns = [
path('index/', views.index,name='index'),
]
###
# app_name : name 형식으로 url 작성
<a href={% url 'pages:index' %}> 두번째 인덱스 </a>
이름이 중복된 경우
하나의 이름 공간에서는 하나의 이름이 단 하나의 객체만을 가리키게 된다
Django 에서는
#urls#
app_name ='pages' # app_name 설정
urlpatterns = [
path('index/',views.index),
]
#html#
<a href="{%url 'pages : index'%}"> 두번째 앱 메인 페이지로</a>
templates 안에 앱 이름과 똑같은 폴더를 만들어 준 뒤
html 파일을 그 안에 넣어준다
templates\articles
jango.contrib.staticfiles 가 Installed_APPS 에 있는지 확인
settings.py 에서 STATIC_URL 을 정의
static 템플릿 태그를 사용하여 지정된 상대경로에 대한 URL을 빌드
{% load static %}
<img src="{% static 'my_app/example.jpg' %}" alt ="my mage" >
앱의 static 디렉토리에 정적 파일을 저장
app / static / app 과 같이 경로를 설정
STATICFILES_DIRS
' app / static / '디렉토리 경로(기본 경로) 를 사용하는 것 외에
추가적인 정적 파일 경로 목록을 정의하는 리스트
추가 파일 디렉토리에 대한 전체 경로를 포함하는 문자열 목록으로 작성되어야 함
STATIC_URL
STATIC_ROOT 에 있는 정적 파일을 참조 할 때 사용할 URL
STATICFILES_DIRS 에 정의된 추가 경로들을 탐색함
비어있지 않은 값으로 설정한다면 반드시 / 로 끝나야함
실제 파일이나 디렉토리가 아니며 URL 로만 존재
STATIC_ROOT
배포를 위해 정적 파일을 수집하는 디렉토리의 전체 경로
모든 정적 파일을 한 곳에 모아 넣는 경로
개발 과정에서 settings.py 의 DEBUG 값이 True 로 설정시 작용 도지ㅣ 않음
실 서비스 환경(배포 환경) 에서 django의 모든 정적파잉릉ㄹ 다른 웹 서버가 직접 제공하기 위함
STATIC_ROOT = BASE_DIR / 'staticfiles'
python manage.py collectstatic
=> 배포 준비
load
static
STATIC_ROOT 에 저장된 정적 파일에 연결
{% load static %}
<img src="{% static 'my_app/example.jpg' %}" alt ="my mage" >
경로 -> pages 폴더 안 static 폴더 생성 후, 앱 이름
{% extends 'base.html' %} <!--항상 최상단에 위치 해야함-->
{% load static %} <!-- extends 아래 load-->
{% block content %}
<img src="{% static 'sample.jpg' %}" alt="sample image" style = 'width:300px'>
<h1> 두번째 앱은 INDEX 페이지 </h1>
{% endblock content %}
settings.py 안
STATICFILES_DIRS = [
BASE_DIR/'static',
]
작성 후, 최 상단에 static 폴더 생성 -> 폴더 안 css 파일 생성
base.html head 부분 block style 생성
style 적용 원하는 html 에 다음과 같이 작성
{% block style %}
<link rel="stylesheet" href="{% static 'style.css'%}">
{% endblock style %}
pip freeze > tab
=>requirements.txt 에 자동 저장
장고 INSTALLED_APPS
내가 설치한 앱
내가 설치한 패키기
장고가 추가한것
Object - Relational - Mapping : 객체 관계 매핑 ( 데이터베이스를 모델 객체로 접근을 하겠다.)
객체 지향 프로그래밍 언어를 사용하여 호환되지 않는 유형의 시스템 간의 ( Django - SQL )
데이터를 변환하는 프로그래밍 기술
OOP 프로그래밍에서 RDBMS을 연동할 때 호환되지 않는 데이터를 변환하는 프로그래밍 기법
Django 는 내장 Django ORM을 사용한다.
from django.db import models
# Create your models here.
class Article(models.Model):
# CharField() => 제목 ( max_length 를 지정 )
title = models.CharField(max_length=30)
# TextField() => 텍스트 내용 (제한 없음)
content = models.TextField()
# DataTimeField() => 현재시간
# auto_now_add => 최초의 데이터가 생성 될 때, 최초의 시간을 저장
created_at = models.DateTimeField(auto_now_add=True)
# auto_now => 데이터가 수정이 될 때마다 시간을 저장
updated_at = models.DateTimeField(auto_now = True)
def __str__(self):
return self.title
model 조작 (생성 , 수정 ,삭제) 시에
migration 생성 ( model 의 history (like git))
# 2
python manage.py makemigrations
migration을 반영 해줘야 한다. (적용)
# 3
python manage.py migrate
null => DB에 null 값을 저장
none => 아무 값도 저장 하지 않음
ORM이 변환한 언어를 볼 수 있음 python -> SQL
# python manage.py sqlmigrate <앱 이름> < migrations 번호>
python manage.py sqlmigrate articles 0001
어떤 migration이 있고, 어떤 것이 적용 되어 있는지 확인하는 명령어
python manage.py showmigrations
ORM을 연습 할 수 있는 곳
python manage.py shell
# 데이터 추가하는 case 1
# 인스턴스 생성 후 save
>>> from articles.models import Article
>>> Article.objects.all()
<QuerySet []>
>>> article = Article() => Article() 인스턴스 생성
>>> article.title = "첫번째 글"
>>> article.content = "푸틴이 정신을 차려야 할텐데..."
>>> Article.objects.all()
<QuerySet []>
>>> article.save()
>>> Article.objects.all()
<QuerySet [<Article: Article object (1)>]>
>>> article = Article.objects.all()[0]
>>> article
<Article: Article object (1)>
>>> article.title
'첫번째 글'
>>> article.content
'푸틴이 정신을 차려야 할텐데...'
# 데이터 추가 case 2
# 키워드 인자를 넘기는 방식
>>> article = Article(title = "두번째 글", content = "점심때는 좀 자야 돼 진짜 ")
>>> article.save()
>>> Article.objects.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>]>
>>> article = Article.objects.all()[1]
>>> article.title
'두번째 글'
>>> article.content
'점심때는 좀 자야돼 진짜 '
# 데이터 추가 case 3 => save가 필요 없음
# Article.objects.crate()
>>> Article.objects.create(title = "세번째 글" , content ="다이어트는 내일부터")
<Article: Article object (3)>
>>> Article.objects.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>
pip install django-extensions
-> settings.py에 등록하자
In [4]: article1=Article.objects.all()[0]
In [5]: print(article1)
첫번째 글
# 조건으로 id 값을 불러와줘야해
In [8]: article = Article.objects.get(id=1)
# article = Article.objects.get(pk=4) pk라고 써도 돼
In [9]: article.title
Out[9]: '첫번째 글'
# filter 조건과 일치하는 모든것들을 가져온다
In [22]: articles = Article.objects.filter(title='첫번째 글')
In [23]: articles
Out[23]: <QuerySet [<Article: 첫번째 글>, <Article: 첫번째 글>]>
-> https://docs.djangoproject.com/en/3.2/ref/models/querysets/#field-lookups
에서 찾자
In [28]: aricles = Article.objects.filter(title__contains='첫')
In [29]: aricles
Out[29]: <QuerySet [<Article: 첫번째 글>, <Article: 첫번째 글>]>
In [36]: article.title = "네번째 글"
In [37]: article.save()
In [38]: article
Out[38]: <Article: 네번째 글>
In [39]: Article.objects.all()
Out[39]: <QuerySet [<Article: 첫번째 글>, <Article: 두번째 글>, <Article: 세번째 글>, <Article: 네번째 글>]>
In [40]: article.delete()
Out[40]: (1, {'articles.Article': 1})
In [41]: Article.objects.all()
Out[41]: <QuerySet [<Article: 첫번째 글>, <Article: 두번째 글>, <Article: 세번째 글>]>
$ python manage.py createsuperuser
Username (leave blank to use 'my'): jongram
Email address: najo7609@gmail.com
Password:
Password (again):
from django.contrib import admin
from .models import Article
# Register your models here.
admin.site.register(Article)
from .models import Article
# Create your views here.
def index(request):
# 1. 모델을 이용해서 모든 데이터를 가져온다.
# 2. 가져온 데이터를 템플릿으로 넘기다.
# 3. 템플릿에서 데이터를 보여준다.
articles = Article.objects.all()
# 다음과 슬라이싱 하면 뒤에서 부터 출력 가능 하다.
#articles = Article.objects.all()[::-1]
# DB에서 가져올떄 부터 정렬을 시킬 수 있음
# articles = Article.objects.order_by('pk')
# 내림차순 정렬
# articles = Article.objects.order_by('-pk')
context = dict(
articles = articles,
)
return render(request,'articles/index.html',context)
{%comment%} index.html {%endcomment%}
{% extends 'base.html' %}
{% block content %}
{% for article in articles %}
<h3># {{article.id}}</h3>
<h5>제목 : {{article.title}}</h5>
<article>{{article.content}}</article>
<hr>
{% endfor %}
{% endblock content %}
def new(request):
return render(request,'articles/new.html')
def create(request):
# new에서 넘어온 데이터를 get 방식을 통해 받아온 뒤 저장
title = request.GET.get('title')
content = request.GET.get('content')
# 데이터베이스에 저장 해주는 함수
Article.objects.create(title=title, content=content)
return render(request,'articles/create.html')
{% extends 'base.html' %}
{% block content %}
<h1 class="text-center">new article</h1>
{%comment%} action으로 create.html에 데이터 전송(get방식){%endcomment%}
<form action={% url 'articles:create' %}>
<label for="title" class="my-3">Title : </label>
<input type="text" id="title" name="title">
<br>
<label for="content">Content : </label><br>
{%comment%} textarea 로 깔끔하게 작성 {%endcomment%}
<textarea name="content" id="content" cols="30" rows="5"></textarea><br>
<input type="submit">
</form>
<br>
<a href= {% url 'articles:index' %}>목록보기</a>
{% endblock content %}
{% extends 'base.html' %}
{% block content %}
<h1 class="text-center">작성완료</h1>
{% endblock content %}
{% extends 'base.html' %}
{% block content %}
<h1 class="text-center">new article</h1>
<form action={% url 'articles:create' %} method ="POST">
{%comment%} post방식 쓸때는 무조건 csrf_token {%endcomment%}
{% csrf_token %}
<label for="title" class="my-3">Title : </label>
<input type="text" id="title" name="title">
<br>
<label for="content">Content : </label><br>
<textarea name="content" id="content" cols="30" rows="5"></textarea><br>
<input type="submit">
</form>
<br>
<a href= {% url 'articles:index' %}>목록보기</a>
{% endblock content %}
def create(request):
title = request.POST.get('title')
content = request.POST.get('content')
Article.objects.create(title=title, content=content)
return render(request,'articles/create.html')
# 사용자를 특정 url로 보내버림
from django.shortcuts import render , redirect
def create(request):
title = request.POST.get('title')
content = request.POST.get('content')
Article.objects.create(title=title, content=content)
# redirect(url) 방식으로 써주자
return redirect('articles:index')
체계화된 데이터의 모임
여러사람이 공유하고 사용할 목적으로 통합 관리된느 정보의 집합
논리적으로 연관된 (하나 이상의) 자료의 모음
내용을 고도록 구조화 하면서 검색과 갱신의 효율화
몇 개의 자료 파일을 조직적으로 통합하여
자료의 중복을 없애고 자료를 구조화하여 기억시켜놓은 자료의 집합체
CREATE TABLE classmates (
id INTEGER PRIMARY KEY,
name TEXT
);
DROP TABLE classmates;
INSERT INTO classmates ( name, age ) VALUES ('홍길동',23)
INSERT INTO classmates VALUES('홍길동',30,'서울');
SELECT rowid, * FROM classmates;
CREATE TABLE classmates (
-- primary key 값은 integer 로 해줘야 해!
-- 스키마에 id를 직접 작성 했기 때문에, 입력할 column 을 명시하지 않으면 실행 되지 않는다.
id INTEGER PRIMARY KEY,
name TEXT not null,
age INT not null,
address TEXT not null
);
INSERT INTO classmates VALUES
('홍길동',30,'서울'),
('김철수',30,'대전'),
('이싸피',26,'광주'),
('박삼성',29,'구미'),
('최전자',28,'부산');
가장 중요
SELECT 문
-- 전체 출력
SELECT rowid,name from classmates;
-- 1명만 출력되도록 제한
select rowid,name from classmates limit 1;
-- offset 사용시 0 부터 시작한다고 생각하자.
SELECT rowid,name from classmates limit 1 offset 2;
-- 주소가 서울인 경우
SELECT rowid,name from classmates where address = '서울';
-- age 값 전체 출력
SELECT DISTINCT age FROM classmates;
sqlite> .mode csv
sqlite> .import users.csv users
"집계 합수"
값 집합에 대한 계산을 수행하고 단일 값을 반환
SELECT 구문에서만 사용됨
예시
select count(*) from users;
select avg(age) from users where age>=30;
select first_name,max(balance) from users;
select avg(balance) from users
where age>= 30;
select * from users
where age like'2_';
select * from users
where phone like '02-%';
select * from users
where first_name like '%준';
select * from users
where phone like '%-5114-%';
ORDER BY
-- ORDER BY 기본값 -> ASC
select * from users ORDER BY age DESC LIMIT 10;
select * from users ORDER BY age,last_name LIMIT 10;
select last_name , first_name from users
ORDER BY balance LIMIT 10;
Q. users 에서 각 성 씨가 몇명씩 있는지 조회
select last_name , count(*) from users GROUP BY last_name;
AS 를 활용하여 count 에 해당하는 컬럼명을 바꿔서 조회 할 수 있음
select last_name , count(*) AS name_count from users GROUP BY last_name;
ALTER TABLE 의 3가지 기능
table 이름 변경
테이블에 새로운 column 추가
column 이름 수정
ALTER TABLE table_name
RENAME COLUMN current_name TO new_name;
테이블 이름 변경
ALTER TABLE article RENAME TO new_article;
-- 새로운 컬럼 추가
-- 기존 컬럼이 있을 경우 NOT NULL 을 하게 되면 ERROR 발생
ALTER TABLE news add COLUMN created_at TEXT NOT NULL;
-- 1. NOT NULL 설정 없이 추가하기
ALTER TABLE news
ADD COLUMN created_at TEXT;
-- datetime('now') : 현재 시간을 기준으로 저장
INSERT INTO news VALUES('제목','내용',datetime('now'));
-- NOT NULL 을 유지 하면서 컬럼을 추가할 경우, DEFAULT 값을 설정해주면 된다.
ALTER TABLE news
ADD COLUMN subtilte TEXT NOT NULL
DEFAULT '소제목';
-- column 이름 변경 하기
ALTER TABLE news
RENAME COLUMN title to main_title;
-- column 삭제 하기
ALTER TABLE news
DROP COLUMN subtilte;