본문 바로가기
SK Shieldus Rookies 19th/인프라 활용을 위한 파이썬

[SK shieldus Rookies 19기][Django] - Django 1

by En_Geon 2024. 3. 21.

1. 앱 생성

 

1) pybo 앱 생성

  • django-admin startapp pybo 생성
  • tree .\pybo /f  생성된 파일 확인

 

pybo 생성

 

 

설치 후 앱 생성까지 다 끝나서 개발 서버로 들어가면 되지만 URL을 정의하지 않아서 오류가 난다.

 

오류 페이지

 

 

2) URL 맵핑

  • config\urls.py 파일에 path() 함수를 사용해서 URL과 요청을 처리할 함수 연결
  • from pybo import views
  • path('pybo/', views.index),

 

from django.contrib import admin
from django.urls import path
from pybo import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('pybo/', views.index),
]

 

pybo 아래에 있는 views 모듈 안에 index 함수를 불러오는 path를 추가하는 것이다.

 

위 코드를 저장하면 views.index 함수가 정의되지 않아서 오류가 발생한다.

 

File "C:\Users\crpark\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py",
line 90, in import_module    return _bootstrap._gcd_import(name[level:], package,level)
                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 995, in exec_module
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
File "c:\python\projects\mysite\config\urls.py", line 22, in <module> 
    path('pybo/', views.index)
                         ^^^^^^^^^^^
AttributeError: module 'pybo.views' has no attribute 'index'

 

  • 뷰 함수가 정의되지 않았기 때문에 오류가 발생

 

 

3) views 함수를 정의

  • pybo\views.py 파일에 index() 함수 추가
  • from django.http import HttpResponse

 

from django.http import HttpResponse

def index(request) :
    return HttpResponse("안녕하세요. PYBO에 온 것을 환영합니다.")

 

  • HttpResponse는 요청에 대한 응답을 만들 때 사용하는 클래스

 

 

 

4) 서버 실행

  • python manage.py runserver

 

서버 실행

 

 

5) 페이지 접속

  • http://localhost:8000/pybo로 접속

 

접속확인

 

 

(1) 명령 프롬프트에서 curl로 접속

 

C:\Users\crpark> curl http://localhost:8000/pybo/ -v
* Trying [::1]:8000...                                           ⇐ 개발 서버와 연결을 시도
* Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000
> GET /pybo/ HTTP/1.1                                     ⇐ 요청 시작
> Host: localhost:8000                                       ⇐ 요청 헤더 시작
> User-Agent: curl/8.4.0
> Accept: */*
>                                                                        ⇐ 요청 헤더 끝 (GET 방식인 경우 요청 본문은 생략)
< HTTP/1.1 200 OK                                          ⇐ 응답 시작
< Date: Fri, 08 Mar 2024 04:32:44 GMT           ⇐ 응답 헤더 시작
< Server: WSGIServer/0.2 CPython/3.12.2
< Content-Type: text/html; charset=utf-8
< X-Frame-Options: DENY
< Content-Length: 52
< X-Content-Type-Options: nosniff
< Referrer-Policy: same-origin
<                                                                         ⇐ 응답 헤더 끝
안녕하세요. PYBO에 온 것을 환영합니다.         ⇐ 응답 본문 ⇒ index 함수에서 HttpResponse 
* Connection #0 to host localhost left intact                       인스턴스 생성 시  입력한 문자열

 

curl로 접속하면 위와 같이 세부적으로 볼 수 있다.

 

 

2. URL 분리, 앱 별로 URL 맵핑을 관리

 

1) config\urls.py 수정

 

페이지를 100개를 만들었을 때, urls.py를 수정하지 않고 위 urls.py와 같은 방식으로 작성한다면 모든 페이지의 url를 다 적어 100 라인을 써야 하며 가독성이 떨어지기 때문에 관련된 앱 별로 관리할 수 있도록 수정을 한다.

 

  • 장고 urls 패키지에 있는 include 모듈 추가 
  • path('pybo/', include('pybo.urls'))로 수정

 

from django.contrib import admin
from django.urls import path, include
from pybo import views   

urlpatterns = [
    path('admin/', admin.site.urls),
    # path('pybo/', views.index),
    path('pybo/', include('pybo.urls'))  # 추가
]

 

pybo 패키지에 있는 urls 모듈을 참조해서 URL 맵핑을 처리한다.

pybo\urls.py 파일에 pybo/ 패턴의 요청을 처리할 URL 맵핑을 정의한 것이다.

 

 

2) pybo\urls.py 파일을 추가

 

from django.urls import path
from . import views         # 현재 패키지에서 views 모듈을 가져옴

urlpatterns = [
    path('', views.index),
]

 

 

http://localhost:8000/pybo/로 요청을 한다. 이때 웹 루트 아래에 있는 pybo를 해석하려고 할 때, 첫 번째로는 confing\urls.py에서 찾는다. 위 config\urls.py에서 수정한 패턴을 보면 pybo/를 찾는 것인데 include 함수를 통해 pybo\urls 내용을 가지고 오는 문장이기 때문에 pybo\urls.py를 추가한 것이다

 

pybo\urls.py의 path에서 보면 패턴이 ' '로 비어 있다. 비어 있다는 말은 http://localhost:8000/pybo/"   " 이곳 즉, pybo/ 다음에 아무것도 없다는 뜻으로 아무것도 없으면 views.index로 보내라는 것이다. 

 

만약 main, sub, page 이름의 페이지가 있다면 http://localhost:8000/pybo/main 이렇게 들어갈 것이다. 나머지도 main이 들어간 자리에 들어간다. 그래서 pybo/로 시작하고 그 밑에 무언가가 있다면 이 파일에 정의를 하면 된다.

 

 

3. config\settings.py  파일에서 설정 정보 확인

 

1) INSTALLED_APPS

기본 설치된 앱

 

  • admin : 관리자 기능 
  • auth  : 인증 
  • contenttypes : 요청 응답에 나오는 내용 바이너리, xml, text
  • sessions : 세션 관리
  • messages : 메시지 관리
  • staticfiles : 정적 관리 

 

 

2) DATABASES

장고 애플리케이션에서 사용하는 데이터베이스의 연결 정보

 

  • sqlite3

 

3) migrate

config\settings.py에 있는 설정 정보를 반영하는 것

 

  • migrate 명령어로 앱이 필요로 하는 테이블 생성

 

migrate

 

migrate를 하면 설정 정보에서 정의한 설정들의  테이블을 만들어 준다.

 

이 테이블들을 시각적으로 보기 위해서는 DB Browser for SQLite를 설치해야 한다.

 

 

4. DB Browser for SQLite 설치

 

 

DB Browser for SQLite

 

 

설치는 기본 설정으로 설치하면 되는데 바로가기를 만드는 것을 추천한다. 바로가기가 없으면 설치 위차까지 찾아 들어가 실행해야 한다.

 

실행 후 DB 열기

 

SQLite를 실행 장고 프로젝트 데이터베이스를 열어준다.

 

데이터베이스 실행

 

migrate으로 테이블을 만든 것을 시각적으로 볼 수 있다.

 

 

5. 모델 생성

데이터 정리하는 역할

 

from django.db import models

# 질문 모델 클래스를 정의
class Question(models.Model):
    # 질문 모델이 가지는 속성을 정의 
    subject = models.CharField(max_length=200)      # 글자 수 제한이 있는 데이터
    content = models.TextField()                    # 글자 수 제한이 없는 데이터
    create_date = models.DateTimeField()            # 날짜, 시간을 나타내는 데이터


# 답변 모델 클래스를 정의
class Answer(models.Model):
    # 답변 모델이 가지는 속성을 정의
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    content = models.TextField()
    create_date = models.DateTimeField()

 

Primary Key(PK)는 개별 데이터를 구분하기 위해 중복이 되지 않는 유일한 데이터를 말한다.

직원이 있다면 4번 직원, 학생이라면 학번, 대한민국 국민이라면 주민등록번호로 생각해면 쉽다.

 

Foreign Key(FK)는 PK와 다른 테이블에 존재하는데 PK에 종속적이고 참조하는 테이블의 PK와 연결되어 있다.

PK가 있는 테이블에서 데이터가 삭제되면 FK가 있는 테이블의 데이터는 의미가 없기 때문에 함께 삭제된다.

 

위 코드의 question은 질문이 없으면 답변도 없을 것이고, 질문이 삭제되면 같이 삭제가 되어야 하기 때문에 어느 질문의 답변인지 알려줘야 한다. 그래서 FK를 사용해서 Question에 종속되도록 작성한다.

 

 

6. pybo 앱 등록

config\settings.py에 pybo 등록

 

  • INSTALLED_APPS에 'pybo.apps.PyboConfig', 추가

 

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'pybo.apps.PyboConfig',				# 추가
]

 

 

INSTALLED_APPS에 등록해 주어야 장고가 pybo 앱을 인식하고 데이터베이스 관련 작업을 수행할 수 있다.

앱을 등록했으니 테이블을 만들어 주어야 한다.

 

1) migrate 명령으로 테이블 생성

 

migrate 오류

 

모델이 변경되지 않았거나 migration 파일이 준비되지 않아서 나오는 오류다. 

데이터베이스에 변화가 생기면 makemigrateion로 migrations 파일을 만들고 migrate을 해야 한다.

 

  • makemigrations은 장고가 테이블 작업을 수행하기 위한 파일을 생성
  • migrate는 실제 테이블을 생성

 

2) makemigrations 후 migrate 수행

 

makemigrations 후 migrate

 

 

  • 0001_initial.py를 적용한 내용을 보여준다.
  • 0001_initial은 Question, Answer 모델은 만든 것이다.
  • migratinos 파일은 pybo\migrations 위치에 있다.

 

시각적으로 확인

 

 

 

7. 데이터 생성, 저장, 조회, 삭제

 

1) 데이터 생성

장고 쉘을 통해 생성

 

  • 장고 실행에 필요한 환경들을 자동으로 설정해서 실행하는 쉘 (python shell과는 다름)

 

장고 쉘에서 생성

 

>>> from pybo.models import Question, Answer
>>> from django.utils import timezone
>>> q = Question(subject='pybo가 무엇인가요?', content='pybo에 대해서 알려 주세요', create_date=timezone.now())
>>> q.save()

 

위와 같이 입력하면 SQLite에서 확인할 수 있다.

 

SQLite 확인

 

 

제목, id 확인

 

  • id는 장고가 자동으로 넣어주는 필드

 

Question 인스턴스를 하나 더 생성 저장

 

>>> q = Question(subject='두 번째 질문입니다.', content='ID는 자동으로 생성되나요?', create_date=timezone.now())
>>> q.save()
>>> q.id

 

 

저장 확인

 

 

2) 데이터 조회

 

Question.objects.all()

 

빨간색 박스 안에 있는 숫자는 위에서 말했듯이 장고가 Question 모델 데이터에 자동으로 입력한 ID 값이다.

 

 

(1) 모델 데이터 조회 결과 출력 정보 변경

pybo\models.py

 

데이터를 조회하면 기본적으로 ID 출력되는 것을 봤다. ID를 출력하면 무슨 내용의 질문인지 알기 어렵다.

어떤 질문인지 일기 위해 제목이 출력되도록 변경을 한다.

 

from django.db import models

# 질문 모델 클래스를 정의
class Question(models.Model) :
    # 질문 모델이 가지는 속성을 정의 
    subject = models.CharField(max_length = 200)    #CharField - 글자 수 제한 
    content = models.TextField()                    # 글자 수 제한 없는 데이터
    create_date = models.DateTimeField()            # 날짜, 시간을 나타내는 데이터

    def __str__(self) :                             # 제목을 반환
        return self.subject

# 답변 모델 클래스를 정의
class Answer(models.Model) :
    # 답변 모델이 가지는 속성을 정의
    question = models.ForeignKey(Question, on_delete = models.CASCADE)  
    content = models.TextField()
    create_date = models.DateTimeField()

 

  • def __str__(self) : 정의

 

위 코드를 저장한 후 장고 쉘에 재 접속 후 데이터를 조회하면 제목으로 나오는 것을 확인할 수 있다.  

 

다시 조회

 

all()은 해당하는 객체 데이터에 전체 내용을 가져오는 것이다.

 

(2) 조건과 일치하는 모델 데이터 조회

filter, get 사용

 

조회

 

  • Question.objects.filter(id=1)
    • 조건에 해당하는 데이터를 모두 찾아서 QuerySet 형태로 리턴
  • rs = Question.objects.fillter(id=100)
    • 조건을 만족하는 결과가 없는 경우 빈 QuerySet을 리턴
  • Question.objects.get(id=1)
    • 조건에 해당하는 데이터 중 하나만 해당 객체 타입으로 리턴
  • rs = Question.objects.get(id=100)
    • 조건을 만족하는 결과가 없는 경우 오류 발생

 

(3) 일부 내용을 포함하는 데이터 조회

__contains

 

비교

 

  • __contains를 사용하지 않으면 일치하는 것을 조회
  • __contains를 사용하면 SQL의 LIKE 연산과 동일하게 동작

 

3) 모델 데이터 수정

 

조회 수정

 

  • 수정 대상 조회 (get, filter)
  • q.subject = 'What is pybo?'
    • 객체 필터의 데이터를 변경
  • save 함수를 이용해서 DB에 반영

 

4) 모델 데이터 삭제

 

삭제

 

  • delete 메서드를 호출하면 DB에도 즉시 반영 (save를 하지 않아도 됨)
  • save와 delete는 DB에 반영하는 함수

 

삭제

 

 

8. 연결된 데이터 처리

 

1) Answer 모델 데이터 생성

 

Answer 데이터

 

 

Answer 데이터

 

종속관계가 있으면 참조하는 대상을 만들어서 매개변수로 넣어주면 된다.

 

2) Answer에 연결된 Question 조회

 

조회

 

답변에는 그 답변에 대한 질문이 연결되어 있기 때문에 답변을 가져오면 연결된 질문도 가져올 수 있다.

 

3) Question에 연결된 Answer 조회

  • 연결되어 있는 모델명_set 형식으로 참조

 

조회

 

질문에 연결된 답변울 가져올 때는 all()을 사용한다.

질문과 답변은 1 : N의 관계이기 때문에 질문 하나에 여러 답변이 있을 수가 있기 때문이다. 

 

 

9. 장고 admin

 

1) 슈퍼 유저 생성

createsuperuser

 

admin 생성

 

2) admin 페이지 접속

 http://localhost:8000/admin/

 

로그인 페이지

 

 

접속 화면

 

 

3) Question, Answer 모델을 admin 페이지에 등록

장고 admin을 통해서 모델 관리 가능

 

(1) pybo\admin.py

 

from django.contrib import admin
from .models import Question

admin.site.register(Question)

 

위 파일에 코드를 저장 후 admin 페이지 리로드

 

Questions 추가

 

(2) Questions 조회

Questions 화면

 

(3) Add question

데이터 입력 후 저장

 

(4) 저장된 데이터 조회

조회

 

 

 

4) 관리자 페이지에 검색 기능 추가

pybo\admin.py에 추가

 

from django.contrib import admin
from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    search_fields = ['subject']

admin.site.register(Question, QuestionAdmin)

 

 

검색 기능

 

 

10. 사용자 화면 중 질문 목록 조회 기능 구현

pybo\views.py
question_list.html

 

 

1) Question 모델 데이터를 작성일자 역순으로 조회

pybo\viesw.py에 추가

 

from django.shortcuts import render
from .models import Question

def index(request):
    question_list = Question.objects.order_by('-create_date')
    context = { 'question_list' : question_list }
    
    return render(request, 'pybo/question_list.html', context)

 

여기서 html로 직접 구현한다면 코드가 너무 복잡해져 가독성이 떨어지게 된다.

데이터와 보여주는 형식을 분리시키면 가독성과 유지보수가 좋아진다.

 

2) 템플릿 생성

c:\python\projects\mysite\templates\pybo\question_list.html

 

{% if question_list %}
    <ul>
        {% for question in question_list %}
            <li><a href="/pybo/{{ question.id }}/">{{ question.subject }}</a></li>
        {% endfor %}
    </ul>
{% else %}
    <p>질문이 없습니다.</p>
{% endif %}

 

 

3) config\settings.py 파일에 템플릿 디렉터 추가

 

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [ BASE_DIR / 'templates' ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

 

  • DIRS에 BASE_DIR / 'templates' 추가

 

pybo 화면

 

기존에는 요청이 들어오면 view에서 그 문자열을 리턴했다. 

지금은 요정이 들어오면 view에서 Question 가지고 DB에 저장되어 있는 패지 해 온다.

 

이 패치해 온 데이터를 그냥 리턴할 수도 있지만 보기 좋게 만들려고 한다면 Template를 사용해야 한다.

가져온 데이터를 지정된 Template에 전달해 Template에서 형식에 맞게 정리해서 리턴한다.

 

Template 문법을 사용하려면 Template 디렉터리가 Settings에 등록을 해야 한다. 그다음 그 디렉터리 아래에 정리해 줄 HTML 파일을 만들어 줘야 한다.

 

이 HTML 파일은 그냥 HTML 파일이 아니고 HTML + 정리해 주는 문법이 결합되어 있는데 이것을 Template 언어라고 한다.

 

여기까지는 기본적인 흐름을 구현할 수 있을 정도로 공부했다고 할 수 있다.

댓글