본문 바로가기
W | eb

Django MVC(MTV)

by 덞웖이 2024. 10. 7.

환경

- Ubuntu Server 22.04 
- VSCode Insider 
- Remote SSH Extension 
- Python 3.10 venv
- Django 5.1.1
- SQLite 3.37.2

준비

# env 생성, 활성화
mkdir devcourse_django && cd devcourse_django
python -m venv django_env
source django_env/bin/activate

### 프로젝트 폴더를 옮겼다면 
# vi django_env/bin/activate에서 virtual_env 경로를 바꿔줘야함 😫
# vi django_env/bin/pip 의 shebang 경로 (#!)도 바꿔준다

### python 명령 실행 시 커맨드라인 앞에 (venv_name) 붙었는지 확인 ###
# 장고, sqlite3 설치
pip install django
sudo apt install sqlite3
python -m django --version

# 프로젝트 init
django-admin startproject test_proj

# 프로젝트 트리 확인
sudo apt install tree
tree -d -L 3 ./

# dev server 실행
python manage.py runserver

# app 생성 : appname = polls
python manage.py startapp appname

# 관리자: url/admin 에서 관리 가능
python manage.py createsuperuser

tree 패키지로 프로젝트 구조 확인

실행

test_proj/urls.py

from django.contrib import admin
from django.urls import path, include

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

# polls에 urls.py 생성
from django.urls import path
from . import views

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

polls/views.py

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello polls") # localhost:8000/polls/
def some_url(request):
	return HttpResponse("hello someurl") # localhost:8000/polls/some_url

polls/models.py

# 모델 작성 부분인듯
from django.db import models
from django.utils import timezone
import datetime

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    # score = models.FloatField(default=0)
    # is_something = models.BooleanField(default=False)
    # data = models.JSONField(default=dict)
    
    # 모델 메소드 (어제 글)
    def is_recent(self):
    	return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    # 관리자 페이지에서 표시될 레코드 이름
    def __str__(self):
    	return f'{'NEW!' if self.is_recent() else ''} {self.question_text}'

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def __str__(self):
        return self.choice_text
    
# 'migration' 필요
# migration 준비: test_proj의 settings.py에 앱 등록

test_proj/settings.py

# added polls app for migration
INSTALLED_APPS = [
	'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

Migration

# Migration: Schema 생성으로 이해하면 될듯
# 해당 앱 아래에 migrations 폴더 생성됨
# 모델에 필드를 추가하면 다시 실행해야됨!
python manage.py makemigrations polls

# 체크: foreign 키에 인덱싱 됨
python manage.py sqlmigrate polls 0001

# Migrate (여기서 테이블 생성하는듯)
python manage.py migrate

# DB에서 확인 (sqlite 인터랙티브 세션)
sqlite3 db.sqlite3
# migrations rev 확인
.tables
# schema 확인
.schema polls_question

# 이전 schema로 (0001번) 다시 migrate 가능
# migrations 에서 0002 삭제하고 모델 코드 수정
python manage.py migrate polls 0001
# polls의 admin.py
from django.contrib import admin
from .models import *

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

# 관리자 페이지에 모델 등록 된 것 확인

Django Shell 에서 테스트 하기

### shell에서 하는 방법: 메모리에 올려놓고 하는 장점이 있는...듯?
python manage.py shell
# shell에서
from polls.models import *
choice = Choice.objects.all()[0]
choice.id
choice.choice_text
choice.question # foreign key

question = Question.objects.all()[0]
question.choice_set.all() # 조인같은 기능인듯

# 관리자 페이지에서 레코드 추가하는 것과 같은 효과
from django.utils import timezone
q = Question(question_text='are you well')
q.pub_date = timezone.now() # 모델에 auto_now_add 설정하면 필요 없다
q.save()

# 커스텀 메소드 체크
q.is_recent()

# foreign키의 레코드 바로 만들기
q.choice_set.create(choice_text='temp_text')
# 반대 방향도 가능: 이 경우 return 타입은 쿼리셋이 아니다 (count() 등 쓸 수 없음)
ch = Choice(choice_text='temp_choice', question=q)
ch.save()

## 레코드 지우기
ch.delete()
# foreign키 세트 전부 삭제도 가능
q.choice_set.delete()

## 쿼리
Question.objects.get(id=1)
Question.objects.get(question_text__startswith='vacat') # 특이한 syntax
Question.objects.get(pub_date__second=59)
# 결과가 여러개일때는
Question.objects.filter(pub_date__year=2024) # .count() 등 쿼리 셋 공통 메소드
# 포함 쿼리
Question.objects.filter(question_text__contains='vacation')
# 비교
Question.objects.filter(votes__gt=0) # 0보다 큰
# regex
Question.objects.filter(question_text__regex=r'^vacation .*location+')
# 제외
Question.objects.exclude(blabla__lookup='')
# chain도 가능하다
Question.objects.filter(blabla__lookup='').filter(blabla__lookup='')
# lookup을 체인하는 것도 가능하다
Choice.objects.filter(question__question_text__contains='ideal')
# query eval
print(Question.objects.filter(pub_date__year=2024).query)

## other query set manipulation
# 업데이트
Question.objects.filter(votes__gt=0).update(votes=10)

MISC

python manage.py shell
# datetime이 아니라 timezone사용해야 함!
from django.utils import timezone
timezone.now()

# for time operations
import datetime
datetime.timedelta(days=1, years=1...)

# django sqlite reference
# https://docs.djangoproject.com/en/5.1/ref/models/querysets

 

'W | eb' 카테고리의 다른 글

Django CRUD: API  (0) 2024.10.09
Django CRUD: Serialize  (0) 2024.10.08
Django CRUD: Admin  (1) 2024.10.08
Django Template  (0) 2024.10.08
HTML  (0) 2024.10.02