Skip to content

Latest commit

 

History

History
147 lines (130 loc) · 9.96 KB

20210428.md

File metadata and controls

147 lines (130 loc) · 9.96 KB

Django

인상 깊은 조언

  • 장고는 어렵지 않다. 이 객체나 모델을 어떻게 효율적으로 설계하는지가 더 중요하고 어려운 이슈이다.
  • 기능 리스트업을 말로 잘 정리해둘 것. 사람은 똑똑하지 않아서 까먹으니까 꼭 글로 써둘 것.
  • 페이지 html이나 views의 함수, models의 클래스 이름은 헷갈리지 않게 지어야 한다. 각 페이지의 기능에 대해 손으로 적고 시작하면 좋다.
  • 한 페이지에는 하나의 기능과 스타일만을 제공해야 한다. 보기 편하게 해줄 것.

Django로 CRUD 서비스 만들기

지난 시간 복습

  • models.py에서 class로 만든 모델을 이용하여 $ python manage.py makemigrations$ python manage.py migrate로 테이블을 생성해주었다.
    • migration 파일을 이용하여 version tracking 도 가능!
    • migrate까지 해주어야 migrations를 바탕으로 테이블이 수정이 된다.
  • 장고의 장점 중 하나인 admin page 작업을 해보았다.
    • $ python manage.py createsuperuser로 admin 계정 생성
    • admin.py에서 모델을 import 해주고 admin.site.register(모델이름) 하면 admin 페이지에 테이블이 연동된다.
    • 이후 데이터를 admin page에서 직접 추가했다.
  • admin 페이지에서 추가한 데이터를 views.py에서 가져와 템플릿에 던져주었다.
  • objects는 데이터를 가져오기 위해 만들어진 매니저이며 아래와 같은 함수를 제공하는데, 그럴 경우가 많지는 않지만 커스터마이즈도 가능하다.
    • models.objects.all(): 해당 모델의 모든 데이터를 가져온다.
    • models.objects.get(조건): 해당 모델에서 조건에 맞는 데이터 인스턴스 하나를 가져온다. 없거나 2개 이상이면 에러.
    • models.objects.filter(조건): 해당 모델에서 조건에 맞는 데이터를 모두 배열 안에 넣어 가져온다. 없거나 2개 이상이어도 에러가 나지 않지만 한개를 가져올 경우 first()로 배열에서 꺼내서 가져와야 한다.
  • 하나의 테이블을 쪼개서 연결시키는 ForeignKey를 통해 relational하게 테이블을 짜보았다.
  • model의 다양한 필드를 활용해보았다. 그 외에도 많으니 document에서 보면서 사용할 수 있어야.

학생조회 페이지 만들기

기본 세팅 및 테이블 준비

  • 디렉토리 만들고 진입, 가상환경 만들고 진입하여 장고 설치
  • $ django-admin startproject config .으로 현재 위치에 config 폴더 생성
  • $ python manage.py startapp {app title} 으로 앱 생성 후 settings.py에 등록
  • models.py에서 모델 생성하고 $ python manage.py makemigrations$ python manage.py migrate로 테이블 만들어주기
  • admin.py에서 만든 모델 from .models import {model name}로 import하고 admin.site.register(model name) 해서 연동해주기
  • $ python manage.py createsuperuser로 관리자계정 만들고 관리자 페이지에서 대분류(반?) 데이터 생성

ForeignKey 옵션

  • on_delete: 연결된 데이터가 지워졌을 때 어떻게 처리할지 지정한다. models.PROTECT는 데이터를 살려두고, models.CASCADE는 같이 삭제한다.
  • related_name: 연결된 다른 테이블에서 나를 조회할 때 사용할 이름

기타 데이터 관리를 위한 필드 추가

is_deleted = models.BooleanField(default=False)
# 지워진 것을 바로 삭제하지 않고 디스플레이만 안되게끔 하는 필드

import time
created_at = models.DateTimeField(default=time.time())
# 그냥 하면 SQL의 시간이 기록되기 때문에 파이썬이나 자바스크립트로의 변환이 번거롭다. 그래서 time.time()으로 유닉스타임을 default로 넣어준다.

default_created_at = models.DateTimeField(auto-created)
# SQL에서 쓰기 위한 default_created_at을 이렇게 따로 만들기도 한다.

updated_at =  models.DateTimeField(default=time.time())
  • 각 클래스마다 이렇게 is_deleted, created_at, updated_at 등을 넣어주기 귀찮으니까 아예 반복을 피하기 위해 상속을 사용하기도 한다. 가독성을 위해 각각 해줘야한다는 의견도 있다.

Create Read 기능 추가 로직

  • model.py에 create나 add 함수를 만들고, add 페이지에서 form을 통해 데이터를 등록하면 redirect로 데이터 생성 후 연결될 페이지를 리턴해준다.
  • migration 폴더에서 클래스를 확인해보면 우리가 만들지 않은 id라는 값도 추가되어있는데, 이게 바로 primary key이다. 나중엔 hashed string으로 커스텀해주기도 한다. user가 숫자를 유추해서 접근하면 안되니까.
  • class_detail 함수에서 pk값을 받아서 해당 class 페이지를 보여주게끔 한다.
  • get_object_or_404(ClassRoom, pk=class_pk): try except 에러처리를 이미 구현해둔 메서드이기 때문에 편리하다.
    • from django.shortcuts import get_object_or_404로 import해준다.
    • 첫 번째 인수로 모델(클래스 이름)을 받고, 두 번째 인수로 조건을 받는다.
    • 이를 target_class 변수에 할당하고 context에 넣어주면 된다.

add 템플릿과 redirect 만들어주기

  • class_detail html에서 학생 추가 링크를 넣어준다.
    • <a href="{% url 'add' classroom.pk %}">로 class의 pk를 물고 add 페이지로 넘어가게.
  • urls.py 에서 add라는 경로를 넣어주되 pk도 받을거니까 `path('add/int:class_pk', 'add.html', name="add")'로 넣어준다.
  • add html파일 작업
    • form 태그의 action은 submit하는 주소이므로 action="{% url 'add' classroom.pk %}" method="POST"를 꼭 해준다.
    • csrf 토큰을 받고(form 태그 바로 밑에 {% csrf_token %} 넣어주기), model에 정의된 모든 항목들을 입력할 수 있게끔 적절한 태그와 어트리뷰트를 넣어준다.
    • 서버로 데이터가 넘어가는 어트리뷰트에는 꼭 name을 포함하여, 서버가 해당 키로 받을 수 있게끔 할 것
<form method="POST" action="{% url 'add' classroom.pk %}">
{% csrf_token %}
  <input type="text" name="name" placeholder="이름" />
  <textarea name="introduction">소개글을 입력하세요.</textarea>
  <button type="submit">추가하기</button>
</form>
  • views.py에서 add 함수를 완성시켜준다. (데이터 반영은 하단에 별도 기재)
    • add 함수를 호출한 결과 학생들의 정보가 나열된 class_detail 페이지로 redirect 해야하는데, 이를 위해 아까 add.html에서 classroom.pk를 받았으니까 함수에서도 class_pk를 받아서 이를 redirect('class_detail', class_pk)로 리턴해준다.

render와 redirect 비교

  • 둘다 django.shortcuts로부터 import 해줘야한다.
  • render는 인수로 request, 렌더링할 html 파일, context(optional)을 받는다.
  • redirect는 인수로 urls.py에서 지정한 이름, 즉 경로 이름을 받는다. 이 때 경로가 <int:pk> 등으로 엔드포인트에서 다른 요소를 받으면 두 번째 인수로 해당하는 요소를 넘겨주어야 한다.
  • render을 하면 그 경로에서 html 파일만 던져주는 것이기 때문에 주소는 여전히 해당 경로이다. 화면상에서는 detail.html을 보여주지만 주소는 여전히 'add/'인 상황.
  • redirect를 써주면 서버응답도 302가 나온다. 즉 서버에서 미리 작성해둔 url로 데려가주는 것.

client 요청에서 온 data를 DB에 반영해주기

  • views.py에서 add 함수를 통해, client에서 온 요청과 데이터를 DB에 추가해주는 작업
  • 그냥 일반적인 화면 렌더링의 GET 요청인지, client에서 POST method로 온 요청인지에 구분하기 위해 if문을 추가해준다.
  • models.py에 정의된 클래스 안의 인스턴스 변수들을 템플릿에서 받는 form을 만들었을 것이다. form 안의 태그들에 각각의 어트리뷰트로 name을 지어줬을텐데, 그것을 키로 하여 딕셔너리 값 참조하듯 request.POST['key']로 하여 데이터를 받을 수 있다.
  • 이를 모델의 objects 매니저 객체에 create 메서드를 호출하며 인스턴스 변수에 할당해주면 DB에 반영된다.
  • 내가 만든 Student 모델에는 이름과 소개만 넣었기 때문에 템플릿에서도 그 두 개를 받는 태그를 넣었고, add 함수에서도 이 두개를 받는다.
def add(request, class_pk):
    class_object = get_object_or_404(ClassRoom, pk=class_pk)
    context = { 'classroom': class_object }
    if request.method == 'POST':
        name = request.POST['name']
        introduction = request.POST['introduction']
        Student.objects.create(
            name=name,
            introduction=introduction
        )
        return redirect('class_detail', class_pk)
    return render(request, 'add.html', context)
  • 아무 입력이 없을 때는 에러메시지를 띄워주기 위해 템플릿과 함수에 다음과 같이 작업해주었다.
<!-- form 태그 앞에 넣어준다-->
{% if error.state %}
<p>{{ error.msg }}</p>
{% endif %}
def add(request, class_pk):
    class_object = get_object_or_404(ClassRoom, pk=class_pk)
    context = {
	'classroom': class_object,
	'error': {
	    'state': False,
	    'msg': '',
	}
    }

    if request.method == 'POST':
        name = request.POST['name']
        introduction = request.POST['introduction']
	if name and introduction: 
	    Student.objects.create(
		 name=name,
		introduction=introduction
            )
            return redirect('class_detail', class_pk)
	context['error']['state'] = True
	context['error']['msg'] = '문항을 모두 입력해주세요'
    return render(request, 'add.html', context)
  • 이렇게 하면 요청에서 온 name이나 introduction이 중 하나라도 내용이 없을 경우 if문을 빠져나가 에러메시지를 템플릿에 보여준다. if조건을 충족하면 바로 return되기 때문에 에러메시지가 띄워지지 않는다.

느낀 점

  • 드디어 DB에 손을 대다니 내가 뭐라도 된 느낌이다.