금일 정리할 내용은 파이썬 웹 프레임워크인 장고!
이번 주차부터 장고를 활용한 API서버 만들기를 주제로 학습을 진행한다.
우선 가상환경에 대해 알아보자.
Django 프로젝트 진행 시 로컬서버에 프로젝트를 만들어 작업하지 않고 프로젝트마다 가상환경을 설정해준다. 그 이유로, 진행하는 각 프로젝트 별 라이브러리, 모듈 버전이 다르기 때문이다.
코드로 가상환경에 대해 알아보면 다음과 같다.# 파이썬에서 가상환경 생성 py -m venv project-name # 가상환경 활성화 project-name\Scripts\activate.bat # 비활성화 deactivate # 활성화한 가상환경에 장고 설치 py -m pip install Django # 장고 올바르게 설치되었나 체크 django-admin -version # 장고 프로젝트 만들기 (project_name : mysite) $ django-admin startproject mysite # 만든 프로젝트로 디렉토리명 변경 이후 서버 작동 (서버는 자동 변경) (mysite)$ python manage.py runserver
Django 프로젝트(하나의 웹사이트)가 생성될 때마다 manage.py 파이썬 파일이 새로 생성되고 해당 파이썬 파일을 실행함으로써 기본 웹 페이지를 띄울 수 있다.
웹사이트 내 카테고리 느낌
# 앱 생성하기 (새로운 폴더에 앱 생기고 url, views 등 python 파일 자동생성) (프로젝트명)$ python manage.py startapp app_name
💡 기본적으로 프로젝트를 생성하면 자동으로 생기는 파이썬 파일
- mysite/manage.py : Django 프로젝트(웹사이트)와 다양한 방법으로 상호작용하는 커맨드라인의 유틸리티
- mysite/ : 프로젝트를 위한 실제 파이썬 패키지들이 저장
- mysite/init.py : 파이썬으로 하여금 해당 디렉토리를 패키지처럼 다루도록 알려주는 빈 파일
- mysite/settings.py : 현재 Django 프로젝트의 환경 및 구성을 저장
- mysite/urls.py : 현재 Django 프로젝트의 url 선언 (작성된 웹사이트의 목차)
- mysite/aspi.py : 현재 프로젝트를 서비스하기 위한 ASGI-호환 웹 서버 진입점
- mysite/wsgi.py : 현재 프로젝트를 서비스하기 위한 WSGI-호환 웹 서버 진입점
💡 기본적으로 앱을 생성하면 자동으로 생기는 파이썬 파일
app_name/models.py : Django가 DB에서 값을 읽어오는 것. 즉, 관계형 데이터베이스와의 연동을 구현합니다 (dbfield에 해당하는 클래스 추가)
+) DB를 테이블 단위로 읽어 하나의 테이블에 저장된 값을 코드에서 읽도록 도움 (ORM)
app_name/urls.py : urlpatterns 리스트에, path 통해 뷰들의 연결 추가
app_name/views.py : 앱의 뷰 추가
models.py를 통해 모델 생성이 끝났으면 테이블에 써주기 위한 migrations를 모델로부터 만들고, 실행해 테이블 만드는 작업 수행
단, migration 실행 전 setting으로 app등록이 필수!
장고에서 모델을 만들때 PK로 id라는 값이 필수로 등록됌 (default)
추가로, models.py에 FK를 생성한 경우에 한해, CREATE INDEX가 생김
테이블 제작하는 방법
: $ python manage.py migrate
< 실습을 통해 구현 >
# 🎈 Model
from django.db import models
# Create your models here.
# 모델 생성
# 모델을 테이블에 써주기 위해 migration 생성 (질문, 답변이 존재하는 테이블 생성)
class Question(models.Model):
question_text = models.CharField(max_length = 200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
# 외래키 생성으로 CREATE INDEXING
question = models.ForeignKey(Question, on_delete = models.CASCADE)
choice_text = models.CharField(max_length = 200)
votes = models.IntegerField(default = 0)
# (모델 -> 테이블로 변환하며 ID 컬럼 무조건 생성)
# migration 라는 새로운 폴더에 해당 모델들이 py로 저장됨.
$ python manage.py makemigrations polls
# migration으로 실행될 SQL 문장 살펴보기
$ python manage.py sqlmigrate polls 0001
# migration 실행하기 (테이블 만드는 작업)
$ python manage.py migrate
생성된 테이블은 app이름_모델이름 임을 알 수 있다.
추가로 장고의 다양한 모델 필드(Boolean, JSON, Text, Datetime등)를 활용하려면 아래 링크 참고
djangoproject.com
실행된 migration에 대해 테이블에서 확인하는 방법 ?
-> DB에 접속 필요
Django에서 기본으로 제공하는 SQLite 데이터베이스 파일 연결
->>> sqlite3 db.sqlite3마이그레이션을 0001버전으로 다시 롤백하기
->>>python manage.py migrate polls 0001관리자 계정 생성
admin 페이지? : 일반적으로 시스템을 관리하는 관리자들이 데이터 추가/수정하는 페이지
(모델)에서 만든 CRUD 작업 가능토록 함
$ python manage.py createsuperuser접속은 ? mysite/urls.py 에서 path에 admin 포함되었나 확인
polls/admin.py
장고 shell의 경우 자동 연동이 되지않아 exit()와 python manage.py shell을 자주 사용하며 웹 상의 변경 사항을 확인해야 한다.
# 장고환경에서 shell 실행하기
python manage.py shell
# models.py 파일에 정의된 모든 모델 가져오기
>>> from polls.models import *
# 모든 (웹사이트에 저장된) Question, Choice 오브젝트 가져오기
>>> Question.objects.all()
>>> Choice.objects.all()
# 첫번째 Choice 오브젝트의 id, 답변 내용, 건수 가져오기
>>> choice = Choice.objects.all()[0]
>>> choice.id
>>> choice.choice_text
>>> choice.votes
# 첫번째 Choice와 연결된 Question 가져오기
>>> choice.question
>>> choice.question.pub_date
>>> choice.question.id
# question.choice 는 에러 발생.
# (choice함수가 ForeignKey이기도 하고, question내 choice접근 X)
-> 해결방안
# 해당 Question과 연결되어 있는 모든 Choice 가져오기
>>> question.choice_set.all()
# VSCODE로 작성한 models.py에서 생성한 class 불러오기
from polls.models import *
# 새로운 Question 오브젝트를 생성하고 이를 'q1'이라는 변수에 저장
# 현재 q1은 admin에 포함 X, DB에 저장할 必
q1 = Question(question_text = "커피 vs 녹차")
# 장고는 웹사이트이므로 time개념이 상당히 중요!
# timezone을 활용하여 새로운 오브젝트 'q1'의 생성시각을 설정하기
from django.utils import timezone
q1.pub_date = timezone.now()
# 모델에서 pub_date (생성시간을 다음과 같이 바꾸면 자동적으로 시간 저장 가능)
변수명 = models.DateTimeField(auto_now_add = True)
# 새로운 Question 오브젝트 'q1'을 데이터베이스에 저장하기 (생성시각 저장 필수)
q1.save()
# question 생성
q3 = Question(question_text = "abc")
# create() 메서드를 활용하여 q3와 연결된 새로운 Choice 오브젝트를 생성 후, choice_text 필드에 값을 넣기
# 아래 코드 적용 시 바로 admin page에 적용
q3.choice_set.create(choice_text = "b")
# 새로운 Choice 오브젝트를 생성하고 question 필드에 q3 값을 넣어 연결하기
choice_c = Choice(choice_text='c', question=q3)
# 새로운 Choice 오브젝트를 데이터베이스에 저장하기
choice_c.save()
모델을 통해 테이블 내용 수정 및 삭제
# Question 오브젝트 중 가장 마지막으로 만들어진 것을 가져오기
q = Question.objects.last()
# 해당 오브젝트의 question_text에 새로운 내용을 더해 수정하기
# shell에 메모리 상에만 존재 -> DB save 필요
q.question_text = q.question_text + '???'
# admin에 결과 반영
q.save()
# Choice 오브젝트 중 가장 마지막으로 만들어진 것을 가져오기
choice = Question.objects.last()
# 해당 오브젝트에 연결된 Question을 통해서 choice set을 가져오기
choice.queston.choice_set.all()
# 해당 오브젝트를 삭제하기
choice.delete()
# get 메서드를 사용해 조건에 해당하는 오브젝트를 필터링
Question.objects.get(id = 1)
q = Question.objects.get(question_text__startswith = '질문 시작')
# 조건에 맞는 1개만 가져오므로 error발생
Question.objects.get(pub_date__year = 2023)
# filter 메서드를 사용해 조건에 해당하는 오브젝트 필터링하기
Question.objects.filter(pub_date__year==2023)
# 조건에 맞는 결과 출력
<QuerySet [<Question: 제목: 휴가를 어디서 보내고 싶으세요?, 날짜: 2023-02-05 18:52:59+00:00>, <Question: 제목: 가장 좋아하는 디저트는?, 날짜: 2023-02-05 18:53:27+00:00>, ...
# count함수로 개수 파악 가능
Question.objects.filter(pub_date__year=2023).count()
# 다음과 같은 예시 가능
q = Question.objects.all().first()
q.choice_set.all()
# 결과 (쿼리셋 결과를 보려면 명령어가 _set이어야 하고 여러개일때만 주어진다.)
<QuerySet [<Choice: a>, <Choice: b>]>
# 쿼리셋의 SQL 쿼리 살펴보기
Question.objects.filter(pub_date__year=2023).query
print(Question.objects.filter(pub_date__year=2023).query)
# 모든 쿼리셋 출력
SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date" FROM "polls_question" WHERE "polls_question"."pub_date" BETWEEN 2023-01-01 00:00:00 AND 2023-12-31 23:59:59.999999
Question.objects.get(question_text__startswith='휴가를').query
print(Question.objects.get(question_text__startswith='휴가를').query)
# 질문시작하는 쿼리 모두 출력
SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date" FROM "polls_question" WHERE "polls_question"."question_text" LIKE 휴가를% ESCAPE '\'
### shell 필터링
# startswith 연산자 활용하여 오브젝트 필터링
q = Question.objects.filter(question_text__startwith = '질문 시작')
# 날짜 __year, __month로 필터링
q2 = Question.objects.filter(pub_date__year = 2023)
# contains로 오브젝트 필터링
q3 = Question.objects.filter(question_text__contains='질문')
# gt는 grater than으로 뒤 숫자보다 큰 값들 필터링. 아래 두가지는 결과 동일
Choice.objects.filter(votes__gt = 0)
Choice.objects.all()
# 필터걸어서 값 제거도 가능!
Choice.objects.filter(vote = 0).delete()
# 해당 쿼리셋에 대한 SQL 쿼리 생성하기
Choice.objects.filter(votes__gt = 0).query
# 결과 출력
SELECT "polls_choice"."id", "polls_choice"."question_id", "polls_choice"."choice_text", "polls_choice"."votes" FROM "polls_choice" WHERE "polls_choice"."votes" > 0
# 정규표현식(Reqex)을 활용하여 조건에 해당하는 오브젝트들을 필터링하기
Question.objects.filter(question_text__regex=r'^휴가.*어디')
# 결과 출력
SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date", "polls_question"."owner_id" FROM "polls_question" WHERE "polls_question"."question_text" REGEXP ^휴가.*어디
# Question의 question_text 필드 값이 '휴가'로 시작하는 모든 Choice 오브젝트를 필터링하기
Choice.objects.filter(question__question_text__startswith='휴가')
# exclude() 메서드를 사용해 question_text 필드 값이 휴가로 시작하는 모든 Choice 오브젝트 제외하고 필터링
Choice.objects.exclude(question_text__startswith='휴가')
추가로 아래 자료 활용해 예제 알아보기
djangoproject.com
파이썬의 경우 time, datetime 라이브러리를 활용할 수 있고, django의 경우 django.utils 라이브러리에서 timezone, datetime을 활용할 수 있다.
예시로 살펴보면 다음과 같다.# 필요 라이브러리 호출 from datetime import datetime, timedelta # 현재 시간 now = datetime.now() # 일주일 후 after_week1 = now + timedelta(days=7) # 장고의 경우 다음과 같다. from django.utils import timezone import datetime # 최근 1일 recent_day = timezone.now() - datetime.timedelta(days=1)
금일 장고를 학습하는 시간을 가졌는데,... cmd, 환경설정해주는 과정부터 시작해 정말이지 끝이 안보였다. 처음 학습해보는 분야이기에 추가적인 학습이 정말 많이 필요하다고 생각이 들었다.
내일 중간 치고, 본격적으로 좀 진행해보고자 한다!