Django

h232ch·2022년 1월 29일
1

backend

목록 보기
1/1
post-thumbnail

django 4.0 document 참고

Settings


BASE_DIR

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

Path(file) : 현재 파일의 위치 .resolve : 절대 경로 .parent : 상위 경로base_dir 위치는 settings.py의 절대 경로에서 상위로 2번 이동한 경로이다.


SECRET_KEY

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-*2#5z(m5v)+aw6cycu+))zh(m!@n$$*--hu-8(v_$@ujwo3=36'

시크릿 키는 Django 설치 시 자동으로 제공되는 유일하고 예측 불가한 값으로 text나 bytes로 가정할 수 없으며 force_str() or force_bytes()로 변환하여 사용된다. 이 키의 용도는 아래와 같다.


INSTALL_APPS

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

Django 프로젝트 내부에 사용되는 모든 앱이 기록되는 곳으로 아래 내용이 추가됨

  • 애플리케이션 configuration class (prefeered)
  • 애플리케이션을 포함하는 패키지

MIDDLEWARE

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output. https://docs.djangoproject.com/en/4.0/topics/http/middleware/


ROOT_URLCONF

ROOT_URLCONF = 'clone_pb.urls'

root URLConf의 위치를 나타냄


TEMPLATES

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',
            ],
        },
    },
]

장고에서 사용되는 모든 템플릿 엔진이 위치하는 설정으로 각 엔진에 대한 옵션이 설정되어 있다.

BACKEND : 백엔드 템플릿

  • 'django.template.backends.django.DjangoTemplates'
  • 'django.template.backends.jinja2.Jinja2'

DIR : 템플릿 엔진이 사용되는 템플릿 위치

APP_DIRS : 설치된 애플리케이션 내에서 템플릿 위치를 찾을 것인지 여부 기본값=True

OPSTIONS : 백엔드 템플릿에 전달할 추가 인자로 사용 가능한 인자는 백엔드 팀플릿에 따라 다름

context_processors : context_processors is a list of dotted Python paths to callables that are used to populate the context when a template is rendered with a request. These callables take a request object as their argument and return a dict of items to be merged into the context.https://docs.djangoproject.com/en/4.0/ref/templates/api/


PASSWORD_VALIDATION

https://docs.djangoproject.com/en/4.0/topics/auth/passwords/#password-validation

admin 애플리케이션에서 사용되는 인증 과정에서 패스워드를 검증하는 프로세스


LANGUAGE CODE AND TIME ZONE

LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_TZ = True

STATIC, MEDIA

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
    BASE_DIR / "static",
                    ]

MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / "media"

STATIC_URL : 정적 파일이 위치하는 URL (실제 urlConf를 조작해서 해당 위치로 연결 가능)

STATIC_ROOT : 배포 진행 시 정적 파일을 모아두는 장소 (배포시 모든 정적 파일이 해당 위치로 복사 됨)

STATICFILES_DIRS : 실제 정적 파일이 위치하는 장소

MEDIA_URL, MEDIA_ROOT : STATIC과 동일한 개념

MDEIA_UPLOAD : For example, if your [MEDIA_URL](https://docs.djangoproject.com/en/4.0/ref/settings/#std:setting-MEDIA_URL) is defined as media/, you can do this by adding the following snippet to your [ROOT_URLCONF](https://docs.djangoproject.com/en/4.0/ref/settings/#std:setting-ROOT_URLCONF)

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [path('admin/', admin.site.urls),
               path('project/', include('project.urls')),
               path('blog/', include('blog.urls')), ]

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Migrating Auto Field

# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'


URL dispatcher

How Django Processes a request

When a user requests a page from your Django-powered site, this is the algorithm the system follows to determine which Python code to execute

  1. 일반적으로 ROOT_URLCONF 설정에 따라 root URLconf를 확인한다. 그러나 인입되는 HttpRequest object가 urlconf 애트리뷰트를 가지고 있다면 ROOT_URLCONF 설정 대신 해당 값을 사용함
  2. 장고는 해당 파이선 모듈을 로드하고 urlpatterns 변수를 찾는다. 이는 django.urls.path() 혹은 django.urls.re_path() 인스턴스의 시퀀스여야 한다.
  3. 장고는 각각의 URL 패턴을 실행하고 요청된 URL과 일치하는 첫번째 패턴에서 중지한다. 이때 매칭되는 패턴은 path_info이다.
  4. URL 패턴에 매치되면 장고는 뷰를 임포트하고 호출한다. 뷰에는 아래의 인수가 전달된다.
  • An instance of HttpRequest (request 인스턴스)
  • 일치하는 URL 패턴에 no named gruops가 포함되는 경우, positional arguments 위치에 정규표현식이 제공됨
  • keyword arguem는 제공된 경로 표현식과 일치하는 named parts로 구성되며, django.urls.path() 또는 django.urls.re_path()에 대한 선택적 kwargs 인수에 지정된 인수로 재정의 됨
  1. 만약 일치하는 URL 패턴이 없을 경우나 예외가 발생하는 경우, 장고는 적절한 에러 핸들링 뷰를 일으킨다.

Example

from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

Note

  • URL에서 value를 캡처하려면 꺾쇠 괄호를 사용해야 함 <int:year>
  • 캡처된 value는 선택적으로 컨버터 타입을 포함할 수 있음. 가령 <int:name>의 경우 integer 파라메터만 캡처한다. 만약 컨버터 타입을 포함하지 않으면 / 문자를 제외한 모든 문자열이 일치됨
  • 모든 URL에는 슬래시가 있으므로 URL 맨 앞에 슬래시를 포함할 필요는 없음 (articles, not /articles)

Example requests:

  • A request to /articles/2005/03/ would match the third entry in the list. Django would call the function views.month_archive(request, year=2005, month=3).
  • /articles/2003/ would match the first pattern in the list, not the second one, because the patterns are tested in order, and the first one is the first test to pass. Feel free to exploit the ordering to insert special cases like this. Here, Django would call the function views.special_case_2003(request)
  • /articles/2003 would not match any of these patterns, because each pattern requires that the URL end with a slash.
  • /articles/2003/03/building-a-django-site/ would match the final pattern. Django would call the function views.article_detail(request, year=2003, month=3, slug="building-a-django-site").
    • slug - Matches any slug string consisting of ASCII letters or numbers, plus the hyphen and underscore characters. For example, building-your-1st-django-site.

Using Regular Expression

regular expression uses [re_path()](https://docs.djangoproject.com/en/4.0/ref/urls/#django.urls.re_path) instead of [path()](https://docs.djangoproject.com/en/4.0/ref/urls/#django.urls.path).

from django.urls import path, re_path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

Using unnamed regular expression groups

As well as the named group syntax, e.g. (?P<year>[0-9]{4}), you can also use the shorter unnamed group, e.g. ([0-9]{4}).


Specifying defaults for view arguments

# URLconf
from django.urls import path

from . import views

urlpatterns = [
    path('blog/', views.page),
    path('blog/page<int:num>/', views.page),
]

# View (in blog/views.py)
def page(request, num=1):
    # Output the appropriate page of blog entries, according to num.
    ...

위 코드에서 URL 패턴은 동일한 뷰(page)를 가르키고 있다. 그러나 첫번째 패턴은 동작하지 않을 것이고 두번째 패턴 또한 num 변수에 1이 오지 않는 이상 동작하지 않을 것이다.


Performance

Each regular expression in a urlpatterns is compiled the first time it’s accessed. This makes the system blazingly fast.


Including other URLconfs

urlpatterns은 다른 URLconf 모듈을 include할 수 있다. 아래의 예제처럼 community/ url로 접속 할 경우 include된 aggregator 앱의 URLconf로 연결된다. 이때 community 문자열을 자르고 나머지를 include된 URLconf로 보내게 된다.

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path('community/', include('aggregator.urls')),
    path('contact/', include('contact.urls')),
    # ... snip ...
]

다른 방법으로는 path() 리스트 인스턴스를 생성하여 추가되는 URL 패턴을 include하는 방식이다.

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path('reports/', credit_views.report),
    path('reports/<int:id>/', credit_views.report),
    path('charge/', credit_views.charge),
]

urlpatterns = [
    path('', main_views.homepage),
    path('help/', include('apps.help.urls')),
    path('credit/', include(extra_patterns)),
]

위 예제에서 /credit/reports/ URL은 credit_views.report()뷰에서 처리된다.

아래 예제는 싱글 패턴 프리픽스가 반복적으로 사용되는 URLconf에서 중복을 제거하는 방법이다.

from django.urls import path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/history/', views.history),
    path('<page_slug>-<page_id>/edit/', views.edit),
    path('<page_slug>-<page_id>/discuss/', views.discuss),
    path('<page_slug>-<page_id>/permissions/', views.permissions),
]

위 코드는 아래와 같이 중복을 제거함으로써 향상시킬 수 있다.

from django.urls import include, path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/', include([
        path('history/', views.history),
        path('edit/', views.edit),
        path('discuss/', views.discuss),
        path('permissions/', views.permissions),
    ])),
]

Captured parameters

An included URLconf receives any captured parameters from parent URLconfs, so the following example is valid:

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path('<username>/blog/', include('foo.urls.blog')),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

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

In the above example, the captured "username" variable is passed to the included URLconf, as expected.


Reverse resolution of URLs

Django provides tools for performing URL reversing that match the different layers where URLs are needed:

  • In templates: Using the [url](https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#std:templatetag-url) template tag.
  • In Python code: Using the [reverse()](https://docs.djangoproject.com/en/4.0/ref/urlresolvers/#django.urls.reverse) function.
  • In higher level code related to handling of URLs of Django model instances: The [get_absolute_url()](https://docs.djangoproject.com/en/4.0/ref/models/instances/#django.db.models.Model.get_absolute_url) method.
from django.urls import path

from . import views

urlpatterns = [
    #...
    path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
    #...
]

According to this design, the URL for the archive corresponding to year nnnn is /articles/<nnnn>/.

You can obtain these in template code by using:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

or python code

from django.http import HttpResponseRedirect
from django.urls import reverse

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

Naming URL patterns

URL 리버싱이 실행되기 위해 named URL 패턴이 필요하다. URL 패턴을 지정할 때는 다른앱의 명칭과 충돌하지 않도록 해야한다. 만약 comment라는 URL 패턴 호출했는데 다른 앱에 동일한 URL 패턴이 존재한다면 reverse()는 프로젝트 urlpatterns에서 마지막으로 생성된 패턴을 찾게된다. 이를 방지하기 위해 애플리케이션 명칭을 프리픽스로 URL 명칭 앞에 두도록 한다. (such as myapp-comment instead of comment)

의도적으로 동일한 URL 명칭을 사용하는 경우도 있는데 가장 보편적인 유즈케이스는 LoginView와 같이 다른 앱에서도 동일한 기능으로 동작하는 기능에 대해서는 의도적으로 URL 명칭을 동일하게 작성하여 오버라이딩 한다. 또한 동일한 URL 명칭을 사용하더라도 아규먼트가 다른경우에도 사용 가능하다.


URL namespaces

Introduction

URL 네임스페이스는 우리가 고유하게 URL 패턴을 리버스할 수 있게 해준다. 만약 다른 애플리케이션에서 동일한 URL 명칭을 사용한다고 하더라도 가능하다. 항상 네임스페이스 URL을 사용하는것은 좋은 사례이다. 비슷하게 여러개의 애플리케이션 인스턴스가 배포되어도 우리는 URL을 리버스할 수 있다. 즉, 단일 애플리케이션의 여러인스턴스가 named URL을 공유하기 떄문에 네임스페이스는 named URL을 구분하는 방법을 제공한다.

  • 두개의 다른 애플리케이션이 동일한 URL 패턴을 사용할 때 application namespace를 사용한다.
  • 동일한 URLconf를 사용하는 하나의 애플리케이션에 속한 두개의 인스턴스와 뷰는 instance namespace를 사용한다.

URL 네임스페이스는 아래와 같이 두 부분으로 나윕니다.

application namespace
배포된 애플리케이션 이름을 설명한다. 단일 애플리케이션의 모든 인스턴스는 동일한 애플리케이션 네임스페이스를 갖는다. 예를들어, 장고 어드민 애플리케이션은 admin이라는 다소 예측 가능한 애플케이션 네임스페이스가 있다.
instance namespace
애플리케이션의 특정 인스턴스를 식별한다. 인스턴스 네임스페이스는 프로젝트 전반에서 유일한 값이어야 한다. 반면 인스턴스 네임스페이스는 애플리케이션 네임스페이스와는 동일한 값을 갖을 수 있다. 이것은 앱의 디폴트 인스턴스를 지정하기 위해 사용된다. 예를들어 장고 어드민 인스턴스는 ‘admin’이라는 인스턴스 이름을 갖는다.

네임스페이스는 ‘:’ 구분자로 구분된다. 장고 어드민 메인 인덱스 페이지는 ‘admin:index’를 참고하고 이는 ‘admin’ 네임스페이스와 named URL인 ‘index’를 나타낸다. 또한 네임스페이스는 중첩이 가능하다. ‘sports:polls:index’는 최상위 네임스페이스 sports에 정의된 poll 네임스페이스에서 index를 찾을 것이다.


Reversing namespaced URLs

‘polls:index’라는 네임스페이스된 URL을 resolving하기 위해, 장고는 정규화된 명칭을 부분으로 분리하는 작업을 수행하고 아래의 절차에 따른다.

  1. 첫번째로, 장고는 매챙되는 애플리케이션 네임스페이스를 찾는다 (예제의 polls). 그리고 해당 애플리케이션의 인스턴스 리스트를 생성한다.
  2. 만약 current application(ex, polls)이 지정되어 있다면, 장고는 인스턴스를 위해 URL resolver를 리턴한다. current application은 reverse() 함수의 current_app 인수로 지정된다.
  3. 만약 current application이 존재하지 않을 경우, 장고는 default application instance를 찾는다. 디폴트 애플리케이션 인스턴스는 애플리케이션 네임스페이스와 인스턴스 네임스페이스가 동일한 것을 말한다.
  4. 디폴트 인스턴스가 존재하지 않을 경우 장고는 가장 최근 배포된 애플리케이션의 인스턴스를 선택할 것이다.
  5. 제공된 네임스페이스가 1단계에서 애플리케이션 네임스페이스와 일치하지 않으면 장고는 네임스페이스를 인스턴스 네임스페이스로 직접 조회한다.

Example (👍)

To show this resolution strategy in action, consider an example of two instances of the polls application from the tutorial: one called 'author-polls' and one called 'publisher-polls'. Assume we have enhanced that application so that it takes the instance namespace into consideration when creating and displaying polls.

from django.urls import include, path

urlpatterns = [
    path('author-polls/', include('polls.urls', namespace='author-polls')),
    path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    ...
]
  • The Application namespace is defined by app_name attribute in polls/urls.py
  • The Instance namespace is defined by namespace argument in urls.py

Using this setup, the following lookups are possible:

  • If one of the instances is current - say, if we were rendering the detail page in the instance 'author-polls' - 'polls:index' will resolve to the index page of the 'author-polls' instance; i.e. both of the following will result in "/author-polls/".

In the method of a class-based view:

reverse('polls:index', current_app=self.request.resolver_match.namespace)

and in the template:

{% url 'polls:index' %}
  • If there is no current instance - say, if we were rendering a page somewhere else on the site - 'polls:index' will resolve to the last registered instance of polls. Since there is no default instance (instance namespace of 'polls'), the last instance of polls that is registered will be used. This would be 'publisher-polls' since it’s declared last in the urlpatterns.
  • 'author-polls:index' will always resolve to the index page of the instance 'author-polls' (and likewise for 'publisher-polls') .

If there were also a default instance - i.e., an instance named 'polls' - the only change from above would be in the case where there is no current instance (the second item in the list above). In this case 'polls:index' would resolve to the index page of the default instance instead of the instance declared last in urlpatterns.


Think of instance namespace as your nickname and application namespace as your real name.

People can have many nicknames for you, but your real name doesn't change.

Django uses the application namespace (your real name) to reverse urls, cause as an application you should not care how many instance namespaces (nicknames) there are.

But to differentiate between one instance and the next, you will use the instance namespaces (nicknames) in urlconfs.

Let's say your app deals with customers and store employees. Both of these have physical addresses and you might want to use an app that just handles all address information: forms, validation, model structure, geo location etc. Our fictional app is a reusable django app called "django_super_address".

Your root url conf may look like this:

Example 2

urlpatterns = [
    path('customer/address/',
         include('django_super_address.urls',
         namespace='customer_address')
    ),
    path('employee/address/',
         include('django_super_address.urls',
         namespace='employee_address')
    ),
]
# File: django_super_address/urls.py
from . import views
app_name = 'django_super_address'

urlpatterns = [
    path('create/', views.SomeAddressCreateView.as_view(),
         name='address_create'),
    path('create/success/', views.SuccessView(),
         name='address_create_success'),
    ...
]
# File django_super_address/views.py
class SomeAddressCreateView(generic.CreateView):
    def success_url(self):
        return reverse(
           'django_super_address:address_create_success'
        )
    ...

When Django gets the URL `/employee/address/create/':

  1. It sets the instance namespace to employee_address
  2. It reads the urls from django_super_address
  3. It sets the application namespace to django_super_address and associates the urls.py with that application namespace.

In the view:

  1. It reverses the URL by looking at the urls file associated with the application namespace (real name) and reverses the name into: create/success
  2. It then goes back up the chain, now using the instance namespace (nickname) to prepend the rest of the url: root + employee/address/ + create/success/ = /employee/address/create/success/

URL namespaces and included URLconfs

URLconfs를 포함하는 애플리케이션 네임스페이스는 두가지 방식으로 정의된다.

첫번째로 included URLconf 모듈에 app_name 속성을 추가한다. 실제로 모듈 또는 모듈에 대한 참조를 urlpatterns 자체 목록이 아니라 include()에 전달해야 한다.

# polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    ...
]
# urls.py
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
]

polls.urls로 정의된 URL은 polls라는 네임스페이스를 갖게된다.

두번째로 내장된 네임스페이스 데이터를 포함한 오브젝트를 include 할 수 있다. re_path(), path()의 목록을 include() 하면 오브젝트에 포함된 URL은 글로벌 네임스페이스로 추가된다. 또한 2-tuple을 포함하는 include()도 사용 가능하다.

from django.urls import include, path
from . import views

polls_patterns = ([
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
], 'polls')

urlpatterns = [
    path('polls/', include(polls_patterns)),
]

Writing views

뷰 함수 혹은 짧은 표현으로 뷰는 web request, response를 처리하는 파이썬 함수이다. reponse의 종류는 HTML 웹 페이지 컨텐츠, 리다이렉션, 404 에러, XML 다큐먼트, 이미지 등 모든것이 가능하다. 뷰 자체에는 reponse를 리턴을 위해 필요한 임의의 로직이 포함되어 있다. 이 코드가 파이썬 경로에 위치하는 한 어디에서나 동작한다. 코드를 어딘가에 두기 위해 규칙은 views.py로 불리는 파일에 위치하게 되며 이 파일은 장고 프로젝트 혹은 애플리케이션 디렉토리에 위치한다.

A simple view

아래 예제는 현재 날짜와 시간을 HTML 형태로 리턴한다.

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)
  • 먼저 django.http 모듈에서 HttpResponse와 파이썬의 datetime을 임포트 시켜준다.
  • current_datetime 이라는 뷰 함수를 만든다. 각각의 뷰 함수는 request로 부르는 HttpsRequset 객체를 첫번째 파라메터로 받는다.
  • 해당 뷰는 생성된 응답인 HttpaResponse 객체를 리턴한다. 각 뷰 함수는 HttpResponse 객체를 응답하는 역할을 한다. (예외는 존재하지만 나중에 알아보도록 한다.)

Django’s Time Zone
장고는 America/Chicago를 기본값으로 TIME_ZONE을 세팅한다. 이것을 변경하기 위해 settings 파일을 변경해야 한다.


Mapping URLs to views

위 예제의 뷰 함수는 현재 시간과 날짜를 담은 HTML 페이지를 리턴한다. 특정한 URL에 해당 뷰를 연결하고자 한다면 URLconf를 설정해줘야 한다. (자세한 내용은 URL dispatcher 참고)


Returning errors

장고는 HTTP 에러 코드를 리턴할 수 있도록 도와준다. 여기는 수많은 공통 HTTP 상태 코드가 HttpResponse 하위 클래스로 존재한다. 우리는 사용가능한 하위 클래스 리스트를 request/response 도큐멘트에서 참고할 수 있다. 특정 에러를 구분하기 위해 일반적인 HttpResponse 대신 하위 클래스중 하나의 인스턴스를 아래와 같이 리턴할 수 있다.

from django.http import HttpResponse, HttpResponseNotFound

def my_view(request):
    # ...
    if foo:
        return HttpResponseNotFound('<h1>Page not found</h1>')
    else:
        return HttpResponse('<h1>Page was found</h1>')

가능한 모든 HTTP 응답 코드에 대한 하위 클래스를 구분하지는 않는다. 대부분의 응답은 일반적이지 않을 것이기 떄문이다. 또한 HttpResponse 도큐멘트에 따라서 HttpResponse 객체에 HTTP status 코드를 전달 할 수도 있다.

from django.http import HttpResponse

def my_view(request):
    # ...

    # Return a "created" (201) response code.
    return HttpResponse(status=201)

404 오류는 가장 일반적인 HTTP 오류이기 때문에 더 쉽게 처리하는 방법이 있다.

The Http404 exception

[class django.http.Http404](https://docs.djangoproject.com/en/4.0/topics/http/views/#django.http.Http404)

HttpResponseNotFound를 리턴할 때, 에러 페이지 결과의 HTML을 지정해야 한다.

return HttpResponseNotFound('<h1>Page not found</h1>')

편의를 위해 그리고 사이트 전반에 일관적인 404 에러 페이지를 갖는 것이 좋다. 장고는 Http404 예외를 제공하는데 만약 Http404가 어떤 뷰 함수 위치에서 발생하던지 장고는 이것을 캐치하여 HTTP 오류 코드 404화 함께 애플리케이션에 대한 표준 에러 페이지를 반환한다.

from django.http import Http404
from django.shortcuts import render
from polls.models import Poll

def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404("Poll does not exist")
    return render(request, 'polls/detail.html', {'poll': p})

장고가 404를 리턴할 때 커스텀 HTML을 보여주기 위해 404라는 HTML 템플릿을 만들고 템플릿 트리 최상위에 위치 시킨다. 이 템플릿은 DEBUG가 False로 설정되어 있는 경우 제공된다. DEBUG가 True일 경우 Http404 메세지를 제공할 수 있고 이는 표준 404 debug 템플릿을 보여준다. 이것은 일반적으로 운영 환경의 404 템플릿으로 적합하지 않다.


Customizing error views

Testing custom error views

from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.test import SimpleTestCase, override_settings
from django.urls import path

def response_error_handler(request, exception=None):
    return HttpResponse('Error handler content', status=403)

def permission_denied_view(request):
    raise PermissionDenied

urlpatterns = [
    path('403/', permission_denied_view),
]

handler403 = response_error_handler

# ROOT_URLCONF must specify the module that contains handler403 = ...
@override_settings(ROOT_URLCONF=__name__)
class CustomErrorHandlerTests(SimpleTestCase):

    def test_handler_renders_template_response(self):
        response = self.client.get('/403/')
        # Make assertions on the response here. For example:
        self.assertContains(response, 'Error handler content', status_code=403)

0개의 댓글