템플릿 상속을 통해서 템플릿 코드를 재사용 할 수 있다. 부모 템플릿은 템플릿의 뼈대를 만들어주고 {% block %} 태그를 통해 하위로 상속해줄 부분을 지정해주면, 자식 템플릿은 부모 템플릿의 뼈대는 그대로 재사용하고 이 때는 {% extends "부모 템플릿.html" %} 태그를 사용하고 {% block %} 부분만 채워주면 된다.

 

block.super는 부모 그대로 사용한다는 의미이다.

 

- base.html

<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    {#  {% load static %} #}
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
    <title>{% block title %}My Amazing Site{% endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Project_Home</a></li>
            <li><a href="/admin/">Admin</a></li>
        </ul>
        {% endblock %}
        <br>
    </div>

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

 

- base_books.html

<!-- base_books.html -->
{% extends "base.html" %}

{% block title %}Books Application Site{% endblock %}

{% block sidebar %}
{{ block.super }}
<ul>
    <li><a href="/books/">Books_Home</a></li>
</ul>
{% endblock %}

 

- index.html

<!-- book/index.html -->
{% extends "base_books.html" %}

{% block content %}
    <h2>Books Management System</h2>
    <ul>
        {% for modelname in model_list %}
{% with "books:"|add:modelname|lower|add:"_list" as urlvar %}
            <li><a href="{% url urlvar %}">{{ modelname }}</a></li>
{% endwith %}
        {% endfor %}
    </ul>
{% endblock content %}

 

-결과 화면

 

 

출처: 한빛미디어, Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍

템플릿 주석을 작성하는 방법은 2가지 방법이 있다.

1번째는 한줄 주석 2번째는 여러줄 주석

 

- 한줄 주석

{# Hello #}world
{# {% if foo %}bar {% else %} #} 

 

- 여러줄 주석

{% comment "note" %}
<p>Commented out text here</p>
{% endcomment %}

 

- HTML 이스케이프

템플릿 코드를 렌더링하여 HTML 텍스트를 만들 때, 템플릿 변수에 HTML 태그가 들어 있는 경우에 그대로 렌더링하면 원하는 결과가 나오지 않을 수 있다. 그리고 이점을 이용하여 XSS 공격이 이루어진다.

 

장고는 자동 이스케이프 기능을 제공하고 있다.

  • <  -> &lt;
  • >  -> &gt;
  • ' (single quote)  -> &#39;
  • " (double quote)  -> &quot;
  • &  -> &amp;

그렇기 때문에 자동 이스케이프 기능을 비활성화 할 수 있는 2가지 방법이 있다.

 

- safe 필더를 이용

This will not be escaped: {{ data|safe }}

safe 필터는 템플릿 변수에만 영향을 미친다.

 

- {% autoescape %} 태그를 이용

{% autoescape off %}
Hello {{ name }}
{% endautoescape %}

autoescape 태그 영역안에서는 자동 이스케이프 기능을 비활성화 한다.

추가적으로 필터의 인자에 사용되는 스프링 리터럴에는 자동 이스케이프 기능이 적용되지 않는다.

 

출처: 한빛미디어, Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍

'Django' 카테고리의 다른 글

14. 폼 클래스  (0) 2021.04.08
13. 템플릿 상속  (0) 2021.04.08
11. Template Tag(템플릿 태그)  (0) 2021.04.08
10. Template 구성 - 파일 구조, 템플릿 필터  (0) 2021.04.08
9. View 구성 - 함수형 뷰 구성  (0) 2021.04.08

템플릿 태그는 {% tag %} 형식을 가진다.

 

- {% for %} 태그

<ul>
{% for athlete in athlete_list %}
	<li>{{ athlete.name }}<li>
{% endfor %}
</ul>

리스트에 담겨 있는 항목들을 순회하면서 출력

변수명 설명
forloop.counter 현재까지 루프를 실행한 루프 카운트(1부터 카운트함)
forloop.counter() 현재까지 루프를 실행한 루프 카운트(0부터 카운트함)
forloop.revcounter 루프 끝에서 현재가 몇 번째인지 카운트한 숫자(1부터 카운트)
forloop.revcounter() 루프 끝에서 현재가 몇 번째인지 카운트한 숫자(0부터 카운트)
forloop.first 루프에서 첫 번째 실행이면 True 값을 가짐
forloop.last 루프에서 마지막 실행이면 True 값을 가짐
forloop.parentloop 중첩된 루프에서 현재의 루프 바로 상위의 루프를 의미함

 

- {% if %} 태그

{% if athlete_list %}
	Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
	Athletes should be out of the locker room soon!
{% else %}
	No athletes.
{% endif %}

변수를 평가하여 조건이 True이면 바로 아래의 문장이 출력된다. 

{% if %} 태그에는 불린 연산자를 사용할 수 있다. ex) and, or, not, and not, ==, !=, <, >, <=, >=, in, not in

 

- {% csrf_token %} 태그

<form action="." method="post">
	{% csrf_token %}

POST 방식의 <form>을 사용하는 템플릿 코드에서는 CSRF 공격을 방지하기 위해 이 태그를 사용한다.

이 태그를 사용하면 내부적으로 CSRF 토크값의 유효성을 검증하여 만일 토큰 검증에 실패하면 사용자에게 403에러는 보여준다.

한 가지 주의할 점은 CSRF 토큰값이 유출될 수도 있으므로, 외부 URL로 보내는 <form>에는 사용하지 않도록 한다.

 

※CSRF 공격이란

CSRF(Cross-Site Request Forgery)는 사이트 간 요청 위조 공격이라는 뜻이다. 특정 웹 사이트에서 이미 인증을 받은 사용자를 이용하여 공격을 시도한다. 인증을 받은 사용자가 공격 코드가 삽입된 페이지를 열면 공격 대상이 되는 웹 사이트는 위조된 공격 명령이 믿을 수 있는 사용자로부터 발송된 것으로 판단하게 되어 공격을 받게 된다.

 

- {% url %} 태그

{% url 'namespace:view-name' arg1 arg2 %}
  • namespace : urls.py 파일의 include() 함수 또는 app_name 변수에 정의한 이름 공간
  • view-name : urls.py 파일에서 정의한 URL 패턴 이름
  • argN: 뷰 함수에서 사용하는 인자로, 없을 수도 있고 여러 개인 경우 공백으로 구분

 

<form action={% url 'polls:vote' question.id %} method="post">

주된 목적은 템플릿 코딩을 할때 URL을 하드코딩하는 것을 방지 하기 위해서이다. 이 코드는 다음의 코드와 유사한 코드이다.

 

<form action="/polls/3/vote/" method="post">

 

 - {% with %} 태그

{% with total=business.employess.count %}
	{{ total }} people works at business
{% endwith %}

 

with 태그는 with 영역에서만 유효한 변수를 정의 하여 사용할 수 있다. 이 태그는 DB를 조회하는 것과 같은 부하가 큰 동작을 결과를 저장해 둠으로써 동일한 동작에 대한 부하를 줄이기 위해 사용한다.

 

- {% load %} 태그

{% load somelibrary package.otherlibrary %}

사용자 정의 태그 및 필터를 로딩해준다.

 

출처: 한빛미디어, Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍

template 파일 구성

Template File은 다른 동일한 이름의 리소스와의 구분하기 위해서 [app_name]/templates/[app_name]의 디렉토리 하위에 존재한다.

 

 

- detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>상세 페이지</title>
</head>
<body>
<h1>{{ question.question_text}}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p> {% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
    {% csrf_token %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"/>
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
    {% endfor %}
<input type="submit" value="투표하기">
</form>

</body>
</html>

 

-템플릿 변수

{{ variable }}

{{}} 문자로 변수를 감싸 해당 변수값을 출력할 수 있다. 변수명은 일반 프로그램밍의 변수 조건과 유사하게 문자, 숫자, 밑줄을 사용하여 이름을 정의할 수 있다.

 

장고의 템플릿 시스템에서 도트(.)는 파이썬 언어와는 조금 다르다. 템플릿 문법에서 도트(.)를 만나면 장고는 다음의 순서를 따른다.

ex) book.name

  • 사전 타입인지 확인 book['name']
  • 속성 값인지 확인 book.name
  • 리스트인지 확인 book[name]

-템플릿 필터

{{ name|lower}}

name의 변수값을 소문자로 변환하여 출력

 

{{ text|escape|linebreaks }}

text 변수값 중에서 특수 문자를 제거하고 , 그 결과에 <p>를 붙여준다.

 

{{ bio|truncatewords:30 }}

bio의 변수값 중에서 앞에 30개의 단어만 보여주고, 줄 바꿈 문자는 모두 제거

 

{{ list|join:" // " }}

필터의 인자에 빈칸이 있는 경우 따옴표로 묶어준다. list가 ['a','b','c']라면 결과는 "a // b // c"가 된다.

 

{{ value|default:"nothing"}}

value 변수값이 False이거나 없는 경우 "nothing"으로 출력

 

{{ value|length }}

value 값의 길이를 반환한다. 변수 값이 스트링이나 리스트인 경우도 가능하다.

 

{{ value|striptags }}

value 변수값에서 HTML 태그를 모두 없애줍니다. 그러나 완벽하지 않다.

 

{{ value|pluralize }}

value 변수값이 복수명 접미사 s를 붙여준다. 

 

{{ value|pluralize:"es" }} 또는 {{ value|pluralize:"ies" }}

value 변수값이 복수이면 접미사 es 또는 ies를 붙여준다.

 

{{ value|add:"2" }}

변수에 더하기를 할 수 있습니다. 데이터 타입에 따라 결과가 다르므로 주의해야 한다.

 

{{ first|add:second }}
  • first="python", second="django"라면 결과는 "pythondjango"
  • first=[1,2,3], second=[4,5,6] 이라면 결과는 [1,2,3,4,5,6]
  • first="5", second="10"이라면 결과는 15

 

 

출처: 한빛미디어, Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍

주로 로직이 간단한 뷰를 구성할 때 함수형 뷰를 이용하여 신속하게 개발한다.

 

-Views.py

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404,render
from django.urls import reverse
from polls.models import Question, Choice

# 요청을 처리할 함수형 뷰의 인자는 request 를 가지고 있어야 한다.
def index(request):
    # Question 테이블에서 전체 레코드를 검색하여 pub_date 컬럼을 오름차순으로 정렬하여 마지막 5개 즉, 최근 5개를 가져옴
    latest_question_list = Question.objects.all().order_by('-pub_date')[:5]
    # 최근 5개의 리스트를 template 에게 넘겨주기 위해 딕셔너리 생성
    context = {'latest_question_list': latest_question_list}
    # render(요청 받은 request, 템플릿 파일, 전달할 데이터)
    return render(request, 'polls/index.html', context)


def detail(request, question_id):
    # URLconf 에서 설정된 question_id를 사용하여 해당 레코드가 존재하지 않으면 Http 404 익셉션을 발생  
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})


def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    # 폼의 데이터에 choice가 없으면 KeyError, 테이블에 해당 레코드가 없다면 DoesNotExist 
    except (KeyError, Choice.DoesNotExist):
        return render(request, 'polls/detail.html',{
            'question': question,
            'error_message': "선택한 선택지가 없습니다."
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # 리다이렉트 설정
        # reverse 함수를 사용하면 URLconf 에서 설정했던 name(별명)을 가지고 역으로 해당 URL로 변환한다.
        return HttpResponseRedirect(reverse('polls:results', args=(question_id,)))


def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request,'polls/results.html', {'question': question})

-urls.py

from django.urls import path
from polls import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/vote', views.vote, name='vote'),
    path('<int:question_id>/results', views.results, name='results'),
    path('yourname/', views.get_name, name='yourname'),
]

path 함수를 이용하여 URL패턴, 적용할 뷰의 함수, 별명(name)을 지정할 수 있다.

별명은 reverse 함수나 template에서 다른 뷰로 로직이 이동할 때 주로 사용하여 URL를 하드코딩하는 불편함을 없애준다.

 

  • 요청에 들어있는 URL이 urls.py 파일에 정의된 URL 패턴과 매칭되는지를 분석한다.
# 프로젝트의 urls.py
from django.contrib import admin
from django.urls import path, include
from djangoProject.view import AboutView
urlpatterns = [
    path('admin/', admin.site.urls),
    path('about/', AboutView.as_view()),
    path('polls/', include('polls.urls')),
    path('books/', include('books.urls')),

]

 

  • settings.py 파일의 ROOT_URLCONF 항목을 통해 최상의 URLconf(urls.py)의 위치를 설정한다.
  • urlpatterns 변수에 지정되어 있는 URL 리스트를 확인한다.
  • 우선 순위는 위에서부터 아래순이다.
  • 매치된 URL의 뷰를 호출. 뷰는 함수 또는 클래스의 메소드이다. 호출 시 HttpRequest 객체와 그리고, 매칭할 때 추출된 단어를 뷰로 넘겨준다.
  • URL 매칭에 실패하면 에러를 처리하는 뷰를 호출한다. 

 

-URLconf의 계층화

path('polls/', include('polls.urls')),
# 프로젝트 하위의 app의 urls.py
from django.urls import path
from polls import views

app_name = 'polls'
urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/vote', views.vote, name='vote'),
    path('<int:question_id>/results', views.results, name='results'),
    path('yourname/', views.get_name, name='yourname'),
]

프로젝트 urls.py에서 app urls.py를 include를하면 계층화 하여 관리할 수 있다. 이와 같이 구성하면 변경도 쉬워지고, 확장도 용이하다.

1개의 URLconf로 코딩하는 경우 app_name등이 변경될 경우 모든 패턴의 URL를 변경해야하지만 2개의 URLconf로 구성할 경우  상위 URLconf에서 하나의 패턴만 수정하면 된다.

 

 

- Path Converter

꺽쇠 부분(<>)을 말하는데. 기본적으로 제공하는 타입이 있고ㅡ 개발자가 추가로 타입을 등록할 수도 있다.

  • str: /(슬래시)를 제외한 모든 문자열과 매치된다. 타입이 지정되지 않았다면 디폴드로 str 타입을 사용
  • int: 0 또는 양의 정수와 매치된다. 매치된 정수를 파이썬의 int 타입으로 변환
  • slug: slug 형식의 문자열(ASCII, 숫자, 하이픈, 밑줄로만 구성됨)과 매치
  • uuid: UUID 형식의 문자열과 매치, 매치된 문자열은 파이썬은 UUID 타입으로 변환
  • path: /(슬래시)를 포함한 모든 문자열과 매치된다. 이는 URL 패턴의 일부가 아니라 전체를 추출하고자 할때 많이 사용한다.

- 정규 표현식(Regular Expression)

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),
]

(?P적용할 패턴)을 작성한다.

ex) r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$'

artlcles로 시작하고 year는 0부터 9까지의 4자리의 정수이고 month는 0부터 9까지의 2자리 정수 slug는 영문, 숫자 , 밑줄(_), 하이픈(-)  한 개 1번 이상 반복

 

- 정규표현식에 사용되는 문자들

표현 의미
.(Dot) 모든 문자 하나
^(Caret) 문자열의 시작
$ 문자열의 끝
[] []괄호에 있는 문자 하나, [akz]이면 a 또는 k 또는 z
[^ ] []괄호에 있는 문자 이외의 문자 하나. [^ab]이면 a와 b를 제외한 문자 하나
* 0번 이상 반복, {0,}와 동일
+ 1번 이상 반복, {1,}와 동일
? 0번 또는 1번 반복, {0,1}과 동일
{n} n번 반복
{m.n} 최소 m번에서 최대 n번까지 반복
| A|B이면 A 또는 B
[a-z] a에서 z까지 임의의 문자, 즉 영문 소문자 한 개
\d 숫자 한 개, [0-9]와 동일
\w 영문, 숫자 또는 밑줄(_) 한 개, [0-9a-zA-Z_]와 동일

 

출처: 한빛미디어, Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍

#models.py
from django.db import models


# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField('Author')
    publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE)
    publication_date = models.DateField()

    def __str__(self):
        return self.title


class Author(models.Model):
    name = models.CharField(max_length=50)
    salutation = models.CharField(max_length=500)
    email = models.EmailField()

    def __str__(self):
        return self.name


class Publisher(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=100)
    website = models.URLField()

    def __str__(self):
        return self.name

- Book 테이블 생성

컬럼:title, authors, publisher, publication_date

authors는 Book과 Author 테이블이 다대다 관계이므로 ManyToManyField를 사용했고 publisher 컬럼은 Publisher과 Book 테이블이 외래키 관계이기 때문에 ForeignKey를 사용하여 관계를 정의하여 주고 on_delete=model.CASCADE 파라미터를 통해 외래키 관련 레코드가 사라질 경우 해당 외래키와 관련된 레코드들이 지워지는 설정으로 데이터베이스 무결성을 지키기 위함이다.

 

- Author 테이블 생성

컬럼: name, salutation, email

 

- Publisher 테이블 생성

컬럼: name, address, website

 

__str__ 메소드는 admin 페이지에서 해당 레코드가 어떻게 보여질지를 설정할 수 있는 함수이다.

 

- Admin 페이지에 모델 등록하기 및 Admin 페이지 커스텀 하기

from django.contrib import admin
from polls.models import Question, Choice

# Choice 모델을 테이블 형식으로 Inline 생성
# 이것은 Question 모델을 추가할 때 Choice 모델을 같이 보기 위해 사용됨
# extra 2개씩 추가로 보여줌
class ChoiceInline(admin.TabularInline):
    model = Choice
    extra = 2


class QuestionAdmin(admin.ModelAdmin):
    # 필드를 분리하여 보여주기
    # 필드를 설명하는 제목, 필드명, 적용할 옵션
    # collapse: 필드내용 Hide/Show 기능 추가
    # fields = ['pub_date', 'question_text'] -> 등록 페이지에서 컬럼 순서 변경
    fieldsets = [
        ('Question Statement', {'fields':['question_text']}),
        ('Date Information', {'fields': ['pub_date'], 'classes': ['collapse']}),

    ]
    # 같이 볼 모델 클래스
    inlines = [ChoiceInline]
    # admin 페이지에서 보여질 테이블 컬럼
    list_display = ('question_text', 'pub_date')
    # 필터 위젯 추가
    list_filter = ['pub_date']
    # 검색 박스 표시
    search_fields = ['question_text']

# admin 사이트에 모델 등록
admin.site.register(Question, QuestionAdmin)
admin.site.register(Choice)

- 결과 화면

www.acmicpc.net/problem/18870

 

18870번: 좌표 압축

수직선 위에 N개의 좌표 X1, X2, ..., XN이 있다. 이 좌표에 좌표 압축을 적용하려고 한다. Xi를 좌표 압축한 결과 X'i의 값은 Xi > Xj를 만족하는 서로 다른 좌표의 개수와 같아야 한다. X1, X2, ..., XN에 좌

www.acmicpc.net

코드:

N = int(input())
data = list(map(int, input().split()))
sorted_data = list(sorted(set(data)))
result = {sorted_data[i]: i for i in range(len(sorted_data))}
# 제네레이터 생성하면서 출력
print(*[result[i] for i in data])

'Algorithm' 카테고리의 다른 글

이진탐색(Binary Search)  (0) 2021.04.16
BOJ - 15649번 - N과 M (1)  (0) 2021.04.15
BOJ - 11651번 - 좌표 정렬하기 2  (0) 2021.04.08
BOJ - 11650번 - 좌표 정렬하기  (0) 2021.04.08
BOJ - 10814번 - 나이순 정렬  (0) 2021.04.08

+ Recent posts