1. 가상환경 생성 및 접속

python -m venv django-venv
source django-venv/bin/activate

# 비활성화
deactivate

2. Django 설치

pip install django

## 버전 확인
python -m django --version

3. Django 프로젝트 생성

django-admin startproject mysite

4. manage.py

  • Django 프로젝트를 터미널에서 조작할 수 있는 명령어 제공

생성한 프로젝트 서버에서 실행

cd mysite
python manage.py runserver

스크린샷 2023-11-01 오전 12 06 24


  • Django 프로젝트 default 페이지

스크린샷 2023-11-01 오전 12 07 37

5. App 생성

python manage.py startapp polls
  • polls 폴더 생성됨
    • admin.py
    • apps.py
    • models.py
    • tests.py
    • views.py

6. url 생성

  • polls/urls.py 수정
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

url 뒤에 아무것도 없을 때, views에 있는 index 를 보여줘라


  • mysite/urls.py 수정
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

import include 추가
urlpatterns에 path('polls/', include('polls.urls')), 추가

7. 첫 화면 생성

  • polls/views.py 수정
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world.")

Hellow, world. 출력

  • 127.0.0.1:8000/polls/ 접속

스크린샷 2023-11-01 오후 2 14 41

  • mysite/urls.py에 path를 추가하고, polls/views.py에서 해당하는 함수를 구현함으로써 페이지 추가 가능!

8. Model 만들기

  • DB에 저장된 값을 불러와서 보여주도록 함

  • polls/models.py
  • DB를 테이블 별로 읽어서 하나의 테이블에 저장되어 있는 값을 읽어들일 수 있도록 도와줌
  • ORM 기능!

  • class는 항상 models.Model을 상속받음

모델 생성 과정

  • 모델 생성
  • 모델을 테이블에 써주기 위한 마이그레이션 생성
  • 이 모델에 맞는 테이블 생성


  • ex) 설문 조사

models.py

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

9. 마이그레이션

app 등록

  • mystie/settings.py 수정
  • INSTALLED_APPS'polls.apps.PollsConfig 추가
# Application definition

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin', 
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

make migration

  • 처음 생성할 때, 모델 수정했을 때 실행!
python manage.py makemigrations polls

Migrations for ‘polls’:
polls/migrations/0001_initial.py
- Create model Question
- Create model Choice

마이그레이션 내용 살펴보기

python manage.py sqlmigrate polls 0001
BEGIN;           
--             
-- Create model Question          
--                
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);          
--            
-- Create model Choice            
--                   
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" bigint NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);              
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT; 
  • id 컬럼이 항상 자동으로 추가됨
  • index
    • 각 질문에 대한 choice 들을 자주 찾아보게 될 것
    • 인덱싱이 되어있지 않다면 DB는 테이블을 full scan해서 찾아야 함
    • ForeignKey에 대해서 항상 인덱싱을 하게 됨!

테이블 생성

python manage.py migrate

스크린샷 2023-11-01 오후 3 54 16

DB 접속

sqlite3 db.sqlite3

테이블 목록

.tables
  • django_migrations : 마이그레이션 실행 목록

테이블 구조 확인

.schema polls_question

CREATE TABLE IF NOT EXISTS “polls_question” (“id” integer NOT NULL PRIMARY KEY AUTOINCREMENT, “question_text” varchar(200) NOT NULL, “pub_date” datetime NOT NULL, “average_score” real NOT NULL, “is_something” bool NOT NULL);

마이그레이션 되돌리기

python manage.py migrate polls 0001

polls의 마이그레이션을 0001 상태로 되돌림

  • 이후 migration 0002 파일 삭제
  • polls/models.py 에서 제거할 field 삭제

10. Admin

CRUD

  • Create 생성
  • Read 읽기
  • Update 갱신
  • Delete 삭제

admin 계정 생성

python manage.py createsuperuser

Username (leave blank to use ‘bokyung’): admin
Email address:
Password:
Password (again):
Superuser created successfully.

admin 서버 접속

  • mysite/urls.py
urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

-> <127.0.0.1:8000/admin/> 접속

스크린샷 2023-11-01 오후 4 28 52

서버에서 사용자 추가

  • [Users] - [+add] - 정보 입력 후 [save]

11. Admin - 모델 CRUD

모델 등록

  • polls/admin.py 수정
from django.contrib import admin
from .models import *

admin.site.register(Question)
admin.site.register(Choice)

스크린샷 2023-11-01 오후 4 35 57

Polls 앱에 두 모델이 등록됨

데이터 추가

  • [+add] 를 눌러서 데이터를 추가할 수 있음

스크린샷 2023-11-01 오후 4 36 36

  • 자기 자신을 문자열로 정의할 때 어떻게 표현할 것인지 지정
    • polls/models.py에서 def __str__(self): 지정
class Question(models.Models):
    ...

    def __str__(self):
        return self.question_text

question_text를 그대로 표시하겠다

스크린샷 2023-11-01 오후 4 43 03


class Question(models.Models):
    ...

    def __str__(self):
        return f'제목: {self.question_text}, 날짜: {self.pub_date}'

텍스트 형식 지정

스크린샷 2023-11-01 오후 4 45 16

12. Django Shell

python manage.py shell
  • 데이터 불러오기
Quesion.objects.all()

<QuerySet [<Question: 제목: 휴가를 어디서 보내고 싶으세요?, 날짜: 2023-11-01 07:37:20+00:00>, <Question: 제목: 가장 좋아하는 디저트는?, 날짜: 2023-11-01 07:37:49+00:00>]>


  • django shell은 변경 사항이 바로 반영되지 않기 때문에, 수정될 경우 쉘을 껐다 다시 켜야 함


  • 모델을 변수에 저장해놓고 각 필드를 불러올 수 있음
from polls.models import *

choice = Choice.objects.all()[0]

choice
# <Choice: 바다>

choice.id
# 1

choice.choice_text
# '바다'

choice.vote
# 0

choice.question
# <Question: 제목: 휴가를 어디서 보내고 싶으세요?, 날짜: 2023-11-01 07:37:20+00:00>

choice.question.question_text
# '휴가를 어디서 보내고 싶으세요?'

choice.question.pub_date
# datetime.datetime(2023, 11, 1, 7, 37, 20, tzinfo=datetime.timezone.utc)

choice.question.id
# 1

question.choice_set.all()
# <QuerySet [<Choice: 바다>]>

13. datetime

  • django에서는 timezone 이용!
from datetime import datetime
from django.utils import timezone

datetime.now()   # python
# datetime.datetime(2023, 11, 1, 16, 15, 41, 588899

timezone.now()   # django
# datetime.datetime(2023, 11, 1, 16, 16, 53, 400371, tzinfo=datetime.timezone.utc)

14. shell에서 레코드 CRUD

생성

q1 = Question(question_text="커피 vs 녹차", pub_date=timezone.now())
q1.save()

레코드가 생성될 때 자동으로 시간 넣기

- 모델의 DateTimeField에서 `(auto_now_add=True)` 추가
  • polls/models.py
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'제목: {self.question_text}, 날짜: {self.pub_date}'

옵션 생성

q3 = Question(question_text="abc")
q3.save()
q3.choice_set.all()
# <QuerySet []>

## Question 모델에서 만드는 방법
q3.choice_set.create(choice_text="a")
q3.choice_set.create(choice_text="b")
q3.choice_set.all()
# <QuerySet [<Choice: a>, <Choice: b>]>

## 직접 Choice 모델로 추가하는 방법
choice_c = Choice(choice_text="c", question=q3)
choice_c.save()
q3.choice_set.all()
# <QuerySet [<Choice: a>, <Choice: b>, <Choice: c>]>

수정

q = Question.objects.last()
q.question_text
# 'abc'

q.question_text = q.question_text + '???'
q.save()
q.question_text
# 'abc???'

삭제

  • 삭제는 .save() 하지 않음!
    • 변수에 담아서 삭제한 경우 쉘 메모리에 값이 남아있기 때문에 save하면 다시 테이블에 들어감
choice = Choice.objects.last()
choice.choice_text  
# 'c'

q = choice.question
q.choice_set.all()
# <QuerySet [<Choice: a>, <Choice: b>, <Choice: c>]>

choice.delete()
# (1, {'polls.Choice': 1})

q.choice_set.all()
# <QuerySet [<Choice: a>, <Choice: b>]>

15. 모델 필터링

한 개만 가져오기 : get

# 같은 <Question: 제목: 휴가를 어디서 보내고 싶으세요?, 날짜: 2023-11-01 07:37:20+00:00> 값을
## id로 가져오기
Question.objects.get(id=1)

## 옵션으로 가져오기
Question.objects.get(question_text__startswith="휴가")
Question.objects.get(pub_date__second=20)

여러 개 가져오기 : filter

Question.objects.filter(pub_date__year=2023)
# <QuerySet [<Question: 제목: 휴가를 어디서 보내고 싶으세요?, 날짜: 2023-11-01 07:37:20+00:00>, <Question: 제목: 가장 좋아하는 디저트는?, 날짜: 2023-11-01 07:37:49+00:00>, <Question: 제목: 커피 vs 녹차, 날짜: 2023-11-01 16:21:27.196500+00:00>, <Question: 제목: abc???, 날짜: 2023-11-01 16:25:01.782268+00:00>]>

Question.objects.filter(pub_date__year=2023).count()
# 4

QuerySet SQL문

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

print(Question.objects.filter(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 '\'

q = Question.objects.get(pk=1)
print(q.choice_set.all().query)
# SELECT "polls_choice"."id", "polls_choice"."question_id", "polls_choice"."choice_text", "polls_choice"."votes" FROM "polls_choice" WHERE "polls_choice"."question_id" = 1
  • filter를 복잡하게 줄 경우 SQL문이 잘 실행되고 있는지 파악할 때 활용

16. 모델 메소드

  • polls/models.py 에서 모델 클래스 내에 함수 생성
  • ex) 데이터가 생성된지 하루가 지나지 않았는지 판단하는 함수 was_published_recently
from django.utils import timezone
import datetime

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField(auto_now_add=True)

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def __str__(self):
        if self.was_published_recently():
            new_badge = '[NEW]'
        else:
            new_badge = ''
        return f'{new_badge} 제목: {self.question_text}, 날짜: {self.pub_date}'
  • 하루가 지나지 않았으면 제목 앞에 [NEW]가 붙도록 __str__ 함수도 수정

스크린샷 2023-11-02 오전 3 28 35