🌉 점프 투 장고 사이트를 참고하여 일정 단위의
chapter
에 대해 실습 후새롭게 알게된 내용
, 혹은복습이 꼭 필요한 내용
에 대해 정리!!
2-01. URL과 View
장고 개발 흐름 정리하기
[1]
브라우저에서 로컬 서버로 http://localhost:8000/pybo
페이지를 요청
[2]
urls.py 파일에서 /pybo
URL 매핑을 확인하여 views.py
파일의 index
함수를 호출
[3]
호출한 결과를 브라우저에 반영
URL 분리
✨ pybo
앱에 관련한 것들은 pybo
앱 디렉터리 하위에 위치해야 함.
urls.py
파일은 앱이 아닌 프로젝트 성격의 파일이므로, 이곳에는 프로젝트 성격의 URL 매핑만 추가되어야 함.pybo
앱에서만 사용하는 URL 매핑을 pybo/urls.py
파일로 분리하여 관리할 것!📄 /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')), # ← 추가한 코드
]
path('pybo/', include('pybo.urls'))
pybo/
로 시작하는 페이지를 요청하면 이제 pybo/urls.py
파일의 매핑 정보를 읽어서 처리하라는 의미pybo/
로 시작하는 URL
(예시 : pybo/question/create, pybo/answer/create
)을 추가해야 할 때 config/urls.py
파일을 수정할 필요없이 pybo/urls.py
파일만 수정하면 됨.📄 /pybo/urls.py
from django.urls import path
from pybo.views import index
urlpatterns = [
path('', index),
]
/config/urls.py
파일에 설정했던 내용과 별반 차이가 없음.path('', index)
처럼 pybo/
가 생략된 ''
이 사용됨. config/urls.py
파일에서 이미 pybo/
로 시작하는 URL
이 pybo/urls.py
파일과 먼저 매핑되었기 때문.pybo/
URL은 다음처럼 config/urls.py
파일에 매핑된 pybo/
와 pybo/urls.py
파일에 매핑된 ''
이 더해져 pybo/
가 됨.2-02. Model
ORM
데이터베이스의 데이터를 생성, 조회, 수정, 삭제하기 위해 사용하는 질의문(문법)
- 전통적으로 데이터베이스를 사용하는 프로그램들은 데이터베이스의 데이터를 조회하거나 저장하기 위해 쿼리문을 사용해야 했다.
- 이 방식은 여전히 많이 사용되고 있는 방식이지만 몇 가지 단점이 있다.
- 개발자마다 다양한 쿼리문이 만들어지고, 또 잘못 작성된 쿼리는 시스템의 성능을 저하 시킬수 있기 때문이다.
- 그리고 데이터베이스를
MySQL
에서 오라클로 변경하면 프로그램에서 사용한 쿼리문을 모두 해당 데이터베이스의 규칙에 맞게 수정해야 하는 어려움도 생긴다.
ORM(Object Relational Mapping)
을 사용하면 데이터베이스의 테이블을 모델화하여 사용하기 때문에 위에서 열거한 SQL
방식의 단점이 모두 없어짐.ORM
을 사용하면 개발자별로 독특한 쿼리문이 만들어질 수가 없고 또 쿼리를 잘못 작성할 가능성도 낮아짐.CASCADE 옵션
Answer
모델은 질문에 대한 답변에 해당되므로 Question
모델을 속성으로 가져가야함.ForeignKey
를 사용해야 함.ForeignKey
는 다른 모델과 연결하기 위해 사용.이 답변(Answer
)과 연결된 질문(Question
)이 삭제될 경우 답변(Answer
)도 함께 삭제된다는 의미
질문 하나에는 무수히 많은 답변이 등록될 수 있음.
CASCADE 옵션
은 질문을 삭제하면 그에 달린 답변들도 모두 함께 삭제
장고에서 사용하는 속성(Field)의 타입은 이것 외에도 많음.
- 다음 URL에서 어떤것들이 있는지 참고할 것
https://docs.djangoproject.com/en/4.0/ref/models/fields/#field-types
sqlmigrate
📌 다음의 명령어를 Terminal
창에서 실행
python manage.py sqlmigrate '앱이름' 'makemigrations으로 생성된 파일 이름'
(mysite) c:\projects\mysite> python manage.py sqlmigrate pybo 0001
BEGIN;
--
-- Create model Question
--
CREATE TABLE "pybo_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "subject" varchar(200) NOT NULL, "content" text NOT NULL, "create_date" datetime NOT NULL);
--
-- Create model Answer
--
CREATE TABLE "pybo_answer" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "content" text NOT NULL, "create_date" datetime NOT NULL, "question_id" bigint NOT NULL REFERENCES "pybo_question" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "pybo_answer_question_id_e174c39f" ON "pybo_answer" ("question_id");
COMMIT;
(mysite) c:\projects\mysite>
python manage.py sqlmigrate pybo 0001
명령에서pybo
는 앱 이름을 의미하고0001
은 생성된 작업파일(예:0001_initial.py
)의 일련번호를 의미.SQL
문에 익숙한 독자라면 데이터베이스에 어떤 일들이 벌어질지 유추할 수 있을 것이지만, 여기에 출력되는SQL
문들이 무엇인지 몰라도 상관없음.- 장고는 이러한
SQL
대신Model
을 사용하기 때문
Django shell
장고 셸을 실행하여 모델을 사용하는 방법
장고 셸은 장고에 필요한 환경들이 자동으로 설정되어 실행됨.
📌 다음의 명령어를 Terminal
창에서 실행
python manage.py shell
>>> from pybo.models import Question, Answer
- Question 모델의 create_date 속성은 DateTimeField 타입이므로 timezone.now()로 현재일시를 대입.
>>> from django.utils import timezone
>>> q = Question(subject='pybo가 무엇인가요?', content='pybo에 대해서 알고 싶습니다.', create_date=timezone.now())
>>> q.save()
>>> q.id
1
>>> q = Question(subject='장고 모델 질문입니다.', content='id는 자동으로 생성되나요?', create_date=timezone.now())
>>> q.save()
>>> q.id
2
1
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>]>
저장한 Question 모델의 데이터는 Question.objects 를 통해서 조회할 수 있음.
- Question.objects.all()은 모든 Question 데이터를 조회하는 함수임.
- 결과값으로는 QuerySet 객체가 리턴되는데 위처럼 Question 객체를 포함하고 있음.
- Question object (1), Question object (2) 에서 1과 2는 Question 데이터의 id 값을 의미.
다음처럼 Question 모델에 str 메서드를 추가하면 id 값 대신 제목을 표시할 수 있음.
📄 /pybo/urls.py
(... 생략 ...)
class Question(models.Model):
subject = models.CharField(max_length=200)
content = models.TextField()
create_date = models.DateTimeField()
def __str__(self): # 추가한 코드
return self.subject # 추가한 코드
(... 생략 ...)
장고 셸을 종료하기 위해서는 장고 셸에서 Ctrl+Z 또는 quit()을 입력.
(mysite) c:\projects\mysite>python manage.py shell
>>> from pybo.models import Question, Answer
>>> Question.objects.all()
<QuerySet [<Question: pybo가 무엇인가요?>, <Question: 장고 모델 질문입니다.>]>
>>>
❗❗ 모델에 메서드가 추가될 경우에는 makemigrations와 migrate를 수행할 필요가 없음.
filter
와 get
- filter는 조건에 해당되는 데이터를 모두 리턴해 주기 때문에 다건을 의미하는 QuerySet이 리턴됨.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: pybo가 무엇인가요?>]>
- get으로 조회할 경우 QuerySet이 아닌 Question 모델 객체가 리턴됨.
- filter는 다건을 리턴하지만 get은 한 건만 리턴하기 때문.
- 하지만 get으로 조회시 조건에 맞는 데이터가 없으면 오류가 발생
- get은 반드시 1건의 데이터를 조회할 때 사용함.
- 보통 get은 id와 같은 유일한 값으로 조회할 경우에만 사용.
Code>
>>> Question.objects.get(id=1)
<Question: pybo가 무엇인가요?>
__contains
- subject__contains='장고'의 의미는 "subject에 '장고'라는 문자열이 포함되어 있는가?" 라고 해석할 수 있다. subject__contains 에서 언더바(_)가 1개가 아닌 2개임에 주의하자.
>>> Question.objects.filter(subject__contains='장고')
<QuerySet [<Question: 장고 모델 질문입니다.>]>
📌 데이터를 조회하는 filter의 사용법은 위에서 알아본 것 외에도 아주 많음.
- filter에 대한 자세한 사용법은 장고 공식 문서를 참조할 것.
- 장고 공식 문서는 장고 개발시 필수적으로 참조해야 하는 문서임.
>>> q = Question.objects.get(id=2)
>>> q
<Question: 장고 모델 질문입니다.>
>>> q.subject = 'Django Model Question'
>>>
- 다음처럼 save를 수행해 주어야 변경된 데이터가 반영된다는 점을 꼭 기억할 것!!
>>> q.save()
>>> q
<Question: Django Model Question>
>>> q = Question.objects.get(id=1)
>>> q.delete()
(1, {'pybo.Question': 1})
>>> Question.objects.all()
<QuerySet [<Question: Django Model Question>]>
>>> q = Question.objects.get(id=2)
>>> q
<Question: Django Model Question>
>>> from django.utils import timezone
>>> a = Answer(question=q, content='네 자동으로 생성됩니다.', create_date=timezone.now())
>>> a.save()
>>> a.id
1
>>> a = Answer.objects.get(id=1)
>>> a
<Answer: Answer object (1)>
>>> a.question
<Question: Django Model Question>
❗❗ Answer 모델 객체인 a를 통해서 질문을 찾는것은 Answer 모델에 question 속성이 연결되어 있기 때문에 매우 쉬움.
Yes
- q.answer_set을 사용하면 질문에 연결된 답변을 가져올 수 있음.
- Question 모델에는 answer_set 이라는 속성이 없지만 Answer 모델에 Question 모델이 ForignKey로 연결되어 있기 때문에 q.answer_set 과 같은 역방향 접근이 가능
>>> q.answer_set.all()
<QuerySet [<Answer: Answer object (1)>]>
연결모델명_set
방법연결모델명_set(예:answer_set)
은 상식적으로 생각하면 더 쉬움.
- 질문 하나에는 여러개의 답변이 가능하므로
q.answer_set
이 가능하지만 답변 하나에는 여러개의 질문이 있을 수 없으므로a.question_set
은 불가능.- 답변 하나에는 질문 하나만 가능하기 때문에
a.question
만 가능.
2-03. Django Admin
모델 관리
📄 /pybo/admin.py
from django.contrib import admin
from .models import Question # 추가한 코드
admin.site.register(Question) # 추가한 코드
모델 검색
- 다음처럼 pybo/admin.py 파일을 수정
- Question 모델에 세부 기능을 추가할 수 있는 QuestionAdmin 클래스를 생성
- 제목 검색을 위해 search_fields 속성에 'subject'를 추가
📄 /pybo/admin.py
from django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin): # 추가한 코드
search_fields = ['subject'] # 추가한 코드
admin.site.register(Question, QuestionAdmin) # 추가한 코드
- 2번째 방식은 김형종 강사님 수업 시간에 배운 방식
❗❗ 장고 관리자에는 이 외에도 무수히 많은 기능들이 있음.
- 자세한 내용은 다음 URL을 참고.
- https://docs.djangoproject.com/en/4.0/ref/contrib/admin/