IT/WEB

[Django] Django로 2개이상의 앱을 구축시, 사전에 고려해두는 것이 좋은 부분

개발자 두더지 2020. 9. 15. 17:06
728x90

( 일본의 한 블로거의 포스팅을 번역한 포스팅입니다. 오역이나 의역이 있을 수 있으며, 틀린 부분에 대해서는 지적해주시면 감사하겠습니다. )

 

 Django를 사용하여 Web앱을 개발하고 있다. 처음부터 동시에 두 개의 어플리케이션 ( 같은 곳에 사용되나, 기능이 거의 다르므로 두 가지로 나누고 있다) 를 구축하고 있다. 그러나 하나를 만든 후 다른 하나를 만들 때 여러가지 걸리는 부분이 있었기 때문에 어떠한 부분에서 곤란을 겪었는지에 대해 써 볼 생각이다. 

 Django는 실제 환경에서 어떻게 동작하는지에 대해 작성하고 있는 포스팅이 생각보다 없는 인상이므로 이 포스팅이 도움이 되었으면 한다.

 

 

버전


명칭 버전
Python 3.7.0
Django 2.1.1

 

 

샘플 


샘플 구성

프로젝트로써 django_complex_sample이라는 것을 만들고 그 안에 app1, app2라는 어플리케이션을 만들었다.

■ 사전 준비

 settings.py INSTALLED_APP에 app1과 app2를 추가한다. DB는 특별히 사용하지 않지만, SQLite로 해두자. 또한, URL도 지정해둔다.

(1) settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app1',
    'app2',
]

(2) urls.py

from django.contrib import admin
from django.urls import path
from app1 import views as v1
from app2 import views as v2

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', v1.HomeView.as_view(), name="app1home"),
    path('app2/', v2.HomeView.as_view(), name="app2home"),
]

 

 

템플릿


■ 결론

표준대로 작성한다면,

/templates/app_name 의 폴더를 만들고 거기에 파일을 저장한다.

② 뷰(View)로 부터 템플릿을 참고하는 경우, app_name/file_name으로 기재한다.

 

■ 근거

템플릿 | Django documentation | Django

 템플릿은, view로 패스지정되어 페이지를 그릴때 사용된다. 표준대로 작성할 경우, 각 사이트에 templates라는 폴더를 만들더 그곳에 HTML을 배치해두면 사이트 표시될 때에 그 템플릿이 표시된다. 

 단지, 보여질 템플릿이 결정되는 것은 템플릿 폴더를 검색하여 처음에 발견한 파일을 사용하는 동작으로 작동하고 있다. 즉, 자동적으로 어플 마다 판정하고 있는 것은 아니다.

 

■ 예

예를 들어, app2의 templates바로 아래에 home.html을 두었다. app1에서의 같은 폴더는 아무것도 두지 않고 비워두었다. 그리고 app1의 뷰(view)에서 템플릿 명 home.html을 지정한다.

 

app2의 템플릿

app1/views.py

from django.shortcuts import render
from django.views.generic import TemplateView

# Create your views here.

class HomeView(TemplateView):
    template_name = 'home.html' # app1의home.html을 기대하고 있으나, 아직 만들어지지 않음.
    def get(self, request, *args, **kwargs):
        return render(request, self.template_name)

app1/home.html

<h1>Hello App1!</h1>

app2/home.html

<h1>Hello App1!</h1>

 결과는 위와 같이, app2의 home.html을 참고하여 표시해버리고 만다. 이것은 templates의 검색으로 app2에 있는 home.html을 찾았기 때문이다.

 이러한 결과를 피하기 위해 모든 어플리케이션 아래에 아래와 같이 폴더를 나눠,

app2의 폴더 구성

app1/views.py

from django.shortcuts import render
from django.views.generic import TemplateView

# Create your views here.

class HomeView(TemplateView):
    template_name = 'app1/home.html' # templates/app1폴더를 참고하도록
    def get(self, request, *args, **kwargs):
        return render(request, self.template_name)

참고하도록 하고자하는 폴더를 고정으로 지정하도록 하자.

 

 

정적 파일 (static)


■ 결론

- 각 어플리케이선 바로 아래에 /static/app_name 이라는 파일을 만들고, 그곳에 파일을 저장하자.

- 템플릿에서 파일을 참고하는 경우, app_name/file_name 이라고 기재하자.

 

■ 근거

정적 파일 (이미지, JavaScrop, CSS 등)의 관리 | Django documentation | Django

 정적 파일이란, JavaScript나 이미지등 페이지에 삽입 형태로 사용하을 파일을 일컫는다. 개발시에는 각 어플리케이션 바로 아래에 static이라는 폴더를 만들어 그곳에 파일을 저장한다.

 이러한 파일은 실제 환경에는 한 곳에 모두 모아 관리한다. collectstatic 커맨드로 정적 파일을 모을 수 있다. 시험삼아, static 폴더에 main.css파일 한 개만 배치하고, collectstatic을 실행해보자.

 그럼, static 바로아래에 위치해버리고 만다. 이렇게 되면 복수의 사이트에 같은 파일명의 파일이 있을 때 서로 덮어쓰게 된다. 

 그러므로 각 어플리케이션의 static 바로 아래에 어플리케이션의 폴더를 작성하고 파일이 충돌하지 않도록 하자. 템플릿에서 참고하는 경우에도.

app1/home.html

{% load static %}
<script type="text/javascript" src="{% static 'app1/main.css' %}"></script>

와 같이 패스에 어플리케아션을 붙일 필요가 있으므로 개발 착수 시작부터 대응해두는 것이 좋을 것이다. static내에 어플리케이션 명의 폴더를 만들어 collectstatic을 실행하면 아래와 같이 된다.

어플리케이션 마다 폴더 분할 후 collectstatic

 

 

URL (urls.py)


■ 결론

- 어플리케이션마다 urls.py를 작성한다.

- 각 어플리케이션의 urls.py에 고유의 app_name을 정의한다.

- 프로젝트의 urls.py에 각 어플리케이션의 정의를 include한다.

- 템플릿에서 어플명을 지정한다.

 

■ 근거

URL 디스패쳐 | Django documentation | Django

현재 프로젝트에 있는 urls.py는 아래와 같이 되어 있다. 

django_complext_sample/urls.py

from django.contrib import admin
from django.urls import path
from app1 import views as v1
from app2 import views as v2

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', v1.HomeView.as_view(), name="app1home"),
    path('app2/', v2.HomeView.as_view(), name="app2home"),
]

어플리케이션에서 URL이 증가한 경우에 여기에 정의를 늘려서 대응하는 것이 가능하다. 그러나 그렇게 한다면,

- URL을 재편성할 때마다 프로젝트의 수정해야한다.

- name의 명령 규칙이 알기 어렵게 되어버린다.

- 프로젝트쪽에 어플리케이션의 URL을 모두 관리하는 것은 힘들다.

위와 같은 문제들이 발생한다. 그러므로 Django에서는 include라는 기능이 준비되어 있다.

 

■ 예

먼저 각 어플리케이션의 바로 아래(어디든 괜찮지만)에 urls.py를 작성한다.

그리고 각 어플리케이션에 대해 URL을 기재한다.

app1/urls.py

"""app1의URL정의"""
from django.urls import path
from .apps import App1Config as config
from . import views as v

app_name = config.name # app1이 들어있다.
urlpatterns = [
    path('', v.HomeView.as_view(), name='home'),
]

그리고 프로젝트의 urls.py에 그것을 include한다.

django_complex_smaple/urls.py

from django.contrib import admin
from django.urls import path, include
from app1 import urls as v1
from app2 import views as v2

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', include(v1)), # 변경(app1의URL을 추가)
    path('app2/', v2.HomeView.as_view(), name="app2home"),
]

 이렇게 작성해두면 자동적으로 app1의 URL에의 라우팅을 추가해준다. 또한 이 기능을 사용한 경우, view에서의 URL 지정 변경도 바뀐다. 먼저 app1에 적당한 뷰를 추가하자.

app1/views.py

from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView
from django.http import HttpResponse

# Create your views here.

class HomeView(TemplateView):
    template_name = 'app1/home.html'
    def get(self, request, *args, **kwargs):
        return render(request, self.template_name)

class ApplicationView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse('GET request!')

app1/urls.py

"""app1의URL정의"""
from django.urls import path
from .apps import App1Config as config
from . import views as v

app_name = config.name # app1가 들어있다.
urlpatterns = [
    path('', v.HomeView.as_view(), name='home'),
    path('app/', v.ApplicationView.as_view(), name='app'), # 추가
]

작성된 view에 대해 home.html로부터 링크를 작성하자.

app1/templates/home.html

{% load static %}
<!DOCTYPE html>
<html lang="ja">
  <head>
    <link href="{% static 'app1/main.css' %}" rel="stylesheet">
  </head>
  <body>
    <h1>Hello App1!</h1>
    <a href={% url 'app1:app' %}>링크</a>
  </body>

여기 코드에서 중요한 부분은 여기이다.

<a href={% url 'app1:app' %}>링크</a>

url이라는 Django 태그로 지정한 이름의 URL을 설정해주지만, {% url '[app_name]:[name]'%}과 href로 지정하면 어플명을 판정하여 그 링크를 만들어 준다. 이것에 의해 어플간의 이름 충돌을 방지할 수 있다.


참고자료

hiroronn.hatenablog.jp/entry/20181216/1544950291

 

728x90