[Django] 파이썬

Magit·2020년 6월 14일
0

Django

목록 보기
13/13

기본 생선된 파일/디렉토리 목록
기본 템플릿 : django/conf/project_template 의 내역으로 생성이 된 것.

  • djangoexample : 프로젝트명으로 생성된 디렉토리. 다른 이름으로 변경해도 괜찮다.
  • manage.py : 명령행을 통해 각종 장고 명령을 수행
  • djangoexample : 프로젝트명으로 생성된 디렉토리. 이 이름을 참조하고 있는 코드가 몇 개 있기에 함부로 수정하면 안된다.
    • init.py : 모든 파이썬 패키지는 init.py를 둔다. 패키지를 import할 때의 import 대상
    • setting.py : 현재 프로젝트에서 장고 기본설정(django/conf/global_setting.py)을 덮어쓰고 새롭게 지정할 설정들
    • urls.py : 최상위 URL 설정
    • wsgi.py : 실서비스에서의 웹서비스 진입점
    • asgi.py : 장고 3.0에서 추가됨. 비동기 지원 프로토콜. 장고 실서비스의 진입점

장고 주요 구성요소

  • Function Based Views : 함수로 HTTP 요청 처리. 매 요청이 올때마다 특정 함수가 실행되는데 그 함수를 view라고 한다.
  • Models : 데이터베이스와의 인터페이스를 담당하는 ORM이라는 영역
  • Templates : 복잡한 문자열 조합을 용이하게 도와줌. 주로 HTML 문자열 조합 목적으로 사용하지만, 푸쉬 메세지나 이메일 내용을 만들 때 쓰면 편리하다.
  • Admin 기초 : 심플한 데이터베이스 레코드 관리 UI 기능 제공. 우리가 관리 웹페이지를 만들지 않아도 장고가 기본적인 부분을 지원해줌. 그러나 시스템관리자정도의 역할만 할 수 있다.
  • Logging : 파이썬에서 지원해주는 logging 기능이다. 다양한 경로로 메세지 로깅
  • Static files : 개발 목적으로 정적인 파일 관리
  • Messages frameword : 유저에게 1회성 메세지 노출 목적. 저장하고 저장했습니다. 삭제하고 삭제했습니다 같은 메세지를 보여줌.
  • Class Based Views : 클래스로 함수 기반 뷰 만들 수 있음. 함수 기반 뷰와 같이 굉장히 중요하다.
  • Forms : 입력폼 생성, 입력값 유효성 검사 및 DB로의 저장이 가능해진다. 장고에서 굉장히 중요한 부분이다.

장고 기본 앱

  • 장고가 규정해놓은 파이썬 패키지라고 보면 된다.
  • admin, admindocs, auth 등등
  • 이 앱의 기능들을 이용해서 개발을 더 편하게 할 수 있다.

웹 애플리케이션 기본 구조

  • 웹브라우저가 어떠한 서버로 요청을 보내게된다. (당연하게도 클라이언트가 항상 먼저 요청을 하게된다.) 그리고 그에 맞춰서 로직이 수행이되고 그 로직에 맞춰서 데이터베이스로부터 데이터를 갖고온다던지 수정, 삭제등을 한다. 그 다음에 캐시서버에 셋팅 혹은 업데이트 혹은 삭제를 하고 값을 갖고와서 응답을 만든다음에 클라이언트에게 응답을 보내준다. 그 응답은 HTMl, 엑셀, pdf 등 다양한 방법으로 보낼 수 있다. 서버단에서는 클라이언트가 원하는 형식의 어떠한 포맷으로라도 응답을 만들 수 있다. 이미지도 가능하다.

  • 장고에서

    • 웹서버 부분을 확대해보면 URLConf / View / Model / Template 엔진이 있다.
    • 클라이언트가 요청을 하게되면 URLConf(미리 URL별로 호출할 함수를 리스트에 등록해놓음)에서 요청한 URL에 맞춰서 어떠한 함수가 즉, View가 호출된다. 이 함수가 수행될 때 데이터베이스와 interaction이 필요할 때에는 sql이라는 언어를 이용해서 해야하지만, 장고에서는 model에서 파이썬 코드로 데이터베이스와 통신이 가능하게 해주므로 좀 더 수월하게 interaction 할 수 있다. 웹 브라우저에서 html 문자열을 응답을 줄 때는 템플릿 엔진을 활용하면 훨씬 수월해진다. 템플릿 엔진은 복잡한 문자열을 손쉽게 조합하기 위한 문자열 렌더링 엔진이다.

장고 앱

장고 앱의 필요성

  • 현재 프로젝트의 블로그 기능을 다른 프로젝트에서도 사용하려면?
    • 블로그를 장고앱 형태로 격리해서 만들어둔다면, 다른 프로젝트에도 적용하기 편리하다.
  • 재사용성을 목적으로한 파이썬 패키지가 장고 앱이다.
    • 재사용성을 목적으로 두지 않았다면, 하나의 장고 앱에서 현재 프로젝트의 거의 모든 기능을 구현해도 무방하다. 앱을 하나의 작은 서비스로 봐도 무방하다.
  • 하나의 앱 이름은 현재 프로젝트ㅡ 상에서 유일해야한다.
  • 새롭게 생성한 장고앱이나 외부 라이브러리 형태의 장고앱은 필히 settings.INSTALLED_APPS에 등록을 시켜줘야만 장고앱으로서 대접을 받는다.
  • 앱의 URLConf를 제외한 많은 부분(모델, 템플릿, static 등) 들이 자동으로 등록된다.

장고 모델 (ORM)

데이터베이스와 SQL

  • 데이터베이스는 별도의 서버이고 우리는 이 서버에 SQL이라는 언어를 통해서 질의(query)를 할 수 있다.
  • 데이터베이스에 쿼리하기 위한 언어 : SQL
    • 같은 작업을 하더라도 보다 적은 수의 SQL, 보다 높은 성능의 SQL을 할 수 있다면 더 성능좋은 서비스 일 것이다.
    • 직접 SQL을 만들어내긷 하지만, ORM을 통해 SQL을 생성/실행하기도 한다.
      • ORM을 쓰더라도 내가 작성된 ORM코드를 통해 어떤 SQL이 실행되고 있는지, 파악하고 이를 최적화할 수 있어야 한다. (django-debug-toolbar 적극 활용)
  • 장고 ORM인 모델은 RDB만을 지원한다.
    • 장고 3.0.2 기준으로 기본 제공되는 백엔드는 mysql, oracle, postgresql, sqlite3가 있다.
    • Microsoft SQL Server는 django-pyodbc-azure 라이브러리 필요

장고의 강점은 Model과 Form

  • 장고에 다양한 ORM, 라이브러리 사용 가능하지만 Model/Form이 굉장히 유용하다.
  • SQL을 직접 실행할 수 있지만 가능하면 ORM을 써보자.

Django Model

  • <데이터베이스 테이블>가 <파이썬 클래스>를 1:1로 매핑한다.
  • 모델 클래스명은 단수형으로 지정 (예. Posts(x), Post(o))
  • 매핑되는 모델 클래스는 DB테이블 필드 내역이 일치해야한다.
  • 모델을 만들기 전에, 서비스에 맞게 데이터베이스 설계가 필수이다.
  • 이는 데이터베이스 영역인데, 관계형 데이터베이스 학습도 필요하다.

  • 파이썬 클래스를 정의할때는 앱 폴더에 있는 models.py에 정의하면 된다.
class Post(models.Model): # models.Model 은 파이썬의 상속 문법이다. models의 Model을 상속받아서 Post라는 클래스를 만든다.

필드명 = models.타입

Model Work Flow

  • 장고 모델을 통해 데이터베이스 형상을 관리할 경우
    • 모델 클래스 작성
    • 모델 클래스로부터 마이그레이션 파일 생성 -> makemigrations 명령
    • 마이그레이션 파일을 데이터베이스에 적용 -> migrate 명령
    • 모델 활용
  • 장고 외부에서 데이터베이스 형상을 관리할 경우
    • 데이터베이스로부터 모델 클래스 소스 생성 - inspectdb 명령
    • 모델 활용

모델명과 DB 테이블명

  • DB 테이블명 : 디폴트 "앱이름_모델명"
    • 예) blog앱의 Post모델 -> "blog_post"
  • 커스텀 지정 : 모델 Meta 클래스의 db_table 속성
python manage.py sqlmigrate 앱이름 

# 실제로 데이터베이스에 들어가는 쿼리를 볼 수 있다.

$ CREATE TABLE "instagram_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "message" text NOT NULL, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)

# 테이블 이름이 "instagram_post"이며 장고에서 자동적으로 지정해주는 id 필드가 프라이머리키로 지정. message, created_at, updated_at이 생성된다.

기본 지원되는 모델 필드 타입 (1)

Primary Key : AutoField(숫자가 1부터 자동 증가), BigAutoField
문자열 : CharField, TextField, SlugField(
날짜/시간 : DateField, TimeField, DateTimeField, DurationField
참/거짓: BooleanField, NullBooleanField
숫자 : IntegerField, SmallIntegerField
파일 : BinaryField, FileField, ImageField, FilePathField

기본 지원되는 모델필드 타입 (2)

이메일 : EmailField
URL : URLField
UUID : UUIDField
아이피 : GenericIPAddressField

  • Relationship Types
    • ForeignKey (외래키)
    • ManyToManyField
    • OneToOneField

모델필드들은 DB 필드타입을 반영

  • DB에서 지원하는 필드들을 반영한다.
    • Varchar 필드타입 -> CharField, SlugField(제목으로부터 슬러그를 생성 제목-ㅇㅇ-ㅁㅁ 이런식의 이름), URLField, EmailField 등
  • 파이썬 데이터타입과 데이터베이스 데이터타입을 매핑
    • AutoField : int
    • BinaryField : bytes
    • BooleanField : bool
    • CharField, SlugField, URLField, EmailField : str
      • 디폴트로 적용된 장고단의 유효성 검사 등의 차이가 있을 수 있다.
      • CharField는 유효한 길이만큼의 문자열을, URLField는 문자열이지만 URL형태만 가능 등
  • 같은 모델필드라 할지라도, DB에 따라 다른 타입이 될 수 있다.
    • DB에 따라 지원하는 기능이 모두 달라진다.
    • 사용하는 DB가 바뀌면 SQL을 꼭 확인하자.

자주 쓰는 필드 공통 옵션

  • blank : 장고 단에서 validation시에 empty 허용 여부 (디폴트: False)
    • 만약 문자열이라면 문자열이 비어있을 때 허용하지 않는다는 의미
  • null (DB옵션) : null 허용 여부 (디폴트: False)
  • SlugField는 제목으로부터 슬러그를 생성하는 admin의 기능을 사용할 수 있다.
    • option으로 allow_unicode=True를 넣으면 한글도 지정 가능
  • PositiveIntegerField(default=0) 로 0부터 시작하는 양수로 더 타이트하게 지정할 수 있다.
  • tag_set = models.ManyToManyField('Tag', blank=True)
    • 하나의 포스팅이 다수의 태그, 하나의 태그가 다수의 포스팅에 있을 수 있으므로 manytomany
  • reated_at = models.DateTimeField(auto_now_add=False) : 레코드가 생성될때, 즉 데이터베이스에 insert가 될 때 시각이 자동입력
  • updated_at = models.DateTimeField(auto_now=True) : 이 모델을 통해서 저장을 할 때, 수정 시각이 자동 입력

강력히 권한다!

  • 설계한 데이터베이스 구조에 따라, 최대한 필드타입을 타이트하게 지정해주는 것이, 입력값 오류를 막을 수 있다.
  • 모델 설계에 공을 들여라!
    • blank/null 지정은 최소화 -> manage.py inspect 명령을 통해 생성된 모델 코드는 초안이다.
    • validators들이 다양하게 타이트하게 지정된다.
    • 필요하다면 validators(유효성 검사 로직)들을 추가로 타이트하게 지정
    • 프론트엔드에서의 유효성 검사는 사용자 편의를 위해서 수행함, 백엔드에서의 유효성 검사는 필수이다.
    • 직접 유효성 로직을 만들지 말자. 이미 잘 구성된 Features들을 가져가 쓰자. 장고의 Form/Model을 통해 지원되며, django-rest-framework의 Serializer를 통해서도 지원된다.
  • ORM은 SQL쿼리를 만들어주는 역할일 뿐, 보다 성능높은 어플리케이션을 위해서는 사용하려는 데이터베이스에 대한 깊은 이해가 필요하다.

장고 admin을 통한 데이터관리

  • django.contrib.admin 앱을 통해 제공된다.

    • 디폴트경로 : /admin/ -> 실제 서비스에서는 다른 주소로 변경 권장
    프로젝트 urls.py
    
    path('admin/', admin.site.urls),
    
    # admin/ 로 시작하는 주소 요청에 대해서는 어드민앱에서 처리하겠다는 선언
    # 'myadmin/' 같이 주소를 바꿔도 장고가 알아서 처리해준다. (URL Reverse 기능)
    • 혹은 django-admin-honeypot 앱을 통해, 가짜 admin 페이지 노출시킬 수 있다. 동일하게 admin 페이지가 뜨지만 절대 로그인을 허용하지 않고 로그인을 시도한 사람의 ip 기록을 db에 기록해둔다.
  • 모델 클래스 등록을 통해, 조회/추가/수정/삭제 웹 UI를 제공 (- 모델을 어드민 페이지에서 사용하려면 어드민앱에 등록을 하는 과정이 필요하다.)

    • 서비스 초기에 관리도구로서 사용하기에는 제격
    • 관리도구 만들 시간을 줄이고, End-User 서비스에 집중
  • 내부적으로 Django Form을 적극적으로 사용

  1. 모델 클래스를 admin에 등록하기
/admin.py

from django.contrib import admin
from .models import Post

admin.site.register(Post) # admin 페이지에서 Instagram 프로젝트의 Posts가 보인다.

관계를 표현하는 모델 필드

ORM은 어디까지나 SQL 생성을 도와주는 라이브러리
ORM이 DB에 대한 모든 것을 알아서 처리해주진 않는다.
보다 성능높은 애플리케이션을 만들고자 한다면, 사용할 DB엔진과 SQL에 대한 높은 이해가 필요하다.

RDBMS에서의 관계 예시

1:N 관계 -> models.ForeignKey로 표현

  • n측에다가 외래키를 심는다.
    1명의 유저(User)가 쓰는 다수의 포스팅(Post)
    1명의 유저(User)가 쓰는 다수의 댓글(Comment)
    1개의 포스팅(Post)에 다수의 댓글(Comment)
    유저-포스팅-댓글 관계가 있을 때, 유저-포스팅에서는 포스팅쪽에 외래키를, 포스팅-댓글에서는 댓글에 외래키를, 유저-댓글에서는 댓글에 외래키를 심는다.

1:1 관계 -> models.OneToOneField로 표현

  • 관계를 어느쪽에 명시해도되는데, 대개 유저보다는 프로필측에 정의한다.
    1명의 유저(User)는 1개의 프로필(Profile)

M:N 관계 -> models.ManyToManyField로 표현

  • 1개의 포스팅(Post)에는 다수의 태그(Tag)
    1개의 태그(Tag)에는 다수의 포스팅(Post)

ForeignKey

  • 1:N 관계에서 N측에 명시
    • Post:Comment, User:Post, User:Comment

ForeignKey(to, on_delete)

  • to : 대상모델
    • 클래스를 직접 지정하거나, 클래스명을 문자열로 지정. 자기 참조는 'self' 지정
  • on_delete : Record 삭제 시 Rule
    • CASCADE : FK로 참조하는 다른 모델의 Record도 삭제
    • PROTECT : ProtectedError (IntegrityError 상속)를 발생시키며, 삭제 방지
    • SET_NULL : null로 대체. 필드에 null=True 옵션 필수 (1대 N 관계에서 1이 삭제되어도 Comment를 삭제하지 않고 null로 대체한다.)
  • 각각의 모델마다 PK라고 Primary Key가 있다. 이름은 디폴트로 id이다.
    • Post-Comment 1:N 관계에서 Post의 각각의 레코드마다 PK값이 있다. 그럼 1:N의 관계에서 1에 속해있는 Post의 Pk를 Comment에 저장해야한다. 그럼 저장할 필드명을 post_id로 만들게되는데 Model에서 코딩을 할 때는 post = ... 로 하면 실제 데이터베이스에서 post_id 라는 이름으로 저장된다. 실제 저장되는 값은 1, 2, 3, 4... 이렇게 올라갈것이다.

올바른 유저 모델 지정

# django/contrib/auth/modesl.py
class Uset(AbstractBaseUser):
	...

#blog/models.py
class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length = 100)

>>> user.post_set.all()

# User 모델의 세팅값이 변할 수 있으므로 from django.conf import settings 을 import해서 settings.AUTH_USER_MODEL을 직접 갖고오는게 더 안전하다.

FK에서의 reverse_name

reverse 접근 시의 속셩명 : 디폴트 -> "모델명소문자_set"

from django.db import models

class Post(models.Model):
	title = models.CharField(max_length=100)
    content = models.TextField()

class Comment(models.Model):
	post = models.ForeignKey(Post, on_delete=models.CASCADE)
    message = models.TextField()

# 디폴트는 1:N의 관계에서 1측에서 사용하는 것이다. 1 측에는 참조할 이름이 없기에, '모델명소문자_set'이 생긴다. 즉, 'post_set'이 생긴다.

OneToOneField

  • 1:1 관계에서 어느쪽이라도 지정 가능
    • User:Profile
    • 만약 auth앱을 사용하는 user면 profile 측에 지정한다.
  • ForeignKey(unique=True)와 유사하지만, reverse에서 차이가 난다.
    • User:Profile를 FK로 지정한다면 -> profile.user_set.first() -> user
    • User:Profile를 O2O로 지정한다면 -> profile.user -> user
  • OneToOneField(to, on_delete)
class Profile(models.Model):
	author = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

# 하나의 유저는 하나의 프로필을 갖는다라는 의미. 필드명은 임의로 지으면 된다.

ManyToManyField

ManyToManyField(to, blank=False)

  • blank=True 로 해도 된다. 포스팅을 작성할 때, 태그를 안넣을수도 있지않은가? 그럴때를 위해 blank=True도 괜찮다.
  • Tag를 활용하는 Post와 Article에 tag_set=models.Many... 를 지정하는게 의미에 맞는것 같다.

Migrations

모델의 변경내역을 '데이터베이스 스키마'로 반영시키는 효율적인 방법을 제공

1. 마이그레이션 파일 생성
python manage.py makemigrations <앱이름>

2. 지정 마이그레이션의 SQL 내역 출력
python manage.py sqlmigrate <앱이름> <마이그레이션-이름>

3. 지정 데이터베이스에 마이그레이션 적용
python manage.py migrate <앱이름>

4 마이그레이션 적용 현황 출력
python manage.py showmigrations <앱이름>

# 순서로는 1-2-3에 4는 중간중간 확인차하게된다
# 1. 모델에 변경사항이 생기고 makemigrations 를 하면 마이그레이션 파일이 생성된다.
# 2. 그리고 실제로 DB에 어떠한 변화를 가할것인지 SQL 문법으로 확인할 수 있다. 미리 확인하고 migrate를 하는게 좋다.
# 3. 데이터베이스에 실제로 변화를 가하게된다.

Migration 파일

  • 데이터베이스에 어떤 변화를 가하는 Operations들을 나열

    • 테이블 생성/삭제, 필드 추가/삭제 등
    • 커스텀 파이썬/SQL Operation
      • 데이터 마이그레이션 등
  • 대개 모델로부터 자동 생성 -> makemigrations 명령

    • 모델 참조없이 빈 마이그레이션 파일 만들어서 직접 채워넣을수도 있다.
  • 주의) 같은 Migration 파일이라 할지라도, DB 종류에 따라 다른 SQL이 생성된다.

    • 모든 데이터베이스 엔진들이 같은 기능을 제공하진 않는다.
      • 예) 예전에는 SQLite DB에서는 기존 테이블에 컬럼 추가가 지원되지 않는다.

언제 makemigrations를 하는가?

  • 모델 필드 관련된 어떠한 변경이라도 발생시에 마이그레이션 파일 생성
    • 실제로 DB Scheme에 가해지는 변화가 없더라도 수행
  • 마이그레이션 파일은 모델의 변경내역을 누적하는 역할
    • 적용된 마이그레이션 파일은 절대 삭제하면 안된다
    • 마이그레이션 파일이 너무 많아질 경우, squashmigrations 명령으로 다수의 마이그레이션 파일을 통합할 수 있다.

마이그레이션 Migrate (정/역방향)

  • python manage.py migrate <앱이름>

다양한 응답의 함수 기반 뷰

View

  • 1개의 HTTP 요청에 대해 -> 1개의 뷰가 호출

  • urls.py/urlpatterns 리스트에 매핑된 호출 가능한 객체

    • 함수도 호출 가능한 객체 중의 하나
  • 웹 클라이언트로부터의 HTTP 요청을 처리

  • 크게 2가지 형태의 뷰

    • 함수 기반 뷰 (Function Based View) : 장고 뷰의 기본
      • 호출 가능한 객체 그 자체
    • 클래스 기반 뷰 (Class Based View)
      • 클래스.as_view() 를 통해 호출가능한 객체를 생성/리턴

View 호출 시, 인자

  • HttpRequest 객체 및 URL Captured Values
  • 1번째 인자 : HttpRequest 객체
    • 현재 요청에 대한 모든 내역을 담고 있습니다.
  • 2번째~ 인자 : 현재 요청의 URL로부터 Capture된 문자열들
    • url/re_path를 통한 처리에서는 -> 모든 인자는 str 타입으로 전달
    • path 를 통한 처리에서는 -> 매핑된 Converter의 to_python에 맞게 변환된 값이 인자로 전달
      • 지난 에피소드의 4자리 년도를 위한 FourDigitYearConverter에서는 int 변환 -> 뷰의 인자로 int 타입의 년도가 전달

View 호출에 대한 리턴값

  • HttpResponse 객체
  • 필히 HttpResponse 객체를 리턴해야한다.
    • 장고 Middleware에서는 뷰에서 HttpResponse 객체를 리턴하기를 기대한다. -> 다른 타입을 리턴하면 Middleware에서 처리 오류
    • django.shortcuts.render 함수는 템플릿 응답을 위한 shortcut 함수
  • 파일like객체 혹은 str/bytes 타입의 응답 지원
    • str 문자열을 직접 utf8 로 인코딩할 필요가 없다.
      • 장고 디폴트 설정에서 str 문자열을 utf8로 인코딩해준다.
    • response = HttpResponse (파일like객체 또는 str객체 또는 bytes 객체)
profile
이제 막 배우기 시작한 개발자입니다.

1개의 댓글

comment-user-thumbnail
2023년 3월 15일

너무 잘 정리해놓으신 것 같습니다. 현업에서 많이 참고하겠습니다!

답글 달기