[Django] 튜토리얼(2/2)

문성호·2020년 9월 4일
  • 튜토리얼을 따라 간단한 설문조사 앱을 만든다.
  • 완성된 코드를 설명하면서 전체 흐름을 이해한다.

polls/urls.py

from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path('', views.index, name='index'),
    # ex: /polls/5/
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]
  • 메인 Project의 urls.py에서 polls/ 디렉토리로 분기해주면, polls/urls.py에서는 app 내부의 logic을 담당하는 함수들로 분기해준다.

  • 질문의 번호를 담당하는 index, 내용을 담당하는 detail, 결과를 담당하는 results, 선택 결과를 알려주는 vote 함수로 나뉜다.

  • 질문의 번호를 인자로 넘겨주기 위해서 int:question_id라고 넘겨주는데, question_id는 각 함수에, argument로 넘어간다.

Models.py

import datetime

from django.db import models
from django.utils import timezone

class Question(models.Model):
	question_text = models.CharField(max_lenght=200)
	pub_date = models.DateTimeField('date published')

	def __str__(self):
		return self.question_text

	def was_published_recently(self):
		return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

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
  • 튜토리얼의 설문조사 앱은 Question과 Choice로 이루어져있고, Question은 text, 날짜를 Field로 갖고 있다.
    Choice는 질문과 선택지, 각 선택지들의 선택 횟수를 Field로 갖고 있다.

  • django.db 패키지에서 models 모듈을 임포트하면, DB에 저장하기 위한 charField(문자), DateTimeField(시간), IntegerField(정수) Field 형식을 갖고 있다.

  • 이렇게 models.py에 저장한 내용은 migration을 거쳐
    DB에 저장된다.

  • models.py를 작성한 후 mysite의 DB에 아래와 같이 migrate 시키면
    python manage.py sqlmigrate polls 0001

BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
    "id" serial NOT NULL PRIMARY KEY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL,
    "question_id" integer NOT NULL
);
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

COMMIT;
  • 위와 같이 polls App의 Question, Choice들을 SQL 형식으로 변환시켜 저장했다는 것을 알 수 있다.

Polls/Views.py

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)

def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})
    
    
def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/results.html', {'question': question})
    
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))    
    
    
  • Views.py는 Polls App의 주요 로직을 담당한다.

  • index 함수는 request로부터 받은 Question_list를 생성날짜 순으로 ordering하여 latest_question_list에 넣은 다음 render()함수를 통해 웹페이지에 출력한다.

  • 물론 그냥 출력하는 것이 아니라, template을 통해 출력한다.
    polls/index.html을 통해 rendering해주는데, render()함수를 사용한다.

  • render함수는 latest_question_list를 Dictionary로 담아 argument로 보낸다. index.html을 Template으로 삼아, context를 웹페이지에 출력하게 만든다.

  • detail함수는 polls/5와 같이 특정 숫자를 인자로 함께 받으면, 해당 id의 question을 출력한다. Question의 객체를 get하는 함수인 Question.objects.get함수에 question_id를 argument로 넣어 question에 저장한다. 이 때 만약 그런 question이 존재하지 않으면, exception 예외처리를 통해 Question does not exist와 함께 404 error를 출력한다.
    존재한다면, polls/detail.html이라는 Template을 통해 질문을 출력한다.

  • results함수는 Question의 결과를 출력하는데, results.html이라는 Template을 통해 출력한다.

  • vote 함수는 설문조사 결과를 출력하는데, question_id를 통해 DB에서 질문을 받아, 그 질문과 함께 등록된 선택지들을 selected_choice에 저장한다.
    Exception을 통해 KeyError가 나면, 다시 detail.html로 돌아가게 만든다.
    그렇지 않으면, selected_choice함수의 votes 필드를 1 증가시켜서 투표수를 증가시킨후 save함수를 통해 저장한다.

Template들.

  • template이란 View를 통해 거친 내부 Logic의 결과값들을 사용자 친화적으로 웹페이지에 출력하는 것이다. CSS 효과를 넣은 HTML과 Javascript를 통해 Frontend를 구현한 것이 Template이다.

  • 위 코드에서 views.py에서 구현한 내부 logic을 render함수를 통해 index.html/detail.html 등으로 넘겨주면, index.html과 detail.html에서 그 인자를 넘겨받아 개발자 편리대로 출력한다.

  • 여기서는 Django Tutorial의 내부 Logic을 설명하는 것이 더 중요하기 때문에 html 문서의 설명에 대해서는 생략한다.
    https://docs.djangoproject.com/ko/3.0/intro/tutorial03/
    이 곳 Django Tutorial에 html 코드가 있음.

Admin 사이트

  • Django는 사용자가 DB관리, 인증, 여러 프레임워크 관리 등을 하는데 있어 편리한 기능을 제공하기 위해 Admin 사이트를 제공한다.\

  • python manage.py createsuperuser를 통해 아이디와 pw를 만들고, https://localhosts:포트번호/admin 사이트에 접속할 수 있다.

전체 흐름.

  • 사용자가 서버에 접근하면, 메인 사이트의 urls.py를 통해 각 App으로 분기하고, 각 App에서 각자 logic을 처리할 함수로 분기한다.

  • Django는 MVT 패턴을 기반으로 웹 어플리케이션 개발 프레임워크를 제공하는데, Models를 통해서 DB와 상호작용하며 관리하고, Views를 통해 Data를 가공하여, Front-end에 출력할 내부 Logic을 짜고, Template을 통해 Front-end를 출력한다.

profile
오늘을 모아 내일을

0개의 댓글