Python + Django 설치
수행환경
- Windows 10 WSL 2(Ubuntu 20.04 LTS)
1.Python 설치
WSL에 접속하여 python을 설치합니다.
sudo apt install python
설치된 python version을 확인합니다.
$ python3 --version
Python 3.6.1
2. Django 설치
설치 전에 장고란 무엇인가 간단히 살펴보겠습니다.
Django(/dʒæŋɡoʊ/ jang-goh/쟁고/장고)는 파이썬으로 만들어진 무료 오픈소스 웹 애플리케이션 프레임워크(web application framework)입니다. 쉽고 빠르게 웹사이트를 개발할 수 있도록 돕는 구성요소로 이루어진 웹 프레임워크입니다.
웹사이트를 구축할 때, 비슷한 유형의 요소들이 항상 필요합니다. 회원가입, 로그인, 로그아웃과 같이 사용자 인증을 다루는 방법이나 웹사이트의 관리자 패널, 폼, 파일 업로드와 같은 것들이 있습니다.
그래서 많은 사람들이 바로 사용할 수 있는 구성요소들을 갖춘 여러 프레임워크를 만들습니다. 장고도 그 중 하나입니다.
비유를 하자면, 편지(request, 요청)가 도착했는지 확인해주는 메일박스(port, 포트)가 있고 이 것은 웹서버가 해주는 일입니다. 웹 서버는 받은 편지를 읽고 웹 페이지와 함께 답장을 준니다. 그런데 무언가를 주고 싶을 때는 그 안에 내용이 있어야 하는데, 장고는 그 특정 콘텐츠를 만들 수 있는 역할을 합니다.
아래 명령어로 장고를 설치합니다.
pip install django
Django 프로젝트
이번장에서는 Django 기본 프로젝트를 생성하고, 생성한 프로젝트로 서버를 실행한 후 브라우저를 통해 접속하는 과정을 알아보겠습니다. Django는 node.js의 express 모듈처럼 간단한 명령어로 기본 프로젝트를 생성할 수 있으며 관리자 기능까지 제공합니다.
manage.py는 사이트 관리를 도와주는 유틸리티입니다.
settings.py는 웹사이트 설정이 있는 파일입니다.
urls.py파일은 urlresolver가 사용하는 패턴 목록을 포함하고 있습니다.
가. Django 프로젝트 생성
프로젝트를 생성하기 위해 wsl에 접속하여 프로젝트를 생성할 디렉토리로 이동합니다. 본 문서에서는 /mnt/d/django 아래에 생성하겠습니다. /mnt/d/django 디렉토리에서 아래와 같이 명령어를 입력합니다.
mkdir /mnt/d/django
cd /mnt/d/django
django-admin startproject mysite
그러면 mysite라는 디렉토리가 하나 생성되고, 디렉토리 내부에는 manage.py 파일과 함께 프로젝트이름과 동일한 디렉토리가 하나 더 생성되어 있는것을 확인할 수 있습니다. 아래와 같은 디렉토리와 파일이 생성됩니다.
mysite
├───manage.py
└───mysite
settings.py
urls.py
wsgi.py
__init__.py
settings.py 파일을 열어 한국시간과 한글로 설정을 변경합니다. 기본은 UTC와 영어(en_us)로 되어 있습니다.
- timezone 설정 : TIME_ZONE = 'Asia/Seoul'
- 언어설정 : LANGUAGE_CODE = 'ko'
Database 설정 확인 : 기본적으로 sqlite DB를 사용하는데 DB명 등을 변경할 수 있습니다.
본 문서에서는 데이터베이스를 db.sqlite3 로 사용합니다.
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
나. 데이터베이스 생성
데이터베이스를 생성하기 위해서 콘솔 창에서 아래 코드를 실행합니다. 위에서 생성한 /mnt/d/django/mysite 디렉토리에서
python3 manage.py migrate 명령어를 실행합니다. 데이터베이스와 함께 테이블들을 생성합니다.
/mnt/d/django/mysite$ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
다. Django 웹서버 실행
이제 /mnt/d/django/mysite디렉토리에서 아래 명령어를 입력하여 웹서버를 실행합니다.
- python3 manage.py runserver
/mnt/d/django/mysite$ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
February 09, 2022 - 21:25:47
Django version 4.0.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
라. 브라우저로 접속 테스트
브라우저를 열고 주소창에 http://127.0.0.1:8000 을 입력합니다. 아래와 같은 화면이 보인다면 정상적으로 수행된 겁니다.
장고 모델
블로그를 위한 장고 모델을 만듭니다.
장고 안의 모델은 객체(object)의 특별한 종류입니다. 이 모델을 저장하면 그 내용이 데이터베이스에 저장되는 것이 특별한 점입니다. 데이터베이스란 데이터의 집합입니다. 이곳에 사용자정보나 블로그글 등이 저장되어 있습니다.
sqlite 데이터베이스는 기본 장고 데이터베이스 어댑터입니다.
데이터베이스 안의 모델이란 열(필드)와 행(데이터)로 구성되어 있습니다.
어플리케이션 만들기
프로젝트 내부에 별도의 애플리케이션을 생성합니다. 애플리케이션을 만들기 위해 콘솔 창(mysite 디렉토리에서 수행)에서 아래 명령어를 실행하세요.
/mnt/d/django/mysite$ python3 manage.py startapp blog
이제 blog디렉터리가 생성되고 그 안에 여러 파일도 같이 들어있는 것을 알 수 있어요. 현재 디렉리와 파일들은 다음과 같을 거예요. :
mysite
├── mysite
| __init__.py
| settings.py
| urls.py
| wsgi.py
├── manage.py
└── blog
├── migrations
| __init__.py
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── tests.py
└── views.py
애플리케이션을 생성한 후 장고에 등록합니다. 이 역할을 하는 파일이 mysite/settings.py입니다. 이 파일 안에서 INSTALLED_APPS를 열어 'blog'를 추가합니다. 아래와 다음과 같을 거예요. :
/mnt/d/django/mysite/mysite/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
]
블로그 글 모델 만들기
모델의 생성/변경을 적용하는 단계는 아래와 같습니다.
- models.py 추가 및 변경
- python3 manage.py makemigrations를 실행해 변경사항에 대한 마이그레이션 파일 생성
- python3 manage.py migrate를 실행해 변경사항을 데이터베이스에 적용
모든 Model 객체는 blog/models.py 파일에 선언하여 모델을 만듭니다. 이 파일에 블로그 글 모델도 정의합니다.
blog/models.py 파일을 열어서 안에 모든 내용을 삭제한 후 아래 코드를 추가합니다.
/mnt/d/django/mysite/blog/models.py
from django.db import models
from django.conf import settings
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
str양 옆에 언더스코어(_) 를 두 개를 써야 합니다. 파이썬에서 자주 사용되는데, "던더(dunder; 더블-언더스코어의 준말)"라고도 합니다.
class Post(models.Model):는 모델을 정의하는 코드입니다. (모델은 객체입니다.)
- class는 객체를 정의합니다.
- Post는 모델의 이름입니다. 클래스 이름의 첫 글자는 대문자로 써야 합니다.
- models은 Post가 장고 모델임을 의미합니다. 이 코드 때문에 장고는 Post가 데이터베이스에 저장되어야 한다고 알게 됩니다.
이제 속성을 정의합니다. title, text, created_date, published_date, author 속성을 정의하기 위해, 필드마다 어떤 종류의 데이터 타입을 가지는지를 정해야 합니다. 여기서 데이터 타입에는 텍스트, 숫자, 날짜, 사용자 같은 다른 객체 참조 등이 있습니다.
- models.CharField - 글자 수가 제한된 텍스트를 정의할 때 사용합니다. 글 제목같이 짧은 문자열 정보를 저장할 때 사용합니다.
- models.TextField - 글자 수에 제한이 없는 긴 텍스트를 위한 속성입니다.
- models.DateTimeField - 날짜와 시간을 의미합니다.
- models.ForeignKey - 다른 모델에 대한 링크를 의미합니다.
모델의 필드와 정의하는 방법에 대해서는 장고 공식 문서를 참고합니다. https://docs.djangoproject.com/en/2.0/ref/models/fields/#field-types)
def publish(self):는 publish라는 메서드(method) 입니다. def는 이것이 함수/메서드라는 뜻이고, publish는 메서드의 이름입니다. 메서드는 무언가를 되돌려 주기도 합니다. 예로 __str__ 메서드를 보면 __str__를 호출하면 Post 모델의 제목 텍스트(string)를 return 받게 됩니다.
데이터베이스에 모델을 위한 테이블 만들기
데이터베이스에 Post 모델을 추가합니다. 먼저 장고 모델에 변화가 생겼다는 걸 알려줍니다.
python manage.py makemigrations blog 를 입력해 봅니다.
/mnt/d/django/mysite$ python3 manage.py makemigrations blog
Migrations for 'blog':
blog/migrations/0001_initial.py:
- Create model Post
장고는 데이터베이스에 반영할 수 있도록 마이그레이션 파일(migration file)이 있습니다. 이제 python manage.py migrate blog 명령을 실행해, 실제 데이터베이스에 모델 추가를 반영합니다.
/mnt/d/django/mysite$ python3 manage.py migrate blog
Operations to perform:
Apply all migrations: blog
Running migrations:
Applying blog.0001_initial... OK
blog 모델이 데이터베이스에 저장되었습니다.
showmigration
현재 적용된 마이그레이션 파일을 보여줍니다.
$ python3 manage.py showmigrations
admin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
[X] 0003_logentry_add_action_flag_choices
auth
[X] 0001_initial
... ...
[X] 0012_alter_user_first_name_max_length
blog
[X] 0001_initial
contenttypes
[X] 0001_initial
[X] 0002_remove_content_type_name
sessions
[X] 0001_initial
sqlmigrate
생성된 migrations파일들이 어떤 sql 문장을 실행하는지 보여줍니다.
$ python3 manage.py sqlmigrate blog 0001
BEGIN;
--
-- Create model Post
--
CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(200) NOT NULL, "text" text NOT NULL, "created_date" datetime NOT NULL, "published_date" datetime NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id");
COMMIT;
장고 관리자
모델링한 글들을 장고 관리자에서 추가하거나 수정, 삭제할 수 있습니다.
blog/admin.py 파일을 열어서 내용을 다음과 같이 변경합니다.
/mnt/d/django/mysite/blog/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
앞에서 정의했던 Post모델을 import 합니다. 관리자 페이지에서 만든 모델을 보려면 admin.site.register(Post)로 모델을 등록해야 합니다.
웹 서버를 실행하려면 콘솔 창에서 python manage.py runserver를 실행합니다.
/mnt/d/django/mysite$ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
February 09, 2022 - 23:05:26
Django version 4.0.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
브라우저를 열고 주소창에 http://127.0.0.1:8000/admin/ 을 입력하면 아래와 같은 로그인 페이지를 볼 수 있습니다.
로그인하기 위해 모든 권한을 가지는 슈퍼 사용자(superuser)를 생성합니다. 커맨드라인으로 돌아가서 python manage.py createsuperuser 를 입력하고 엔터를 누릅니다.
메시지가 나타나면 사용자 이름 (소문자, 공백 없이), 이메일 주소 및 암호를 입력합니다.
/mnt/d/django/mysite$ python3 manage.py createsuperuser
사용자 이름 (leave blank to use 'ypjeong'): admin
이메일 주소: admin@admin.com
Password:
Password (again):
Superuser created successfully.
브라우저에서 장고 관리자 페이지에서 슈퍼 사용자로 로그인한 후 대시보드를 확인합니다.
[+추가] 버튼을 클릭하여 블로그 포스트를 등록합니다.
Author 항목의 "+" 버튼을 클릭하여 사용자를 추가합니다.
Title, Text, Published date 를 입력한 후 [저장] 버튼을 클릭합니다.
장고 관리자에 대해서 좀 더 알고 싶다면 장고 공식 문서를 참고합니다. https://docs.djangoproject.com/en/2.0/ref/contrib/admin/
장고 urls
URL이란?
URL(Uniform Resource Locators)은 웹 주소입니다. 웹 사이트를 방문할 때마다 브라우저의 주소창에 URL을 볼 수 있습니다. 127.0.0.1:8000이 바로 URL이고 https://djangogirls.org/도 URL입니다.
좀더 상세하게 예를 들어 "http://www.abcd.com:80/asd/df/sf.html" 이라는 사이트가 있다면,
- http:// : 프로토콜
- www.abcd.com :서버
- asd/df : 자원의 위치
- sf.html : 자원을 나타냅니다.
인터넷의 모든 페이지는 고유한 URL을 가지고 있습니다. 애플리케이션은 사용자가 URL을 입력하면 어떤 내용을 보여줘야 하는지 알고 있습니다. 장고는 URLconf (URL configuration)를 사용합니다. URLconf는 장고에서 URL과 일치하는 뷰를 찾기 위한 패턴들의 집합입니다.
장고 URL은 어떻게 작동할까요?
mysite/urls.py파일을 열어 보면 아래 내용이 보입니다.
/mnt/d/django/mysite/mysite/urls.py
"""mysite URL Configuration
[...]
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
세 개의 따옴표들(""", """) 사이에 있는 줄들은 독스트링(docstring)입니다. 독스트링은 파일 제일 첫 부분, 클래스 또는 메서드 윗 부분에 작성해, 이들이 어떤 일을 수행하는지 알려줍니다. comment로 생각하면 됩니다. 파이썬은 이 부분을 실행하지 않습니다.
관리자 URL이 등록되어 있습니다.
path('admin/', admin.site.urls),
장고는 admin/로 시작하는 모든 URL을 view와 대조해 찾아냅니다. 무수히 많은 URL이 admin URL에 포함될 수 있어 일일이 모두 쓸 수 없어 정규표현식을 사용합니다.
Django url 생성
URL을 생성합니다. 'http://127.0.0.1:8000/' 주소를 블로그 홈 페이지로 지정하고 여기에 글 목록을 보여주도록 합니다.
먼저 blog.urls를 가져오는 행을 추가합니다. blog.urls를 가져오려면 include 함수가 필요합니다. from django.urls 행을 찾아 import 뒤에 include 함수를 추가합니다.
mysite/urls.py 파일을 아래와 같이 작성합니다.
/mnt/d/django/mysite/mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
장고는 http://127.0.0.1:8000/ 로 들어오는 모든 접속 요청을 blog.urls로 전송해 추가 명령을 찾습니다.
blog.urls
blog/urls.py이라는 새 파일을 생성하고 아래 내용을 추가합니다.
/mnt/d/django/mysite/blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
]
장고 함수인 path와 blog 애플리케이션에서 사용할 모든 views를 가져옵니다. 그 다음, 첫 번째 URL 패턴을 추가합니다.
이제 post_list라는 view가 루트 URL에 할당되었습니다. 이 URL 패턴은 빈 문자열에 매칭이 되며, 장고 URL 확인자(resolver)는 전체 URL 경로에서 접두어(prefix)에 포함되는 도메인 이름(i.e. http://127.0.0.1:8000/)을 제외하고 받아들입니다. 이 패턴은 장고에게 누군가 웹사이트에 'http://127.0.0.1:8000/' 주소로 들어왔을 때 views.post_list를 보여주라고 말해줍니다.
마지막 부분인 name='post_list'는 URL에 이름을 붙인 것으로 뷰를 식별합니다. 뷰의 이름과 같을 수도 다를 수도 있습니다.
http://127.0.0.1:8000/ 접속하면 '웹 페이지를 사용할 수 없음(web page not available)'이라는 메시지가 표시됩니다.
서버 콘솔 창을 보면 아래와 같은 에러가 발생한 것을 볼 수 있습니다.
path('', views.post_list, name='post_list'),
AttributeError: module 'blog.views' has no attribute 'post_list'
no attribute 'post_list' 라는 메시지가 보이는데 이 메시지는 장고가 사용하고자 하는 뷰가 아직 없다는 메시지입니다.
장고 뷰 만들기
뷰(view) 는 애플리케이션의 "로직"을 넣는 곳입니다. 뷰는 이전 장에서 만들었던 모델에서 필요한 정보를 받아와서 템플릿에 전달하는 역할을 합니다. 뷰는 파이썬 함수입니다.
뷰는 views.py 파일 안에 있습니다. views를 blog/views.py 파일 안에 아래와 같이 추가합니다.
/mnt/d/django/mysite/blog/views.py
from django.shortcuts import render
# Create your views here.
def post_list(request):
return render(request, 'blog/post_list.html', {})
post_list라는 함수(def)를 만들었습니다. 이 함수는 요청(request)을 넘겨받아 render 메서드를 호출합니다. 이 함수는 render 메서드를 호출하여 받은 blog/post_list.html 템플릿을 보여줍니다.
파일을 저장하고, http://127.0.0.1:8000/ 로 접속해 확인해 봅니다.
TemplateDoesNotExist 에러가 발생하는 것을 확인할 수 있습니다. 장고 템플릿 양식은 HTML을 사용하는데 템플릿 파일이 존재하지 않아 발생하는 오류입니다.
장고 URL 설정에 대해 더 알고 싶다면 장고 공식 문서를 읽어보세요. : https://docs.djangoproject.com/en/2.0/topics/http/urls/
템플릿 생성
템플릿은 blog/templates/blog 디렉토리에 저장됩니다. blog디렉터리 안에 하위 디렉터리인 templates을 생성하고 template 디렉토리 하위에 blog 디렉토리를 생성합니다.
blog
└───templates
└───blog
(왜 똑같은 blog디렉토리를 하나 더 만들어야하는지는 나중에 폴더 구조가 복잡해 질 때 좀더 쉽게 찾기 위해 사용하는 관습적인 방법입니다)
blog/templates/blog디렉토리 안에 post_list.html 이라는 새 파일을 만듭니다.
웹 서버를 다시 시작한 후 웹 사이트를 확인해 봅니다. 오류 메시지없이 빈 화면이 표시됩니다.
커맨드라인에서 Ctrl + C를 눌러 웹 서버를 중단한 후 python manage.py runserver명령을 실행해 서버를 재시작합니다.
post_list.html템플릿 파일에 아래 내용을 입력합니다.
blog/templates/blog/post_list.html
<html>
<head>
<title>Django mysite blog</title>
</head>
<body>
<div>
<h1><a href="">Django mysite Blog</a></h1>
</div>
<div>
<p>published: 14.06.2014, 12:14</p>
<h2><a href="">My first post</a></h2>
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
</div>
<div>
<p>published: 14.06.2014, 12:14</p>
<h2><a href="">My second post</a></h2>
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut f.</p>
</div>
</body>
</html>
이제 웹 사이트가 아래와 같이 보여집니다. http://127.0.0.1:8000/
장고 ORM과 쿼리셋(QuerySets)
장고를 데이터베이스에 연결, 데이터를 저장하는 방법에 대해서 알아봅니다.
ORM이란
Object-Relational Mapping의 약자로 객체(Object)와 관계형 데이터베이스(Relational Database)의 데이터를 매핑(Mapping)해주는 것을 의미합니다. 객체 간의 관계를 바탕으로 SQL을 자동 생성하여 sql쿼리문 없이도 데이터베이스의 데이터를 다룰 수 있게 해줍니다.
데이터베이스의 테이블을 객체지향 프로그래밍에서 사용하는 객체(Class)처럼 사용할 수 있도록 해주는 기술입니다.
<예시>
book 이라는 객체에서 저자의 이름이 kim 인 책 목록을 가져오고 싶을 때,
SQL 쿼리문을 사용할 경우, sql 쿼리문을 작성하고 데이터를 가져오는 일련의 과정들을 코드에 적어야 합니다.
book_list = new list();
sql = "SELECT book FROM library WHERE author = 'kim'";
data = query(sql);
while (row = data.next()){
book = new Book();
book.setAuthor(row.get('author'));
book_list.add(book);
}
ORM을 사용할 경우, 간단하게 한 줄로 원하는 객체를 가져올 수 있습니다.
book_list = BookTable.query(author="kim")
쿼리셋이란 ?
쿼리셋(QuerySet)은 전달받은 모델의 객체 목록입니다(Django ORM에서 발생한 자료형). 쿼리셋은 데이터베이스로부터 데이터를 읽고, 필터를 걸거나 정렬을 할 수 있습니다. 리스트와 구조는 같지만 파이썬 기본 자료구조가 아니기 때문에 파이썬에서 읽고 쓰기 위해 자료형 변환(Casting)을 해줘야 합니다.
장고 쉘(shell)
로컬 콘솔에서 아래 명령을 입력합니다.
/mnt/d/django/mysite$ python3 manage.py shell
Python 3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
장고 인터랙티브 콘솔(interactive console)로 들어왔습니다. 파이썬 프롬프트와 비슷하지만, 장고의 명령어를 수행할 수 있습니다. 물론 파이썬의 모든 명령어를 여기서 사용할 수 있습니다.
모든 객체 조회하기
아래 명령어로 입력했던 글들을 출력합니다.
>>> from blog.models import Post
>>> Post.objects.all()
<QuerySet [<Post: 첫번째 블로그입니다.>]>
장고 관리자 인터페이스로 생성했던 글 목록이 출력됩니다.
객체 생성하기
데이터베이스에 새 글 객체를 저장하는 방법에 대해 알아봅시다. 먼저 User 모델과 Post 모델을 import 합니다.
사용자이름(username)이 '홍길동'인 User 인스턴스를 가져옵니다.
>>> from blog.models import Post
>>> from django.contrib.auth.models import User
>>> auth = User.objects.get(username='홍길동')
>>> Post.objects.create(author=auth, title='second title', text='두번째 블로그입니다.')
<Post: second title>
다시 입력했던 모든 글들을 출력해 봅니다.
>>> Post.objects.all()
<QuerySet [<Post: 첫번째 블로그입니다.>, <Post: second title>]>
글 더 추가하기
몇 개 글을 더 추가해서 잘 작동하는지 확인합니다.
필터링하기
쿼리셋의 중요한 기능은 데이터를 필터링입니다. 예를 들어, '홍길동'이라는 사용자가 작성한 모든 글을 찾고 싶다고 가정합니다. 이런 경우 Post.objects.all()에서 all대신, filter를 사용합니다. 쿼리셋 안에 있는 괄호 안에 원하는 조건을 넣어줍니다.
작성자(author)가 auth 인 조건을 입력합니다.
>>> Post.objects.filter(author=auth)
<QuerySet [<Post: 첫번째 블로그입니다.>, <Post: second title>]>
모든 글들 중, 제목(title)에 '블로그'이라는 글자가 들어간 글들만을 뽑아냅니다.
>>> Post.objects.filter(title__contains='블로그')
<QuerySet [<Post: 첫번째 블로그입니다.>]>
title와 contains 사이에 있는 밑줄(_)이 2개(__)입니다. 장고 ORM은 필드 이름("title")과 연산자 필터("contains")를 밑줄 2개를 사용해 구분합니다. 밑줄 1개만 입력한다면, FieldError: Cannot resolve keyword title_contains라는 오류가 발생합니다.
게시글 목록을 볼 수 있어요. 게시일(published_date)로 과거에 작성한 글을 필터링하면 목록을 불러올 수 있어요.
command-line
>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: 첫번째 블로그입니다.>]>
정렬하기
퀘리셋은 객체 목록을 정렬할 수 있습니다. 이제 created_date필드를 정렬해 봅니다.
>>> Post.objects.order_by('created_date')
<QuerySet [<Post: 첫번째 블로그입니다.>, <Post: second title>]>
-을 맨 앞에 붙여주면 내림차순으로 정렬합니다.
>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: second title>, <Post: 첫번째 블로그입니다.>]>
쿼리셋 연결하기
쿼리셋들을 함께 연결(chaining)할 수 있습니다.
>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
이 방법은 복잡한 쿼리도 작성할 수 있게 해줍니다.
다음 명령어로 장고 쉘을 종료합니다.
>>> exit()
$
템플릿 동적 데이터
블로그 글은 각각 다른 장소에 나눠져 있습니다. Post모델은 models.py파일에, post_list모델은 views.py파일에 있습니다.
템플릿 동적 데이터에서는 콘텐츠(데이터베이스 안에 저장되어 있는 모델)를 가져와 템플릿에 넣는것을 수행해 봅니다.
뷰(view)는 모델과 템플릿을 연결하는 역할을 합니다. post_list를 뷰에서 보여주고 이를 템플릿에 전달하기 위해서는, 모델을 가져와야 합니다. 뷰가 템플릿에서 모델을 선택하도록 만들어야 합니다.
blog/views.py파일을 열어봅니다.
/mnt/d/django/mysite/blog/views.py
from django.shortcuts import render
def post_list(request):
return render(request, 'blog/post_list.html', {})
models.py 파일에 정의된 모델을 가져기 위해 from .models import Post을 추가합니다.
from 다음에 있는 마침표(.)는 현재 디렉토리 또는 애플리케이션을 의미합니다. 동일한 디렉터리 내 views.py, models.py파일이 있기 때문에 . 파일명 (.py확장자를 붙이지 않아도)으로 내용을 가져올 수 있습니다.
Post모델에서 블로그 글을 가져오기 위해서는 쿼리셋(QuerySet)을 추가하고, 글 목록을 게시일 published_date기준으로 정렬하기 위해 from django.utils import timezone 을 추가합니다.
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {})
render함수에는 매개변수 request(사용자가 요청하는 모든 것)와 'blog/post_list.html' 템플릿이 있습니다. {} 이곳에 템플릿을 사용하기 위해 매개변수를 추가합니다. 이 매개변수를 'posts' 라고 정의합니다. {'posts': posts} 이렇게 작성합니다.
: 이전에 문자열이 와야하고, 작은 따옴표''를 양쪽에 붙입니다.
이제 blog/views.py코드는 아래 코드처럼 작성되어야 합니다.
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
템플릿 파일로 돌아가 쿼리셋을 보이게 만들어 봅시다.
쿼리셋에 대해 더 알고 싶다면 장고 공식 문서를 읽어보세요. : https://docs.djangoproject.com/en/2.0/ref/models/querysets/
장고 템플릿
데이터를 보여주기 위해 장고는 내장된 템플릿 태그(template tags) 라는 기능을 제공합니다.
템플릿 태그는 무엇인가요?
브라우져는 파이썬 코드를 이해할 수 없기 때문에 HTML에 파이썬 코드를 바로 넣을 수 없습니다. HTML는 정적이지만, 파이썬은 동적입니다.
템플릿 태그는 파이썬을 HTML로 바꿔주어 동적인 웹 사이트를 만들 수 있게 합니다.
post 목록 템플릿 보여주기
위 글에서 블로그 목록이 들어있는 posts 변수를 템플릿에 넘겨주었습니다. 이제 넘겨진 posts변수를 받아 HTML에 나타나도록 해봅니다.
장고 템플릿 안에 있는 값을 출력하려면, 변수 이름 안에 {{ posts }} 처럼 중괄호를 넣어 표시합니다.
여러 목록을 보여주기 위해 for loop을 이용합니다. 장고 템플릿에서는 아래와 같이 기술합니다.
blog/templates/blog/post_list.html
{% for post in posts %}
{{ post }}
{% endfor %}
HTML과 템플릿 태그를 함께 사용하여 아래와 같이 post_list.html 파일을 수정합니다.
/mnt/d/django/mysite/blog/templates/blog/post_list.html
<html>
<head>
<title>Django mysite blog</title>
</head>
<body>
<div>
<h1><a href="">Django mysite Blog</a></h1>
</div>
{% for post in posts %}
<div>
<p>published: {{ post.published_date }}</p>
<h1><a href="">{{ post.title }}</a></h1>
<p>{{ p.text|linebreaksbr }}</p>
</div>
{% endfor %}
</body>
</html>
{% for %} 와 {% endfor %}사이에 넣은 모든 것은 목록의 모든 객체를 반복하게 됩니다. 페이지를 새로고침하면 아래 화면이 브라우저에 보여집니다.
{{ post.title }}라던가 {{ post.text }}같이 Post모델에서 정의한 각 필드의 데이터에 접근하기 위해 이 표기법을 사용합니다. 또한 |linebreaksbr같이 파이프 문자(|)도 사용해요. 이건 블로그 글 텍스트에서 행이 바뀌면 문단으로 변환하도록 하라는 의미입니다. 행바뀜을 문단으로 변환하는 필터를 적용한다는 표현을 쓰기도 합니다.
'장고(Django)' 카테고리의 다른 글
Django framework (2) (0) | 2022.02.15 |
---|---|
Django REST Framework로 REST API 만들기 (0) | 2022.02.11 |
장고란 무엇인가요? (0) | 2022.01.06 |