App 생성
앞에서 만든 mysite 프로젝트에서 기능을 추가하기 위해서는 앱을 생성해야한다. 게시판 기능을 담당할 앱을 생성하자. django-admin의 startapp 명령어로 app을 생성 할 수 있다.
django-admin startapp <APP-NAME>
- 명령을 실행하면 pybo 디렉토리가 생성된걸 확인할 수 있다.
- 하지만 /pybo 페이지를 요청했을 때는 404 에러가 발생한다. 오류의 내용은 config.urls에 매핑이 없다고 적혀 있다.
Hello Pybo
config/urls.py 파일을 다음과 같이 수정하자.
from django.contrib import admin
from django.urls import path
from pybo import views
urlpatterns = [
path('admin/', admin.site.urls),
path('pybo/', views.index),
]
- pybo/ URL이 요청되면 views.index를 호출하라는 매핑을 urlpatterns에 추가하였다.
- pybo 뒤에 슬래시(/)는 pybo라고 호출해도 pybo/로 변환된다. 이는 URL을 정규화하는 장고의 기능 때문이다. 특별한 경우가 아니라면 URL 매핑시 항상 끝에 슬래시를 붙여 주도록 하자.
이제 views.py에 index 함수를 추가해야한다.
from django.http import HttpResponse
def index(request):
return HttpResponse("안녕하세요 pybo에 오신것을 환영합니다.")
- HttpResponse는 요청에 대한 응답을 할 때 사용한다. 여기서는 문자열을 브라우저에 출력하기 위해 사용되었다.
- index 함수의 매개변수 request는 HTTP 요청 객체이다.
/pybo 페이지를 요청하니 아래와 같은 결과를 볼 수 있었다.
URL 분리
config/urls.py를 아래와 같이 수정하자.
from django.contrib import admin
from django.urls import path, include
# from pybo import views
urlpatterns = [
path('admin/', admin.site.urls),
path('pybo/', include('pybo.urls')),
]
그리고 pybo/urls.py 파일을 만들고 다음과 같이 작성하자. 그러면 /pybo로 오는 url은 여기서면 작성하면 된다.
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
Model
장고는 모델을 이용하여 데이터베이스를 처리한다. 보통 데이터베이스에 데이터를 저장하고 조회하기 위해서 SQL 쿼리문을 이용해야 하지만 장고의 모델을 사용하면 이런 SQL 쿼리문의 도움없이 데이터를 쉽게 처리할 수 있다.
- You have 18 ~: 18개의 적용되지 않은 migration이 있다는 문구가 보인다. admin, auth, contentypes, sessions 앱들과 관련된 내용이고 이것을 적용하려면 python manage.py migrate를 실행해한다고 나와 있다.
- admin, auth, contenttypes, sessions 앱들은 장고 프로젝트 생성시 기본적으로 설치되는 앱들이다.
- 설치된 앱들은 config/settings.py에서 확인할 수 있다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 'livereload',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# 'livereload.middleware.LiveReloadScript',
]
- 위에서 언급한 앱들 이외에 messages와 staticifiles 앱들도 추가로 보인다. 이 두 개의 앱은 데이터베이스와 상관없는 앱이라서 위의 경고문에 포함되지 않았다.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
- config/settings.py 파일에는 데이터베이스 정보도 정의되어 있다.
- 데이터 베이스 엔진은 django.db.backends.sqlite3
- 데이터 베이스 파일은 BASE_DIR 디렉토리 밑에 db.sqlite3 파일에 저장한다고 정의되어 있음(BASE_DIR은 프로젝트디렉토리)
- SQLite는 주로 소규모 개발에서 사용되는 가벼운 파일 기반의 데이터 베이스이다. 실제 운영에서는 좀 더 규모있는 DB를 사용하는 것이 일반적이다.
python manage.py migrate
- migrate를 수행하면 admin, auth, contentypes, sessions 앱들이 사용하는 테이블들이 생성된다.
- 어떤 테이블이 생성되는지 알 필요는 없다. 위의 앱들을 사용하더라도 테이블을 직접 건드릴 일은 없기 때문이다.
DB Browser for SQLite 를 다운 받아서 [데이터베이스 열기 > C:\projects\mysite\db.sqlite3 파일 선택] 해서 열면 GUI로 테이블을 확인할 수 있다.
모델 작성하기
1. projects/mysite/pybo/models.py
from django.db import models
# 모델 작성하기
# Question 모델 --subject(질문 제목)/ content(질문 내용)/ create_date(질문 작성 일시)
# Answer 모델 --question(질문)/ content(답변 내용)/ create_date(답변을 작성한 일시)
class Question(models.Model):
subject = models.CharField(max_length=200) # 최대 200자
content = models.TextField() # 글자수 제한없는 text field
create_date = models.DateTimeField() # 작성일시
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField()
2. 테이블 생성하기
/config/settings.py 에 'boiler_plate.apps.BoilerPlateConfig', 추가하기
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'boiler_plate.apps.BoilerPlateConfig',
]
- INSTALLED_APPS 에 추가한 'boiler_plate.apps.BoilerPlateConfig' 클래스는 boiler_plate/apps.py 파일에 있는 클래스이다. 이 파일은 pybo 앱 생성시 자동으로 만들어지는 파일로 따로 만들 필요가 없다. 이미 boiler_plate/apps.py 파일 안에 다음과 같은 클래스가 구현되어 있다.
boiler_plate/apps.py
from django.apps import AppConfig
class BoilerPlateConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'boiler_plate'
- 특별한 경우가 아니라면 ~Config 클래스를 수정할 일은 없다.
3. makemigrations
python manage.py makemigrations
- manage.py migrate 명령을 수행하면 정상적으로 수행되지않고 makemigrations를 먼저 수행하라고 나온다.
- makemigrations 명령은 모델을 생성하거나 모델에 변화가 있을 경우 실행해야 하는 명령
- makemigrations 을 수행하면 boiler_plate/migrations/0001_initial.py 라는 파이썬 파일이 자동으로 생성된다.
- makemigrations 명령을 수행하더라도 실제로 테이블이 생성되지는 않는다. makemigrations 명령은 장고가 테이블 작업을 수행하기 위한 작업 파일(예: 0001_initial.py)을 생성하는 명령어다.
- 실제 테이블 작업은 migrate 명령을 통해서만 가능하다.
4. sqlmigrate
python manage.py sqlmigrate boiler_plate 0001
- migrate 명령을 실행하기 전에 실제 어떤 쿼리문이 실행되는지 sqlmigrate 명령으로 확인해 볼 수 있다.
- "boiler_plate"는 앱 이름을 의미하고 "0001"은 생성된 작업파일(예: 0001_initial.py)의 일련번호를 의미한다.
5. migrate
python manage.py migrate
모델 사용하기
insert
~/baby-django$ python manage.py shell
Python 3.8.12 (default, Aug 30 2021, 16:42:10)
[GCC 10.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from boiler_plate.models import Question, Answer
>>> from django.utils import timezone
>>> q = Question(subject='승주의 생일은?', content='승주에 대해 알고 싶어요', create_date=timezone.now())
>>> q.save()
>>> q.id
1
- timezone.now(): 현재일시
Select
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
- 저장한 Question 모델의 데이터는 Question.objects 를 통해 조회할 수 있다. Question.objects.all() 은 모든 Question 데이터를 조회하는 함수이다.
- QuerySet 객체가 리턴되는데 위처럼 Qustion 객체를 포함하고 있다.
class Question(models.Model):
subject = models.CharField(max_length=200) # 최대 200자
content = models.TextField() # 글자수 제한없는 text field
create_date = models.DateTimeField() # 작성일시
def __str__(self):
return self.subject
>>> from boiler_plate.models import Question, Answer
>>> Question.objects.all()
<QuerySet [<Question: 승주의 생일은?>]>
- __str__ 메서드를 추가하면 id 값대신 제목을 표시할 수 있다.
- 셸을 재시작하고 다시 Question.objects.all() 를 수행하면 변경된 결과를 확인할 수 있다.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: 승주의 생일은?>]>
>>> Question.objects.get(id=1)
<Question: 승주의 생일은?>
>>> Question.objects.filter(subject__contains='승주')
<QuerySet [<Question: 승주의 생일은?>]>
- filter는 조건에 해당되는 데이터를 모두 리턴해 주기 때문에 다건을 의미하는 QuerySet이 리턴된다.
- id는 유일한 값이므로 filter 대신 get을 이용해 조회할 수도 있다.
- get으로 조회할 경우 QuerySet이 아닌 Question 모델 객체가 리턴되었다. 1건만 처리하고 id와 같은 유일한 값으로 조회할 경우에만 사용한다.
- subject__contains='승주' 의 의미는 "subject"에서 '승주'라는 문자열이 포함된 객체를 찾는다. 언더바(_)가 2개임에 주의하자.
Update
>>> q = Question.objects.get(id=1)
>>> q
<Question: 승주의 생일은?>
>>> q.subject = '승주가 좋아하는 음식은'
>>> q.save()
>>> q
<Question: 승주가 좋아하는 음식은>
Delete
>>> q.delete()
(1, {'boiler_plate.Question': 1})
>>> Question.objects.all()
<QuerySet []>
외래키
>>> q = Question.objects.get(id=2)
>>> q
<Question: 승주의 생일은?>
>>> a = Answer(question=q, content='1월1일입니다', create_date=timezone.now())
>>> a.save()
>>> a.id
1
>>> a.question
<Question: 승주의 생일은?>
>>> q.answer_set.all()
<QuerySet [<Answer: Answer object (1)>]>
- Answer객체인 a를 사용하여 답변에 연결된 질문도 조회할 수 있다.
- Question객체인 q에서 answer_set이라는 속성이 없지만 외래키로 연결되어 있기 때문에 answer_set으로 역방향 접근이 가능하다.
- 연결모델명_set 은 질문하나에 여러개의 답변이 가능하므로 가능하지만 답변하나에는 여러개의 질문이 있을 수 없으므로 question_set은 불가능하다. a.question만 가능하다.
References
'네트워크 보안 > 네트워크' 카테고리의 다른 글
TCP/IP Stack 개발 #1 Ethernet & ARP (0) | 2024.08.04 |
---|---|
[C/C++] epoll (0) | 2024.07.30 |
Scalable Network Programming (3) | 2024.03.18 |
[Python/ MQTT] MQTT – Pub/Sub 모델 구현 (2) | 2022.08.26 |
[Django] Jump to Django (02/admin) (0) | 2022.06.30 |