Django tutorial과 stop-out 과제를 하다보니 어떤 타이밍에 어떤 모듈에서 실행하는 순서인지를 파악하는게
중요하다고 느껴져서 Django tutorial강의를 들으며 전반적인 순서를 정리해보고자 한다.
1. view function과 urls 추가
-
polls/views.py
def detail(request, question_id): return HttpResponse("You're looking at question %s." % question_id) def results(request, quetion_id): response = "You're looking at the results of question %s." return HttpResponse(response % quetion_id) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id)
-
polls/urls.py
from django.urls import path from polls import views urlpatterns = [ # path(아무것도 없는 문자열이 오면, views의 index가 실행 # view.index를 실행하려면 config의 urls.py에 패턴추가 path('', views.index, name='index'), """ 추가된 부분 """ path('<int:question_id>/', views.detail, name='detail'), path('<int:question_id>/results/', views.results, name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ]
-
config.url -> polls.url 순서
2. view가 뭔가 하게 만들기
- polls/views.py
from django.http import HttpResponse
from .models import Question
def index(request):
# DB에 있는 Question중, 가장 최근에 발행(pub_date)된 순서대로 최대 5개에 해당하는 # QuerySet을 latest_question_list변수에 할당
latest_question_list = Question.objects.order_by('-pub_date')[:5]
# latest_question_list의 각 Question의 question_text들을 ', '로 연결시킨
# 문자열을 output변수에 할당
output = ', '.join([q.question_text for q in latest_question_list])
# 만들어진 질문 제목들을 모은 문자열을 HttpResponse클래스의 생성자로 전달, 인스턴스를 리턴
return HttpResponse(output)
-
질문 추가
-
shell 켜서 입력
# create를 써서 만들었기 때문에 save()를 하지 않아도 됨. # 그냥 인스턴스를 만들었으면 메모리에만 존재하니까 save를 호출해야 되지만 # create는 DB에 들어가는거까지 한번에 됨. In [35]: Question.objects.create(question_text='가장 좋아하는 게임은?', pub_date ...: =timezone.now()) Out[35]: <Question: 가장 좋아하는 게임은?> In [36]: Question.objects.create(question_text='가장 좋아하는 걸스데이 멤버는?', ...: pub_date=timezone.now()) Out[36]: <Question: 가장 좋아하는 걸스데이 멤버는?>
3. Templates 디렉토리 만들기
- 아래 순서로 패키지(이해하기 쉽게 디렉토리) 생성
- polls -> templates(directory) -> index.html(file)
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>
<a href="/polls/{{ question.id }}">{{ question.question_text }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available</p>
{% endif %}
-
polls/views.py에서 index 함수 수정
def index(request): # DB에 있는 Question중, 가장 최근에 발행(pub_date)된 순서대로 최대 5개에 해당하는 # QuerySet을 latest_question_list변수에 할당 latest_question_list = Question.objects.order_by('-pub_date')[:5] context = { 'latest_question_list': latest_question_list, } return render(request, 'polls/index.html', context)
-
원래는 settings.py에 TEMPLATES_DIRS를 별도로 지정해야되는데 안해도 됨
-
루트 폴더를 기준으로 templates 폴더를 만든게 아니라
-
실제 동작하는 애플리케이션 패키지 안에 template 폴더를 만들었기 때문에
-
자동으로 templates 폴더까진 찾아줌. 그 이후엔 경로 설정을 해줘야 함
- ex ) ‘polls/index.html’
3-1. return render(request, ‘polls/index.html’, context)의 추상화 과정
def index(request):
# DB에 있는 Question중, 가장 최근에 발행(pub_date)된 순서대로 최대 5개에 해당하는 # QuerySet을 latest_question_list변수에 할당
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {
'latest_question_list': latest_question_list,
}
# Django의 TEMPLATES설정에 정의된 방법으로,
# 주어진 인자('polls/index.html')에 해당하는 템플릿 파일을 가지는 Template인스턴스를
# 생성, 리턴
template = loader.get_template('polls/index.html')
# Template인스턴스의 render()함수를 실행, 인수로 context와 request를 전달
# 결과로 렌더링 된 HTML문자열이 리턴됨
html = template.render(context, request)
# 결과 HTML문자열을 사용해 생성한 HttpResponse객체를 리턴
return HttpResponse(html)
# return render(request, 'polls/index.html', context)
- 축약하는걸 추상화라고 함
4. 404 에러 일으키기
- polls/views.py에 detail 함수 수정
# try-except구문 없이
# polls/detail.html에 해당하는 Question인스턴스를 전달해서
# HTML에서는 해당 Question의 question_text를 출력
def detail(request, question_id):
# question 변수에 Question 클래스 객체중 id가 question_id인 애
question = Question.objects.get(id=question_id)
# question 이라는 이름으로 위의 question을 전달
context = {
'question': question,
}
return render(request, 'polls/detail.html', context)
- polls/templates 안에 detail.html 파일 만들기
# HTML에서는 해당 Question의 question_text를 출력
## context에 있는 'question'으로 question 인스턴스를 전달했으니까
## 그 인스턴스의 question_text를 출력
-
polls/views.py에 detail 함수에 try-except구문 삽입.
def detail(request, question_id): try: question = Question.objects.get(id=question_id) except Question.DoesNotExist: raise Http404('Question does not exist') context = { 'question': question, } return render(request, 'polls/detail.html', context)
-
try-except구문 추상화
question = get_object_or_404(Question, id=question_id)
-
-
http://localhost:8000/polls/100/ 입력시 Page not found (404)로 바뀜.
-
config/settings.py에서 명령어 2개변경
# DEBUG가 True여야 어떤 부분이 잘못된건지 상세하게 알려줌
DEBUG = True -> False로 변경
ALLOWED_HOSTS = [
'localhost' <- 빈 리스트에서 'localhost' 추가
]
-
최종 완료시 아래 문자열이 출력되는 화면을 얻을수 있음
Not Found The requested URL /polls/100/ was not found on this server.
-
파이썬에서 동적으로 함수 콜을 하고 싶은 경우
## 파이썬에서 동적으로 함수콜을 하고 싶다 하면 이런 방식을 할수 있다. 기억할것.
def custom_get_object_or_404(model, **kwargs):
# 1번째 인자로 특정 Model Class를 받음
# 최소 1개 이상의 키워드인자를 받아서, 받은 인자들을 사용해 주어진
# Model Class의 get()메서드를 실행
# 존재하면 해당 인스턴스를 리턴
# 없으면 raise Http404를 실행 (메시지는 임의로 지정)
try:
return model.objects.get(**kwargs)
except model.DoesNotExist:
raise Http404()
- 매개변수에 **kwargs를 하게 되면 보다 많은 인자들이 사용 가능해지기 때문에 동적으로 작동시킬수 있음.
5. Template 시스템 사용하기
-
polls/templates/polls/detail.html
<h1>{{ question.question_text }}</h1> <ul> <!-- question이 갖고 있는 choice목록을 순회 --> {% for choice in question.choice_set.all %} <!-- choice가 갖고 있는 choice의 텍스트를 보여줌 --> <li>{{ choice.choice_text }}</li> {% endfor %} </ul>
6. Namespace
6-1. blog 애플리케이션 생성
$ python manage.py startapp blog
# 1. config.urls에서 blog.urls를 include, path는 'blog/'를 사용
# 2. blog app내에 urls모듈을 생성하고 이 view를 위 URL과 연결되도록 설정
# 3. localhost:8000/blog/에서 Blog index텍스트가 출력되는지 확인
- blog/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse('Blog index')
-
config/urls.py에 추가
path('blog/', include('blog.urls')),
-
blog 패키지(폴더)내에 urls.py 파일 생성
from django.urls import path from blog import views urlpatterns = [ path('', views.index, name='index') ]
6-2. common 애플리케이션 생성
$ python manage.py startapp common
-
common/views.py
from django.shortcuts import render def index(request): return render(request, 'common/index.html')
-
# 1. common app내에 templates/common/index.html파일 생성 # 2. 해당 파일에서 /blog/로의 링크 , /polls/로의 링크(a태그)를 두개 생성 # 3. INSTALLED_APPS에 common을 추가 # 4. config.urls에서 이 view를 바로 연결 (include를 사용하지 않음)
common 패키지 안에 templates 폴더 -> common 폴더 -> index.html 파일 순서로 생성
-
templates/common/index.html(/blog/로의 링크 , /polls/로의 링크(a태그)를 두개 생성)
<a href="/blog/">Blog index</a><br> <a href="/polls/">Polls index</a>
-
config/setting.py (3. INSTALLED_APPS에 common을 추가)
INSTALLED_APPS = [ 'polls.apps.PollsConfig', 'common.apps.CommonConfig', <- 추가 / 이걸 추가해야 templates폴더 파일이 동작함 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # pip install django_extensions 'django_extensions', ]
-
config/urls.py (4. config.urls에서 이 view를 바로 연결 (include를 사용하지 않음)
from django.contrib import admin from django.urls import path, include from common.views import index <- 추가 urlpatterns = [ path('admin/', admin.site.urls), # 경로(url 끝에 polls입력하면, polls 폴더의 urls.py를 include한다.) path('polls/', include('polls.urls')), path('blog/', include('blog.urls')), path('', index), <- 추가 ]
-
이렇게 하면 localhost:8000을 했을때 Blog index 혹은 Polls index로 갈수 있는 창이 생김
-
하지만 하드코딩 형태이기 때문에 url형태로 바꿔줄 필요가 있음.
<a href="/blog/">Blog index</a><br> -> <a href="{% url 'index' %}">Blog index</a><br> <a href="/polls/">Polls index</a> -> <a href="{% url 'index' %}">Polls index</a>
-
문제는 blog.url이나 polls.url이나 index 이름이 같아서 저렇게 연결하면 blog걸로만 인식이 됨.
- config.urls에서 blog path가 나중에 선언됐기 때문에 polls path를 덮어썼기 때문.
-
이런 문제를 해결하기 위해선 각 url에 app_name을 선언해줘야함
-
blog/urls.py and polls/urls.py
from django.urls import path from blog import views app_name = 'blog' <- 추가 urlpatterns = [ path('', views.index, name='index') ]
from django.contrib import admin from django.urls import path, include from common.views import index app_name = 'polls' <- 추가 urlpatterns = [ path('admin/', admin.site.urls), # 경로(url 끝에 polls입력하면, polls 폴더의 urls.py를 include한다.) path('polls/', include('polls.urls')), path('blog/', include('blog.urls')), path('', index), ]
-
이후 polls/templates/polls/index.html에서 app_name 수정
{% if latest_question_list %} <ul> {% for question in latest_question_list %} <li> <a href="{% url 'detail -> polls:detail' question_id=question.id %}">{{ question.question_text }}</a> </li> {% endfor %} </ul> {% else %} <p>No polls are available</p> {% endif %}
Comments