장고
웹서비스 기본구조
- 백엔드개발(django) -focus!
- 프론트엔드 개발
- 백엔드 서버 운영: 다양한 클라우드
- 앱개발
웹 애플리케이션 기본 구조
- 클라이언트단: 웹브라우저 - 웹서버(django) - 데이터베이스서버(MySQL)
- 클라이언트가 웹서버에 요청
- 장고에서 URL(URLConf)을 기준(미리 URL별로 호출할 함수 등록해둠)> 뷰(함수)- return >URL>웹브라우져
- 뷰에서 DB가 필요할 경우 모델(파이썬코드로 데이터베이스처리함) 통해서 가져옴!!
- 웹브라우저는 html을 요구함. 템플릿(HTML응답을 효과적으로 주기위한 HTML응답소스)을 통해 html로 넘길수있다
장고 따라가기
dev> django-admin startproject askdjango
Django 프로젝트 생성
dev> cd askdjango
dev/askdjango> python3 manage.py migrate
dev/askdjango> python3 manage.py createsuperuser
dev/askdjango> python3 manage.py runserver
디렉토리 이동 (cd : change directory)
Model 내역을 데이터베이스에 반영
Superuser 계정 생성
개발서버 구동
Django App, URLConf, Template
장고는 원프로젝트, 멀티 앱
python3 manage.py startapp 이름 해서 앱생성후 프로젝트디렉토리 안에 인서트.py에 꼭 추가하기(마지막 , 꼭쓰기)
템플릿을 쓸때는 무조건 앱이름/post_list.html 방식으로쓰기(관리용이)
import include, url 해서 url(r’^blog/‘, include(‘blog.urls’)) 하면 url로 들어오면 blog에 urls.py를 실행
장고를 runserver를 할때 템플릿 다 읽고 시작하므로 새로 만들면다시 시작해야함
python3 manage.py runserver 0.0.0.0:8000 하면 로컬 서버 주소바꾸기가능
ifconfig로 현재 자신의 있는 네트워크 ip주소알수있다. en0 >inet
외부망을 통해 다른기기에서 접속은 ngrok 쓰자 (로컬서버에 접속가능) (외부망설정 귀찮)(./ngrok http 8000)(forwarding 주소로 ㄲ) (프로젝트에 setting.py > ALLOWED_HOSTS 에 앞에 주소 추가해주기, *로하면 모든 도메인 허용임)(ngrok는 주소는 변경됩니다. 고정은 유로임. )(테스트용)
하지만 모바일용에 적합하지 않으므로 템플릿에 추가하기( meta테그에 아래것추가)
1
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0,maximum-scale=1.0, user-scalable=no" />
- 앱추가시 꼭해야하는것: 프로젝트에 setting.py에 앱추가, urls.py 에 include, 새로한 앱안에 urls.py 만들기
- 모든 view함수는 첫번쨰인자 (request)
URLConf and Regular Expression
정규표현식(Regular Expression)
문자열의 패턴, 규칙을 정의하는 방법 을 통해 문자열 검색이나 치환작업을 간편하게 처리가능
파이썬3 정규표현식 라이브러리 (r)
다양한 정규표현식 패턴 예시
- 최대3자리숫자:”[0-9]{1,3}”혹은”\d{1,3}”
- 휴대폰번호:”010[1-9]\d{7}”
- 한글이름2글자혹은3글자:”[ᄀ-힣]{2,3}”
- 성이”이”인이름:”이[ᄀ-힣]{1,2}”
1 | val = "01092330203" |
숫자 1글자 : “[0123456789]” 또는 “[0-9]” 또는 “\d”
알파벳 소문자 1글자 : “[abcdefghijklmnopqrstuvwxyz]” 혹은 “[a-z]”
알파벳 대문자 1글자 : [ABCDEFGHIJKLMNOPQRSTUVWXYZ]” 혹은 “[A-Z]”
알파벳 대/소문자 1글자 : “[a-zA-Z]”
16진수 1글자 : “[0-9a-fA-F]”
문자열의 시작을 지정 : “^”
문자열의 끝을 지정 : “$”
한글 1글자 : “[ᄀ-힣]”
한글자를 표현할때 그중한글자의 정보를 []에 담는다 ex) “01[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]”
반복횟수 지정
“\d?” : 숫자 0회 또는 1회
“\d*” : 숫자 0회 이상
“\d+” : 숫자 1회 이상
“\d{m}” : 숫자 m글자
“\d{m,n}” : 숫자 m글자 이상, n글자 이하주의:정규표현식은띄워쓰기하나에도민감합니다.
\가 들어갈경우 맨앞에 r쓰고 “^
~$”쓰기 (이걸해줘야 \ \ d 로 인식함)
URLConf
프로잭트/setting.py 에 최상위 URLConf모듈을 지정 (Root_urlconf 항목에 기본으로 프로젝트의 urls.py가 지정되있다)
Root_url에서 서브로 url.py와 연결
특정URL과뷰매핑List
Django 서버로 Http 요청이 들어올 때마다, URLConf 매핑 List 를 처
음부터 끝까지 순차적으로 훝으며 검색합니다.
매칭되는 URL Rule 을 찾지못했을 경우, 404 Page Not Found 응답
을 발생시킵니다.
URLConf 정규표현식 매핑 연습
- (?P ) : 이 영역의 문자열에 정규표현식을 적용해서 !!!
- \d+ : \d+ 패턴에 부합된다면
: x 라는 변수명으로 인자를 넘기겠다.
• 뷰의인자로넘겨받은값들은모두문자열타입입니다.
1 | Example #4 하나의 뷰에 3개의 URL연결 |
만약 넣은 것에 //100/234//45이라면 빈문자열이 생기므로 int””은 에러가뜸
빈문자열을 없애줘야하므로 sum(map(lambda s: int(s or 0), numbers.split(“/“))) 해야함 #or표현은 s가 거짓일떄 0으로 치환됨
View
URLConf에 매핑된 Callable Object
• 첫번째인자로HttpRequest인스턴스를받습니다. • 필히HttpResponse인스턴스를리턴해야합니다.크게 Function Based View와 Class Based View로 구분
요청에 대한 리턴값으로는 무조건 HttpResponse 인자값이여야함로 html을 직접써서 하던가, 템플릿을 활용한다
from django.shortcuts import render
render사용하여 render(request, ‘myapp/post_list.html’, {‘name’: name}) (템플릿!)
파일다운로드
1
2
3
4
5
6
7
8
9
10def excel_download(request): 'FBV: 엑셀 다운로드 응답하기'
filepath = '/other/path/excel.xls'
filename = os.path.basename(filepath)
with open(filepath, 'rb') as f:
# 필요한 응답헤더 세팅
response = HttpResponse(f, content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename) return response
함수기반view 응답만드는4가지
- HttpResponse
- render(템플릿)
- json
- 파일 다운로드
클래스기반 view
- 함수기반 뷰를 생성해주는 클래스
1 | class SampleTemplateView(object): |
Model and Model Fields
SQL (Structured Query Language) (꼭별도공부)
• Query : 정보 수집에 대한 요청에 쓰이는 컴퓨터 언어 (위키백과)
• SQL : 관계형 데이터베이스 관리 시스템(RDBMS) (Relational Database Management System) 의 데이터를 관리하기 위해 설계된 특수 목적 으로 프로그래밍 언어 (위키백과)
• RDBMS 종류 : PostgreSQL, MySQL, MariaDB 등
• 장고 모델은 RDBMS만을 지원
• 장고 모델을 통해 SQL을 생성/실행 (이런것을ORM이라고함)
- Django 내장 ORM
- SQL을 직접작성하지않아도 장고 모델을 통해 데이터베이스로의 접근(조회추가수정삭제)
- SQL을 몰라도 된다느 것은 아님. 최소한 내가 짠 코드가 어떤 SQL을 만들어내는지검증해야함
DjangoORM 개념
- 엑셀처럼 하나 시트를 테이블이라함 = 이 DB테이블과의 매핑이 Model
- Model Instance= DB 테이블의 1 Row (엑셀에 행!!!!!!!)
- 엑셀의 여러 시트들 !!= DB
Django Model 커스텀 모델 정의 (특정앱/models.py)
데이터베이스 테이블 구조/타입을 먼저 설계를 한 다음에 모델 정의 모델 클래스명은 단수형(Posts가 아니라, Post)
1
2
3
4
5
6from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)- DataBase의 구성요소
파란색 박스 : 행 or 로우(raw) or 레코드(record)
빨간색 박스 : 열 or 컬럼(column) or 필드(field)
AutoField, BooleanField, CharField, DateTimeField, FileField, ImageField, TextField, ForeignKey, ManyToManyField, OneToOneField 많이 쓰는 필드임
데이터베이스 데이터타입과 파이썬 데이터타입을 매핑
AutoField (int), BinaryField (bytes), BooleanField (bool), NullBooleanField (None, bool), CharField/TextField/ EmailField/GenericIPAddressField/SlugField/URLField (str)
같은 파이썬 데이터타입에 매핑되더라도, “데이터 형식” 에 따라 여러 Model Field Types 로 나뉨
자주 쓰는 필드 옵션(모든 데이터필드가능)(연습필요,, 진짜 유용함)
• null (DB 옵션) : DB 필드에 NULL 허용 여부 (디폴트 : False)(null의미는 데이터존재x)
• unique (DB 옵션) : 유일성 여부
• blank : 입력값 유효성 (validation) 검사 시에 empty 값 허용 여부 (디폴트 : False)
• default : 디폴트 값 지정. 값이 지정되지 않았을 때 사용. • 인자없는 함수 지정 가능. 함수 지정 시에는 매 리턴값이 필요할 때마 다 함수를 호출하여 리턴값을 사용
• choices (form widget 용) : select box 소스로 사용
• validators : 입력값 유효성 검사를 수행할 함수를 다수 지정
각 필드마다 고유한 validators 들이 이미 등록되어있기도 함
ex) 이메일만 받기, 최대길이 제한, 최소길이 제한, 최대값 제한, 최소 값 제한, etc.
• verbose_name : 필드 레이블. 지정되지 않으면 필드명이 쓰여짐.
• help_text (form widget 용) : 필드 입력 도움말
(~/nomade/django/askdjango/blog/models.py)
데이터 정의 후에는 makemigrations, migrate 통해 DB에 반영하고 해당 앱에 admin에서
1 | from .models import Post |
- (지금까지과정이 모델정의 정의후에 이대로 DB생성후 admin에 모델에 모델에Post라는 클래스로 등록시킴)
Migration
관련 명령
쉘> python manage.py makemigrations
쉘> python manage.py migrate
쉘> python manage.py showmigrations
쉘> python manage.py sqlmigrate
마이그레이션 파일 생성 및 적용
- makemigrations로 마이그레이션 파일(작업 지시서)(적용전에 무조건까서확인해야함! )(SQL용어로도 확인하면좋음)
- migrate로 데이터베이스에 마이그레이션 파일을 반영함
- 참고로 현재 sqlite3를 쓰고있는데 DB형태 변경은 프로젝트 dir에 setting.py 에 DATABASES 확인 변경
- 눈으로 DB보고싶으면 DBLiteBrowser설치
Migration 정방향(forward) 역방향(reverse)
마이그레이션 적용된것이 blog/0007인상태에서 역방향가고싶으면 (내 현재위치기준으로 정, 역 정해짐)
1
python3 manage.py migrate blog 0006 #zero라고하면 모든 마이그레이션 적용모두 취소
id필드는 왜 기본임?
• 모든 데이터베이스 테이블에는 각 Row 의 식별기준인 “기본키 (Primary Key)” 가 필요
• Django 에서는 기본키로서 id 필드(AutoField)가 디폴트 지정
• 기본키는 줄여서 pk 로도 접근 가능 (primary key)
기존 모델 클래스에 필수필드를 추가하여 makemigrations 수행
필수필드는 인자가있어야만 DB에저장할수잇는것
(blank, null가 기본적으로 False이므로 따로True지정안하는이상 필수필드됨임)
필수필드를 추가하므로, 기존 Row들에 필드를 추가할때, 반드시 채워넣어야하므로 어떤 값으로 채워넣을 지 묻습니다
선택1) 지금 값을 입력!!! 새로생기는 필드의기존빈것들전체동일적용됨 (반드시 필드타입확인후 같은 타입 입력 (int str,,,등)
선택2) 모델 클래스를 수정하여 디폴트 값을 제공
Django Shell
장고 모듈등을 사용할려면 필히 장고 환경에 접근해야하므로 (일반 파이썬셀은 접근불가함)(장고프로젝트에 setting.py에존재)
1 | python3 manage.py shell #장고환경 접근가능! |
Jupyter Notebook 으로 장고쉘 띄우기
1 | pip3 install django-extensions 설치후에 프로젝트 settings.py내 INSTALLED_APPS에 django_extensions추가해야함 !!! 이것은 앱형태이므로!!! |
실행하려면
1 | python manage.py shell_plus #쉘에서 필요한것 자동으로 import해줌 |
쥬피터 노트북이 유리한이유는 log남길수있고 이미지등도 확인할수있고 즉각적이라 더욱 좋다
1 | import os |
Django Admin
staff/superuser만 접근가능 (Users에서 권한 부여가능)
모델 클래스만 등록하면, 조회/추가/삭제 가능 (#ModelCls 는 모델에 클래스 이름을 적으면됨)
1 | admin에 DB등록하는 법! |
ModelAdmin Options (admin.ModelAdmin)
• list_display : Admin 목록에 보여질 필드 목록.
• list_display_links : 목록 내에서 링크로 지정할 필드 목록. #이를 지정하지 않으면, 첫번째 필드에만 링크가 적용
• list_editable : 목록 상에서 수정할 필드 목록
• list_per_page (디폴트 : 100) : 페이지 별로 보여질 최대 갯수
• list_filter: 필터 옵션을 제공할 필드 목록
• actions : 목록에서 수행할 action 목록
위에가 쉽게 쓰임.
• fields: add/change 폼에 노출할 필드 목록
• fieldsets: add/change 폼에 노출할 필드 목록 (fieldset)
• formfield_overrides : 특정 Form Field 에 대한 속성 재정의
• form : 디폴트로 모델 클래스에 대한 Form Class 지정
list_display 옵션
- 모델 인스턴스 필드명/속성명/함수명 뿐만 아니라, ModelAdmin 내 맴버 함수도 지정가능
1 | @admin.register(Post) |
Admin Actions
대개 선택된 Model Instance 들에 대해 Bulk Update 용도 구현 #한번에 여러개 인스턴스 업데이트
- ModelAdmin 클래스내 멤버함수로 action 함수를 구현
- 멤버함수.short_description 을 통해, action 설명 추가
- ModelAdmin actions 내에 등록 #모든액션 첫번째인자는 request 두번째 queryset
아래는 이페이지 완성될때 model.py에 모델클래스
1 | from django.db import models |
CRUD
Model Manager
데이터베이스 질의 인터페이스를 제공
디폴트 Manager로서 ModelCls.objects가 제공 ex) post.objects.all()
1
2
3ModelCls.objects.all() # 특정 모델의 전체 데이터 조회
ModelCls.objects.all().order_by('-id')[:10] # 특정 모델의 최근 10개 데이터 조회
ModelCls.objects.create(title="New Title") # 특정 모델의 새 Row 저장
QuerySet (알아서 SQL언어로 변경해줌)
- SQL을 생성해주는 인터페이스!
- Model Manager 를 통해, 해당 Model 에 대한 QuerySet 을 획득
- Post.objects.all() 는 “SELECT * FROM post;” 와 같은 SQL 을 생성하여, 데이터베이스로의 질의를 수행
- Post.objects.create(…) 는 “INSERT INTO …;” 와 같은 SQL을 생성하여, 데이터베이스로의 질의를 수행
- Chaining 지원 : QuerySet 수행 리턴값이 다시 QuerySet
데이터베이스에 데이터 조회 요청 (retrieve)
QuerySet을 통한 AND 조회 조건 추가 (아래 예시들은 모두 AND조건으로추가됨) (ModelCls는 내가쓴 모델클래스이름)
1
2
3
4
5
6queryset = ModelCls.objects.all() #아래예시는 모두 이어지는것 #filter대신 exclude쓰면 and조건으로제외
queryset = queryset.filter(조건필드1=조건값1, 조건필드2=조건값2)
#Chaining지원이므로 쿼리셋리턴값 퀴리셋임
queryset = queryset.filter(조건필드3=조건값3) #계속 퀴리셋으로 추가됨
queryset = queryset.filter(조건필드4=조건값4, 조건필드5=조건값5)
#여기까지하면 즉 queryset이 모두1,2,3,4,5 조건필드1,2,3,4,5에 각자 맞는 조건값을 가진것이 and조건을 찾는 SQL명령어생성됨, 실행은 아직안됨or조건으로 할려면
1
2from django.db.models import Q
Post.objects.filter(Q(title__icontains='1')|Q(title__endswith="3")) #|가 or를 뜻하지queryset은 명령을 대기중이며 실제로 DB접근하는건 다른 명령이 수행될때임 즉위에코드는 계속 명령작성추가하는거임
- render에서 render에 3번쨰 인자로 딕셔너리 형태로 다양한 인자들을 넘겨줄수있다,
1 | blog/view.py |
데이터베이스에 특정 필드로 정렬 조건 추가
- queryset내 기본정렬은 모델내 Meta.ordering설정을 따릅니다.
1 | - class Post(models.Model): (필드 정의 생략) |
- 필드명만 지정시 오름차순 정렬 요청, “-필드명” 지정시 내람차순 정렬 요청 정렬 미지정시에는 데이터베이스 측에서 임의정렬
1 | # 모델 Meta.ordering 을 무시하고, 직접 정렬조건 지정하는법 |
슬라이싱을 통한 범위 조건 추가
queryset = queryset[:10] # 현재 queryset에서 처음10개만 가져오는 조건을 추가한 queryset queryset = queryset[10:20] # 현재 queryset에서 처음10번째부터 20번째까지를 가져오는 조건을 추가한 queryset
리스트 슬라이싱과 거의 유사하나, 역순 슬라이싱은 지원하지 않음
queryset = queryset[-10:] (AssertionError 예외 발생 AssertionError: Negative indexing is not supported.)
이때는 먼저 특정 필드 기준으로 내림차순 정렬을 먼저 수행한 뒤, 슬라이싱
queryset = queryset.order_by(‘-id’)[:10]
지정 조건으로 DB로부터 데이터를 Fetch(가져오기)
지정 조건의 데이터 Row를 순회
for model_instance in queryset:
print(model_instance)
지정 조건 내에서 특정 인덱스 데이터 Row를 Fetch
model_instance = queryset[0] # 갯수 밖의 인덱스를 요청할 경우 IndexError 예외 발생 model_instance = queryset[1]
특정 조건의 데이터 Row 1개 Fetch (1개!! 2개이상말고 1개!! 0개말고 1개!!)
model_instance = queryset.get(id=1)
model_instance = queryset.get(title=’my title’)
queryset.get은 예상되는 데이터가 1개일떄만 에러안뜨고 정상 처리
qureyset.first() 혹은 queryset.last()
지정 조건 내에서 첫번째/마지막 데이터 Row를 Fetch, 지정 조건에 맞는 데이터 Row가 없더라도, DoesNotExist 예외가 발 생하지 않고, None을 반환
데이터베이스에 데이터 추가 요청 (create)
(필수 필드1를 모두 지정을 하고, 데이터 추가가 이뤄져야합니다. • 그렇지 않으면, IntegrityError 예외 발생)
- 방법 #1) 각 Model Instance 의 save 함수를 통해 저장
1 | >>> model_instance = ModelCls(field1=value1, field2=value2) # New Model Instance |
- 방법 #2) 각 Model Manager 의 create 함수를 통해 저장
1 | >>> 인스턴스 = ModelCls.objects.create(필드명1=값1, 필드명2=값2) # DB에 저장을 시도 |
데이터베이스에 데이터 갱신 요청
- 방법 1) 각 Model 인스턴스 속성을 변경하고, save 함수를 통해 저장 • 각 Model 인스턴스 별로 SQL 이 수행 • 다수 Row 에 대해서 수행 시에는 성능저하가 발생할 수 있음
1 | >>> post = Post.objects.get(id=1) |
- 방법 2) QuerySet 의 update 함수에 업데이트할 속성값을 지정하여 일괄 수정 하나의 SQL 로서 동작하므로, 동작이 빠르다.
1 | >>> queryset = Post.objects.all() |
데이터베이스에 데이터 삭제 요청
- 방법 1) 각 Model 인스턴스의 delete 함수를 호출하여, 데이터베이스 측의 관련 데이터를 삭제
1 | • 각 Model 인스턴스 별로 SQL 이 수행 |
- 방법 2) QuerySet 의 delete 함수를 호출하여, 데이터베이스 측의 관 련 데이터를 삭제
1 | 하나의 SQL 로서 동작하므로, 동작이 빠르다. |
웹서비스, 각 요청 반응속도에서의 병목
데이터베이스 : 아주 중요
• DB로 전달/실행되는 SQL갯수를 줄이고
• 각 SQL의 성능/처리속도 최적화가 필요
• 로직의 복잡도 : 중요 • 프로그래밍 언어의 종류 : 대개는 미미
tip
django-debug-toolbar
• 현재 request/response 에 대한 다양한 디버깅 정보를 보여줍니다.
• SQLPanel을 통해 각 요청 처리 시에 발생한 SQL 내역 확인 가능 • 웹서비스 성능과 직결 = 응답속도
# 프로젝트/settings.py
INSTALLED_APPS = […, “debug_toolbar”]
MIDDLEWARE = [“debug_toolbar.middleware.DebugToolbarMiddleware”, …]
INTERNAL_IPS = [“127.0.0.1”]
#프로젝트/urls.py
from django.conf import settings
from django.conf.urls import include, url
if settings.DEBUG:
import debug_toolbar
urlpatterns += [ url(r’^debug/‘, include(debug_toolbar.urls)), ]
/
/ 꼭 바디테그가 필요함( 바디테그에 대입해서 툴바가 나오므로)