🌉 점프 투 장고 사이트를 참고하여 일정 단위의
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. ModelORM데이터베이스의 데이터를 생성, 조회, 수정, 삭제하기 위해 사용하는 질의문(문법)
- 전통적으로 데이터베이스를 사용하는 프로그램들은 데이터베이스의 데이터를 조회하거나 저장하기 위해 쿼리문을 사용해야 했다.
- 이 방식은 여전히 많이 사용되고 있는 방식이지만 몇 가지 단점이 있다.
- 개발자마다 다양한 쿼리문이 만들어지고, 또 잘못 작성된 쿼리는 시스템의 성능을 저하 시킬수 있기 때문이다.
- 그리고 데이터베이스를
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/