장고(django) 프로젝트에서 사용되는 유저 모델(User Model)을 입맛에 맞게(Customization) 수정하여 사용해 봅시다.
1. 개요
장고(django)로 개발하다보면 기본적으로 제공되는 유저 모델(User Moedl)은 로그인할 때 username으로 로그인해야 합니다. 또한 서비스를 개발할 때, 성별, 생년월일 또는 프로필 사진 등, 다양한 유저 정보를 등록하게 만들고 싶을 때가 있습니다. 이번 블로그 포스트에서는 장고(django)에서 커스텀 유저 모델(Custom User Model)을 사용하는 방법에 대해서 알아보도록 하겠습니다. 이 블로그에 내용은 django 공식 홈페이지의 자료를 바탕으로 만들었습니다.
그리고django_custom_user_model/settgins.py를 열고 아래와 같이 새롭게 추가한 앱(App)을 등록합니다.
...
INSTALLED_APPS = [
...
'account',
]
...
3. 커스텀 유저 모델(Custom User Model) 생성
커스텀 유저 모델(Custom User Model)을 만들기 위해
account/models.py를 열고 아래와 같이 수정합니다.
from django.db import models
from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)
classUserManager(BaseUserManager):defcreate_user(self, email, date_of_birth, password=None):ifnot email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
defcreate_superuser(self, email, date_of_birth, password):
user = self.create_user(
email,
password=password,
date_of_birth=date_of_birth,
)
user.is_admin = True
user.save(using=self._db)
return user
classUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['date_of_birth']
def__str__(self):return self.email
defhas_perm(self, perm, obj=None):returnTruedefhas_module_perms(self, app_label):returnTrue @propertydefis_staff(self):return self.is_admin
좀 더 자세히 살펴보도록 하겠습니다.
...
from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser)
...
class UserManager(BaseUserManager):
...
class User(AbstractBaseUser):
...
커스텀 유저 모델(Custom User Model)를 만들기 위해서는
두 클래스(BaseUserManager, AbstractBaseUser)를 구현해야 합니다.
BaseUserManager 클래스는 유저를 생성할 때 사용하는 헬퍼(Helper) 클래스이며,
실제 모델(Model)은 AbstractBaseUser을 상속받아 생성하는 클래스입니다.
헬퍼(Helper) 클래스인 class UserManager(BaseUserManager):는 두 가지 함수를 가지고 있습니다.
: Ojbect를 반환하는 경우 해당 Object로 사용 권한을 확인하는 절차가 필요합니다.
- def has_module_perms(self, app_label):
: True를 반환하여 주어진 앱(App)의 모델(Model)에 접근 가능하도록 합니다.
- def is_staff(self):
: True가 반환되면 장고(django)의 관리자 화면에 로그인 할 수 있습니다.
4. 관리자 페이지 수정
장고(django)의 관리자 페이지를 통해 유저를 관리하기 위해 관리자 페이지를 수정하도록 하겠습니다.
(1) 폼(Form) 생성
장고(django)의 관리자 페이지에서 사용하는 폼(Form)을 수정하기 위해
자체적으로 우리의 커스텀 유저 모델(Custom User Model)에 맞는 폼(Form)을 생성합니다.
account/forms.py를 생성하고 아래와 같이 수정합니다.
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
classUserCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(
label='Password confirmation', widget=forms.PasswordInput)
classMeta:
model = User
fields = ('email', 'date_of_birth')
defclean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
defsave(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
classUserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
classMeta:
model = User
fields = ('email', 'password', 'date_of_birth',
'is_active', 'is_admin')
defclean_password(self):return self.initial["password"]
좀 더 자세히 살펴보도록 하겠습니다.
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
classUserCreationForm(forms.ModelForm):
...
classUserChangeForm(forms.ModelForm):
...
우리는 사용자 생성 폼(Form)과 사용자 수정 폼(Form)을 만들어야 합니다.
classUserCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(
label='Password confirmation', widget=forms.PasswordInput)
classMeta:
model = User
fields = ('email', 'date_of_birth')
defclean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
defsave(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
사용자 생성 폼(Form)은 password1와 password2를 가지고 있으며
classMeta:
model = User
fields = ('email', 'date_of_birth')
기본적으로 우리가 만든 User 모델의 email과 date_of_birth를 가지고 있습니다.
그리고 def clean_password2(self):을 통해 password2이 password1과 일치하는지 검증합니다.
마지막으로 def save(self, commit=True):를 통해 데이터를 저장합니다.
사용자 정보 수정 폼(Form)은 좀 더 간단합니다.
classUserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField()
classMeta:
model = User
fields = ('email', 'password', 'date_of_birth',
'is_active', 'is_admin')
defclean_password(self):
returnself.initial["password"]
사용자 암호를 ReadOnlyPasswordHashField()으로 가져와서 화면에 표시해 줄 예정입니다.(수정 못함)
classMeta:
model = User
fields = ('email', 'password', 'date_of_birth',
'is_active', 'is_admin')
또한 사용자의 email, paasword, date_of_birth, is_active, is_admin 필드를 가져오고, 저장할 때 def clean_password(self):를 통해 password를 그대로 다시 저장하도록 하였습니다.
(2) 관리자 페이지에 적용
이제 위에서 만든 폼(Form)을 장고(django)의 관리자 페이지에 적용해 보도록 하겠습니다.
account/admin.py를 열고 아래와 같이 수정합니다.
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserChangeForm, UserCreationForm
from .models import User
classUserAdmin(BaseUserAdmin):
form = UserChangeForm
add_form = UserCreationForm
list_display = ('email', 'date_of_birth', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('date_of_birth',)}),
('Permissions', {'fields': ('is_admin',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'date_of_birth', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
admin.site.unregister(Group)
좀 더 자세히 살펴보도록 하겠습니다.
class UserAdmin(BaseUserAdmin):
form = UserChangeForm
add_form = UserCreationForm
관리자 화면의 사용자 변경 폼(Form)과 사용자 추가 폼(Form)을 우리가 생성한 폼(Form)으로 설정하였습니다.
장고(django) 프로젝트에서 API를 사용할때 JWT(Json Web Token) 인증을 사용하는 방법에 대해서 알아보자
1. 개요
리액트 네이티브(React Native)로 개발된 앱(App)의 로그인, 정보 갱신 등의 API 서버를 장고(django)를 사용하여 개발하려고 합니다. 이 때, 앱(App)과 API 서버에 자주 사용되는 JWT(Json Web Token) 인증을 장고(django)를 사용하여 구현하려고 합니다.
회원 가입 및 로그인은 일반 서비스의 회원 가입 및 로그인 절차와 같으므로 자세한 설명은 생략 하도록 하겠습니다.
3. 헤로쿠(Heroku) 앱 생성
헤로쿠(Heroku)에서 웹 서비스를 운영하기 위해서는 헤로쿠(Heroku)에 앱(App)을 생성할 필요가 있습니다.
회원 가입과 로그인후 아래와 같은 대시보드(Dashboard) 화면이 보인다면 Create new app을 눌러 새로운 앱을 생성합니다.
헤로쿠(Heroku) 앱을 생성하기 위해 앱 정보를 입력합니다.
무료이기 때문에 지역은 미국(United State)과 유럽(Europe)만 선택이 가능합니다. 앱 정보를 입력하였다면 Create app을 눌러 앱을 생성합니다.
4. 헤로쿠(Heroku) CLI 설치
우리는 헤로쿠(Heroku) CLI(Command Line Interface)를 통해 우리가 만든 장고(djanog) 프로젝트를 헤로쿠(Herkou) 업로드(Deploy) 할 예정입니다. 아래에 링크를 통해 각 OS에 맞는 헤로쿠(Heroku) CLI를 다운로드 하시기 바랍니다. 여기에서는 macOS를 기준으로 설명합니다.
헤로쿠(Heroku) CLI를 이용하여 헤로쿠(Heroku)에 로그인 할 필요가 있습니다.
아래에 명령어를 통해 헤로쿠(Heroku) 서비스에 로그인 합니다.
heroku login
위에 헤로쿠(Heroku) 명령어를 실행하면 아래와 같이 로그인 화면이 웹 브라우저에 표시됩니다.
Log in 버튼을 눌러 로그인합니다.
로그인이 완료되면 아래와 같이 로그인 성공 화면을 웹 브라우저에서 확인할 수 있으며,
헤로쿠(Heroku) 명령어를 입력한 터미널에서는 아래와 같이 성공 메세지를 확인할 수 있습니다.
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/browser/f844937e-aaaf-4620-998f-1f938ed3dea7
Logging in... done
Logged in as dev.yakuza@gmail.com
6. 장고(django) 프로젝트 수정
헤로쿠(Heroku) 서비스에 배포(Deploy) 준비가 끝났습니다.
우리는 장고(django) 프로젝트를 헤로쿠(Heroku) 서비스에서 동작하도록 수정할 필요가 있습니다.
manage.py가 있는 폴더에 Procfile 파일을 생성한 후 아래와 같이 추가합니다.
web: gunicorn django_exercise.wsgi --log-file -
위에 내용에서 django_exercise.wsgi 부분을 자신의 프로젝트 이름에 맞게 수정합니다.
([project name].wsgi) 우리는 gunicorn이라는 파이썬 HTTP 서버(Python WSGI HTTP Server)를 사용하여 웹 서비스할 것임을 헤로쿠(Heroku)에게 알려주었습니다.
아래에 명령어로 헤로쿠(Heroku)에서 장고(django)를 사용하기 위해 필요한 모듈을 설치합니다.
from django.shortcuts import render, get_object_or_404, redirect
...
from django.utils import timezone
from .forms import PostCreateForm
...
defpost_create(request):if request.method == "POST":
form = PostCreateForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.published_at = timezone.now()
post.save()
return redirect('post_detail', id=post.id)
else:
form = PostCreateForm()
return render(request, 'blog/post_create.html', {'form': form})
- redirect
: 데이터를 성공적으로 저장한 후 페이지를 다른 페이지로 리다이렉트(Redirect)시키기 위한 기능을 불러옵니다.
- from django.utils import timezone
: 블로그 데이터에publised_at에 현재 날짜를 넣기 위해 기능을 불러옵니다.
- if request.method == "POST": ... else
: 우리가 선언한 함수에는 기본적으로 request 파라메터가 설정되어 있습니다.
: 이 request 파라메터의 method를 확인하여 GET/POST를 구별합니다.
: POST인 경우는 폼(Form)을 작성하여 데이터를 저장하는 경우입니다.
- form = PostCreateForm(request.POST)
: 우리가 폼(Form)을 통해 전송한 POST 데이터는 request.POST에 담겨있습니다.
: 이 데이터를 가지고 우리가 생성한 PostCreateForm 폼 클래스(Form class)를 통해 폼 객체(Form object)를 생성합니다.
- if form.is_valid()
: 장고(django)가 기본적으로 제공하는 유효성 체크(Validation) 기능을 사용하여 POST로 보내온 데이터를 확인합니다.
: 우리는 블로그 Post 모델(Model)을 생성할 때, published_at에만 blank = True을 사용하였습니다.
: 따라서 이 필드 이외에 모든 필드는 필수(required) 필드가 적용됩니다.
- post = form.save(commit=False)
: 폼 객체(Form object)를 통해 데이터를 저장(form.save)합니다.
: 하지만 commit=False 옵션을 통해 데이터베이스에 반영하지 않도록 설정합니다.
- post.author = request.user
: 위에서 바로 저장하지 않은 이유는 추가적인 데이터를 함께 저장하기 위해서 입니다. 저장할 데이터의 작성자(author)를 현재 request를 보낸 사용자로 넣습니다. 우리는 관리자 화면을 통해 이미 로그인한 상태임으로 request.user에는 관리자 화면에 로그인한 사용자 정보가 담겨져있습니다.
- post.published_at = timezone.now()
: 추가적으로 공개일(published_at)도 함께 넣어줌으로써 데이터가 화면에 바로 표시될 수 있도록 설정합니다.
- post.save()
: 최종적으로 데이터를 데이터베이스에 저장합니다.
- return redirect('post_detail', id=post.id)
: 그리고 우리가 만든 데이터가 잘 저장되었는지 확인하기 위해
: redirect 함수를 통해 post_detail 페이지로 리다이렉트(redirect) 시킵니다.
- if request.method == "POST"
: ... else: 만약 보내온 요청(request)가 POST가 아닌 경우
- form = PostCreateForm()
: 우리가 만든 폼(Form)을 가져와 return render(request, 'blog/post_create.html', {'form': form}) 화면에 표시합니다.
(4) 링크 생성
위에서 만든 페이지로 활용하기 위해
메인 페이지인 blog/posts.html 파일을 열고 아래와 같이 수정합니다.
{% extends 'blog/layout.html' %}
{% block content %}
<a href="{% url 'post_create' %}">Create Blog Post</a>
{% for post in posts %}
...
{% endfor %}
{% endblock %}
5. 확인
지금까지 작업한 내용을 확인하기 위해 http://127.0.0.1로 접속합니다.
그러면 위와 같이 우리가 새로 추가한 Create Blog Post 링크가 보이는 메인 페이지를 확인할 수 있습니다.
Create Blog Post 링크를 눌러 블로그 작성 페이지로 이동합니다.
그러면 위와 같이 폼(Form) 작성 페이지를 확인할 수 있습니다.
여러분이 저장하길 원하는 데이터를 넣고 Save 버튼을 눌러 데이터를 저장합니다.
데이터 저장 완료후 우리는 상세 페이지로 리다이렉트(Redirect)되도록 작업하였기 때문에,
위와 같이 저장된 데이터의 상세 페이지로 이동하게 됩니다.
마지막으로 상단에 Post List 링크를 눌러 메인 페이지로 이동해 봅니다.
메인 페이지에서 위와 같이 우리가 추가한 데이터가 표시되는 걸 확인할 수 있습니다.
6. 완료
이것으로 장고(django)의 폼(Form)을 사용하는 방법에 대해서 알아보았습니다.
또한 뷰(View)에서 사용자의 요청(Request)을 GET과 POST로 구분하여 다르게 처리하는 방법에 대해서도 알아 보았습니다. 이것으로 우리는 사용자가 보내온 데이터를 저장하거나 수정할 수 있게 되었습니다.
웹 페이지를 위해 장고(django)의 뷰(View)를 사용하는 방법에 대해서 알아보겠습니다.
1. 개요
지금까지 데이터를 저장할 데이터베이스와의 연동과 데이터를 생성(Create)하고 읽고(Read) 갱신(Update)하고 삭제(Delete) CRUD 그리고 사용자가 접속할 URL을 생성하는 방법 등 장고(django)로 웹 서비스를 하기 위한 많은 작업을 진행하였습니다.
이번 블로그에서는 사용자에게 보여줄 웹 페이지를 만들기 위해
장고(django)의 뷰(View)를 사용하는 방법에 대해서 알아보겠습니다.
이 블로그는 시리즈로 작성되어 있으며, 아래에 링크를 통해 시리즈의 다른 글을 확인할 수 있습니다.
이전 블로그(장고(django)의 라우팅(Routing))에서 우리는 사용자가 접속할 URL과 정적 HTML을 연결하는 방법에 대해서 알아보았습니다. 아래에 장고(django) 명령어를 실행하여 테스트 서버를 시작한 후, http://127.0.0.1:8000/에 접속하면 Hello World가 표시되는 웹 페이지를 확인할 수 있습니다.
published_at__isnull=False: published_at 필드가 null이 아닌 경우(__isnull=False)에 데이터를 가져옵니다
order_by('-published_at'): 데이터를 published_at 필드로 내림차순 정렬합니다.
return render(request, 'blog/posts.html', {'posts': posts}): 가져온 데이터를 blog/posts.html 페이지에 {'posts': posts} posts란 변수명으로 전달합니다.
4. 데이터 표시
이제 위에서 전달한 데이터를 화면에 표시해 봅시다.
blog/templates/blog/posts.html 파일을 열고 아래와 같이 수정합니다.
<html><head><title>Hello World</title></head><body>
{% for post in posts %}
<div><h1>
{{ post.title }}<small>(published: {{ post.published_at }})</small></h1><p>{{ post.content | linebreaksbr }}</p></div>
{% endfor %}
</body></html>
{% for post in posts %}...{% endfor %}: 위에서 blog/views.py에서 전달한 posts 데이터 리스트에서 post로 데이터를 하나씩 가져와 반복문을 돌립니다.
{{ post.title }}<small>(published: {{ post.published_at }})</small>: post 데이터의 title / published_at 필드값을 표시합니다.
<p>{{ post.content | linebreaksbr }}</p>: 우리가 가지고 있는 post 데이터의 content를 가져와 줄바꿈(\n)을 줄바꿈 태그(<br/>)로 변환하여 표시합니다.
위와 같이 코드를 수정하고 http://127.0.0.1:8000/에 접속하면
아래와 같이 데이터가 표시되는 것을 확인할 수 있습니다.
조금 더 연습을 하기 위해 상세 페이지를 제작해 봅시다.
위에서 만든 blog/templates/blog/posts.html 파일을 아래와 같이 수정합니다.
<html><head><title>Hello World</title></head><body>
{% for post in posts %}
<ahref="{% url 'post_detail' id=post.id %}"><!-- <<<<<<<<<<<<<<<<<<<<< here --><h1>
{{ post.title }}<small>(published: {{ post.published_at }})</small></h1><p>{{ post.content | linebreaksbr }}</p></a><!-- <<<<<<<<<<<<<<<<<<<<< here -->
{% endfor %}
</body></html>
{% url 'post_detail' id=post.id %}: 우리가 정의한 django_exercise/urls.py 와 blog/urls.py에서 post_detail이라는 이름(name)을 찾고 해당 URL로 변경해 줍니다. 이때 id라는 파라메터를 만들고 Post의 id를 넣어줍니다.
아직은 post_detail과 매칭되는 URL을 만들지 않았습니다.
이제 post_detail과 대응하는 URL과 뷰(View)를 제작해 봅시다.
blog/templates/blog/post_detail.html을 생성하고 아래와 같이 수정합니다.
{% url 'posts' %}: URL 파일에서 posts라는 이름(name)을 갖는 URL을 찾고 그 URL로 대체합니다.
author: {{ post.author.username }}: 우리는 우리가 만든 Post 모델과 장고(django)에서 기본적으로 제공하는 auth.User과 연결하여 작성자(author) 필드를 만들었습니다. 이렇게 연결한 모델(Models)에서 username을 가져와 표시하였습니다.
이제 화면에 표시할 페이지는 준비되었습니다.
blog/urls.py를 열고 아래와 같이 수정합니다.
from django.urls import path
from . import views
urlpatterns = [
path('', views.posts, name='posts'),
path('post/<int:id>/', views.post_detail, name='post_detail'), # <<<<<<<<<<<< here
]
post/<int:id>/: URL에 파라메터로 넘어온 숫자형 데이터 id를 표시합니다.
name='post_detail': URL의 이름은 post_detail이며 views.post_detail와 매핑되어있습니다.
이로써 {% url 'post_detail' id=post.id %}을 사용하여
post/<int:id>/ URL을 표시하고 views.post_detail과 매핑 시킬 준비가 되었습니다.
{% load static %}: 이 파일에서 static 폴더를 사용할 수 있도록 static 폴더를 불러옵니다.
<link rel="stylesheet" href="{% static 'css/main.css' %}" />: 우리가 불러온 static 폴더에서 css/main.css를 찾아 URL로 변경합니다.
{% block content %} {% endblock %}: 이 레이아웃(layout) 파일에 필요한 데이터(content)를 표시할 위치를 설정합니다. 이렇게 표시하고 싶은 부분을 block [name]으로 설정하고 해당 블록(block)을 대체할 부분을 [name]을 사용하여 대체합니다.
이제 레이아웃(layout) 파일을 활용하기 위해 blog/templates/blog/posts.html 파일을 열고 아래와 같이 수정합니다.
ORM(Object-Relation Mapping)란,객체(Object)와 관계형 데이터베이스(Relational)을 연결(Mapping)해 주는 것을 의미한다. 간단하게 설명하면 데이터베이스의 테이블을 객체(Object)와 연결하여 테이블에 CRUD를 할 때, SQL 쿼리를 사용하지 않고도, 가능하게 하는 것을 말합니다.
우리는 이전 블로그(장고(django) 모델(models) 사용해보기)를 통해 이미 장고(django)의 ORM(Object-Relational Mapping)을 사용하기 위한 준비를 하였습니다. 이전 블로그에서 생성한Post모델(Models)은 데이터베이스의blog_post테이블과 연결(Mapping)되어 있습니다. 우리는 이 모델(Models)을 사용하여 데이터베이스에CRUD을 함으로써 장고(django)의 ORM(Object-Relational Mapping)을 이해해 보도록 하겠습니다.
아래에 장고(django) 명령어를 통해 장고(django)가 기본적으로 제공하는 쉘(Shell)을 실행 시킵니다.
Post.objects.create(author=admin, title='This is a test title from django shell', content='This is a test title from django shell. This is a test title from django shell.')
정상적으로 실행되었다면 아래와 같은 결과를 볼 수 있습니다.
>>> Post.objects.create(author=admin, title='This is a test title from django shell', content='This is a test title from django shell. This is a test title from django shell.')
<Post: This is a test title from django shell>
(3) 데이터 생성 확인
다시 한번 Post 모델(Models)을 조회하면 아래와 같이 데이터가 잘 추가된 것을 확인 할 수 있습니다.
>>> Post.objects.all()
<QuerySet [<Post: thisis a test1 title>, <Post: thisis a test2 title>, <Post: This is a test title from django shell>]>
새로운 터미널에서 아래에 장고(django) 명령어로 테스트 서버를 실행한 후,
관리자 화면에서 데이터를 확인하면 아래와 같이 데이터가 잘 추가된 것을 확인할 수 있습니다.
지금까지 장고(django)의 쉘(Shell)을 이용하여 간단하게 장고(django)의 ORM(Object-Relational Mapping)에 대해서 연습해 보았습니다. 아래에 코드로 장고(django)의 쉘(Shell)을 종료합니다.
exit()
(9) 완료
이것으로 장고(django)의 ORM(Object-Relational Mapping)에 대해 알아보았습니다.
ORM(Object-Relational Mapping)은 장고(django)이외에도 많은 프레임워크에서 사용되는 개념이므로 잘 기억에 두면 좋을거 같네요. 이것으로 우리는 장고(django)의 모델(Models)을 사용하여 데이터를 읽고 쓰고 업데이트하고 삭제(CRUD - Create Read Update Delete)할 수 있게 되었습니다!
장고(django)는 크게 프로젝트(Project) 단위와 어플리케이션(Application) 단위가 존재합니다.
장고(djanog) 프로젝트는 여러 어플리케이션을 가질 수 있습니다.
이것은 곧
프로젝트(Project) 단위의 라우팅(Routing) 관리와
어플리케이션(Application) 단위의 라우팅(Routing) 관리가 존재한다는 것을 의미합니다.
우선 장고(django)의 프로젝트 단위의 라우팅(Routing) 관리를 확인하기 위해
django_exercise/urls.py 파일을 확인 합니다.
...
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
파일을 열면 위와 같은 화면을 볼수 있습니다.
이전 블로그(장고(django)의 관리자 페이지)에서 http://127.0.0.1:8000/admin URL로 관리자 페이지에 접속하였습니다. 우리가 아무 설정도 하지 않아도 관리자 화면이 표시된 이유는 django_exercise/urls.py 파일에 위와 같은 설정이 기본적으로 설정되어있기 때문입니다. 우리는 이곳에 우리가 만든 새로운 장고(django) 어플리케이션(Application)의 라우팅 파일을 등록하여 어플리케이션(Application)별 라우팅을 관리할 예정입니다.
3. views.py 생성
일단 어플리케이션(Application)의 라우팅(Routing)을 통해 URL에 연결할 뷰(Views)를 생성할 필요가 있습니다. blog/views.py를 열고 아래와 같이 수정합니다.
from django.shortcuts import render
defposts(request):return render(request, 'blog/posts.html', {})
4. html 파일 생성
이제 뷰(Views) 파일에서 참고하고 있는 blog/posts.html 파일을 생성해야 합니다.
blog/templates/blog/posts.html 파일을 생성하고 아래와 같이 코딩합니다.
<html><head><title>Hello World</title></head><body>
Hello World
</body></html>
이것으로 라우팅(Routing)을 통해 URL에 연결할 화면 준비가 끝났습니다.
이제 실제로 라우팅(Routing)을 통해 URL과 화면을 연결하는 방법에 대해서 알아보겠습니다.
5. 어플리케이션의 라우팅 파일 urls.py 생성
우리가 제작중인 블로그 웹 사이트에 해당하는 장고(django) 어플리케이션(Application)을 위한 라우팅(Routing) 파일을 생성할 필요가 있습니다. blog/urls.py 파일을 생성하고 아래에 내용을 추가합니다.
from django.urls import path
from . import views
urlpatterns = [
path('', views.posts, name='posts'),
]
6. 어플리케이션의 라우팅 등록
위에서 생성한 장고(django) 어플리케이션(Application)의 라우팅(Routing) 파일인 blog/urls.py를 장고(django) 프로젝트(Project)에 등록할 필요가 있습니다. django_exercise/urls.py 파일을 열고 아래와 같이 수정합니다.
from django.contrib import admin
from django.urls import path, include # <<< here
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')), # <<< here
]
7. 확인
아래에 장고(django) 명령어로 테스트 서버를 실행한 후,
http://127.0.0.1:8000/에 접속하여 우리가 설정한 라우팅(Routing)이 동작하는지 확인합니다.