[Request 객체]


REST FRAMEWORK는 일반 HttpRequest 를 확장하고 Request Parsing에 있어서 좀더 유연한 방법을 제공합니다.


Request 객체의 핵심기능은 request.data 속성입니다. 이것은 request.POST와 유사합니다. 그러나 WEB API에 있어서 훨씬더 유용합니다.


request.POST  # 오직 form Data만 핸들링가능. 오직 POST방식만 동작.
request.data  # 속성 데이터를 핸들링.  POST, PUT, PATCH 방식에 동작.

[Response 객체]


REST FRAMWORK는 또한 Response 객체도 도입했는데 이것은 TemplateResponse 타입으로 랜더링 되지 않은 콘텐츠를 사용하고 콘텐츠를 올바르게 가공하여 클라이언트에게 올바른 콘텐츠를 반환 할 수 있도록 합니다.



return Response(data)  # 클라이언트가 요청한 타입으로 컨텐츠를 리턴합니다.

[상태코드]


View에서 HTTP 상태 코드를 사용한다고 해서 분명하게 확인 할 수 있는 것은 아니며, 오류 코드를 통지하는 것이 쉽지는 않습니다. REST FRAMEWORK는 각 상태코드에 대해서 보다 명확히 식별자를 제공합니다. 예를들면 status 모듈 안의  HTTP_400_BAD_REQUEST 입니다. 숫자 식별자를 사용하는 것 보다 전체적으로 이러한 방식을 사용하는것이 훨씬 효과적입니다.


[ API views ]


REST FRAMEWORK는 API 보기를 작성하는데 사용할 수 있는 2개의 Wrapper 를제공합니다.

1. 함수 기반 View 작업을 위한 @api_view 데코레이터

2. 클래스 기반 View 작업을 위한 APIView 클래스


이러한 Wrapper는 Reqest 인스턴스를 전달 받는지 확인하는 것과 같은 몇가지 기능을 제공합니다. 그리고 Content를 가공 할 수 있도록 컨텍스트를 Response객체에 추가합니다.


해당 랩퍼는 405 Methond Not Allowed 와 같은 허용하지 않는 응답을 리턴하는 것과 같은 동작도 제공합니다.


request.data에 엑세스 할떄 발생하는 모든 ParseError 예외를 처리할 수도 있습니다.


[실전]


이제 위의 구성요소들을 사용해서 몇가지 예를 작성해보겠습니다.


첫번째 포스팅에서 사용했던 예제를 사용하겠습니다.


기존의 snippets/view.py를 열고 내용을 아래로 대체합니다.


from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


@api_view(['GET', 'POST'])
def snippet_list(request):
    """
    List all snippets, or create a new snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

방금 삭제한 소스코드 보다 지금의 예제는 훨씬더 세련되어져 있습니다. 코드가 좀더 간결해지고, Forms API를 사용하는 경우와 매우 비슷합니다. 또한 응답의 의미를 분명하게 해주는 상태코드를 사용하고 있습니다.


list를 작성했으니 detail을 작성해볼게요.


@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a snippet instance.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

위의 예제들은 일반적으로 Django View의 작업과 크게 다르지 않다는 것을 알수 있습니다.

더이상 특정 콘텐츠에 대한 타입에 대한 요청이나 응답을 명시적으로 묶어두지 않습니다.

request.data는 들어오는 json 요청을 처리할 수 있지만, 다른 형식도 처리할 수 있습니다.

마찬가지로 data로 응답 객체를 반환하지만, REST FRAMEWORK가 Response를 올바른 콘텐츠로 랜더링 하도록 허용합니다.


[ URL에 접미사 추가하기 ]


어떤 방식인지 한마디로 설명하자면 http://example.com/api/items/4.json.과 같이 처리 할수 있다는 말입니다.


list와 detail 2가지 view 모두에 format 키워드 인수를 추가하는것으로 시작합니다.


def snippet_list(request, format=None):
def snippet_detail(request, pk, format=None):
이제 urls.py 파일을 약간 손보기로 하겠습니다. format_suffix_patterns 를 추가해줍니다.


from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

이러한 추가 URL 패턴을 반드시 추가 할필요는 없지만, 특정 형식을 간단하고 명확하게 참조 할 수 있도록 합니다.


[결과를 봅시다]


첫번쨰 포스트에서 테스트했던것 처럼 테스트해보세요. 첫번째 포스트와 비슷하게 작동할 겁니다. 유효하지 않은 request 에 대해서 훨씬 nice하게 error을 핸들링 할 수 있습니다.


http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK
...
[
  {
    "id": 1,
    "title": "",
    "code": "foo = \"bar\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  },
  {
    "id": 2,
    "title": "",
    "code": "print \"hello, world\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  }
]

Accept 헤더를 사용해서 응답의 형식을 제어할수도 있죠


http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML

또는 format 접미사를 추가해도 됩니다.


http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # Browsable API suffix

마찬가지로 Content-Type 헤더를 사용해서 보내는 요청의 형식을 제어할수 있습니다.


# POST using form data
http --form POST http://127.0.0.1:8000/snippets/ code="print 123"

{
  "id": 3,
  "title": "",
  "code": "print 123",
  "linenos": false,
  "language": "python",
  "style": "friendly"
}

# POST using JSON
http --json POST http://127.0.0.1:8000/snippets/ code="print 456"

{
    "id": 4,
    "title": "",
    "code": "print 456",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

위의 http 요청에 --debug 스위치를 추가하면 요청 헤더에서 요청 유형을 볼 수 있습니다.



Posted by C마노
,

원래는 Django 자체에 관한것을 계속적으로 포스팅하고 있었지만,  RESTFRAMEWORK를 실제로 사용할 일이 생겨서 정리차원으로 RestFulFramwork 공식 홈페이지에서 제공하는 튜토리얼을 제가 공부한 방식대로 번역한 글입니다.


== 환경설정 ==


1. virtual env 설정.


virtualenv env
source env/bin/activate

2. django와 restfulframwork 설치.


pip install django
pip install djangorestframework
pip install pygments # Syntax Highlight용.

프로젝트를 시작해봅시다.


cd ~
django-admin.py startproject tutorial
cd tutorial

app을 하나 만들어주시고~

python manage.py startapp snippets
rest_framework와 방금만든 snippets를 settings.py안의 INSTALL_APPS에 추가해봅시다.


INSTALLED_APPS = (
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
)

[모델 만들기]


간단하게 snippet 모델을 한번 만들어 보겠습니다.


snippets/models.py에 들어가서 해당 파일을 수정해봅시다.


from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())


class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ('created',)

그후 makemigration과 migrate를 해줍시다~.


python manage.py makemigrations snippets
python manage.py migrate

[직렬화 클래스 만들기]


WEB으로 API를 만들기 전에 중요한 일은 JSON데이터를 파이썬에서 제공하는 Dictionary객체로 직렬화하고 비직렬화 하는 방법이 제일 중요할겁니다. 가장 기초적이기도 하구요.

Django에서 제공하는 Model의 형식과 비슷한 serializers.py를 선언해서 작업을 수행할 수 있습니다.

snippets 디렉토리에 serializers.py 라는 파일을 만들고 아래를 추가해주세요.


from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    def create(self, validated_data):
        """
        Snippet 인스턴스를 생성하고 리턴합니다. 검증된 데이터가 주어집니다.
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        존재하는 Snippet인스턴스를 업데이트하거나 리턴합니다. 검증된 데이터가 주어집니다.
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

위의 부분은 serialize / deserialize 되는 필드를 정의하는 겁니다.

create() 및 update() 메서드는 serializer.save()를 호출 할때, 인스턴스가 create 되거나 update되는것을 정의합니다.


serializer 클래스는 Django Form 클래스와 비슷하며, required, max_length 및 default와 같은 여러가지 필드에 유효성 검사 Flag를 포함 합니다.


[ 직렬화 / 비직렬화 방법 ] 


우선 해당 방법을 배우기 전에 django의 shell에 접속합니다.

python manage.py shell
그리고 아래의 코드를 한번 입력해 봅시다.

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo = "bar"\n')
snippet.save()

snippet = Snippet(code='print "hello, world"\n')
snippet.save()

해당 코드에 대한 Snippet을 생성하였습니다.


해당 코드를 한번 serialize 해보겠습니다.


serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}

위의 시점에서 모델 인스턴스를 Python 에서 제공하는 딕셔너리 데이터 유형으로 변환하였고, 직렬화를 마루리 하기위해서 데이터를 json으로 변환합니다.


content = JSONRenderer().render(serializer.data)
content
# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'

자 여기까지는 OK이라고 가정하고 그렇다면 JSON 데이터를 Python 딕셔너리 타입으로 바꾸려면 어떻게해야할까요?


from django.utils.six import BytesIO

stream = BytesIO(content)
data = JSONParser().parse(stream)

우선 JSONParser를 사용해서 해당 stream을 파싱한 후에,

SnippetSerializer에 해당 값을 주입해서 완전한 객체 인스턴스로 복원시킵니다. (아래코드를 보세요)


serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
serializer.save()
# <Snippet: Snippet object>

또한 Django의 쿼리셋을 model대신에 직렬화 할 수도 있습니다.

이럴 때는 간단하게 many=True를 매개변수에 집어넣으면 됩니다.


serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]

[ ModelSerializers 사용 ]


SnippetSerializer 클래스는 Snippet 모델에 포함된 많은 정보를 복제하고 있습니다. 그렇지만 실제로 보면 코드가 너무 복잡합니다. 코드의 내용만 좀 다를뿐 중복된 내용도 존재하구 있구요.

Django에서 From 클래스와 ModelForm 클래스를 제공하는 것 처럼 RESTFUL FRAMEWORK도 Serializer클래스와 ModelSerializer 클래스를 모두 지원합니다.


자, 그럼 ModelSerializer 클래스를 사용해서 serializer를 리팩토링 하는 방법을 실제로 한번 해보겠습니다.

파일 snippets / serializers.py 파일을 다시 열고, SnippetSerializer 클래스를 바꿔줍니다.


class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

serializer 가 가지고 있는 장점 중 하나는 serializer 인스턴스의 모든 필드를 검사 할 수 있다는 점입니다. 

Django 쉘을 python manage.py 쉘로 엽니다.


from snippets.serializers import SnippetSerializer
serializer = SnippetSerializer()
print(repr(serializer))

* ModelSerializer 는 아래와 같은 기능을 합니다.

1. 자동으로 필드 셋을 결정해줍니다.

2. create 와 update 메소드를 기본적으로 구현해줍니다.


[ 실제로 Django 의 View에 적용해보기]


snippets/views.py 파일에 아래를 추가합니다.


from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

API의 루트는 모든 snippet을 나열하거나 새로운 snippet을 만드는것을 지원하는 view 입니다.


@csrf_exempt
def snippet_list(request):
    """
    List all code snippets, or create a new snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == 'POST':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)

만약 CSRF 토큰이 없는 클라이언트로부터 이 View로 POST를 할 수 있기를 원한다면 View에다가 csrf_exempt 데코레이터를 추가해줘야 합니다.

이것은 일반적으로 이렇게 구현하면 아니지만, REST Framwork view는 실제로 이러한 방법을 사용하지 않지만 지금은 설명을 위해 사용할것입니다.


또한 개별 snippet에 해당하는 view가 필요하며, snippet을 검색 업데이트 삭제 하는데 사용 되어질 수 있습니다.


@csrf_exempt
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return JsonResponse(serializer.data)

    elif request.method == 'PUT':
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(snippet, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data)
        return JsonResponse(serializer.errors, status=400)

    elif request.method == 'DELETE':
        snippet.delete()
        return HttpResponse(status=204)

마지막으로 이러한 view을 연결해봅시다. snippets/urls.py 파일을 만듭니다.


from django.conf.urls import url
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
]

그리고 totorials/urls.py에 해당 라인을 추가합니다.


from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('snippets.urls')),
]

그렇지만 현재 문제점이 존재하기는 합니다. 정형화된 json을 보내지 않거나 request에 정상적인 데이터를 넣지않으면 500에러가 발생합니다. 해결방법은 다음 포스팅에서 정리하도록 하겠습니다.


[ API 테스팅 시도하기 ]


우선 shell을 닫고 quit()


django를 실행합니다.


python manage.py runserver

Validating models...

0 errors found
Django version 1.8.3, using settings 'tutorial.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

그뒤 아래 URL로 요청해보면.


http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK
...
[
  {
    "id": 1,
    "title": "",
    "code": "foo = \"bar\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  },
  {
    "id": 2,
    "title": "",
    "code": "print \"hello, world\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  }
]

ID로도 조회가 가능합니다.~


http http://127.0.0.1:8000/snippets/2/

HTTP/1.1 200 OK
...
{
  "id": 2,
  "title": "",
  "code": "print \"hello, world\"\n",
  "linenos": false,
  "language": "python",
  "style": "friendly"
}

우선은 여기까지로 포스팅을 끝내고 2부를 계속 포스팅하도록 하겠습니다.

Posted by C마노
,

저번 포스트에서 포스팅 했듯이 시스템에는 기본 제공 태그와 필터가 함께제공됩니다.

이번 포스트에서는 가장 일반적인 태그와 필터를 정리해보겠습니다.


[태그]


* if / else


{% if %} 태그는 변수를 평가합니다. 


{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% endif %}

An `{% else %}` tag is optional:

{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% else %}
<p>Get back to work.</p>
{% endif %}

elif 절도 사용 가능하죠.


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

{% if %} 태그는 and, or 또는 not을 사용하여 여러 변수를 테스트하거나 주어진 변수를 무효화 합니다.


{% if athlete_list and coach_list %}
<p>Both athletes and coaches are available. </p>
{% endif %}

{% if not athlete_list %}
<p>There are no athletes. </p>
{% endif %}

{% if athlete_list or coach_list %}
<p>There are some athletes or some coaches. </p>
{% endif %}

{% if not athlete_list or coach_list %}
<p>There are no athletes or there are some coaches. </p>
{% endif %}

{% if athlete_list and not coach_list %}
<p>There are some athletes and absolutely no coaches. </p>
{% endif %}

동일한 태그 내에서 and와 or절을 모두 사용할 수 있으며 and 가 or 보다 우선순위가 높습니다.


{% if athlete_list and coach_list or cheerleader_list %}

결과는 아래와 같죠


if (athlete_list and coach_list) or cheerleader_list

하지만 if 문에서 ()의 사용은 잘못된 방법입니다. 즉 다른 연산자를 결합하지 마세요.


만약 우선 순위를 나타 내기 위해서 괄호가 필요한 경우는 중첩된 if 태그를 사용해야 합니다.


조작 순서 제어에 괄호를 사용하는 것은 지원되지 않습니다.


괄호가 필요하다고 생각되면 템플릿 외부에서 먼저 로직을 수행하고 그 결과를 전용 템플릿 변수로 전달하는 방법을 먼저 고려하세요..


또는 아래와 같이 중첩된 태그를 사용하세요.


 {% if athlete_list %}
     {% if coach_list or cheerleader_list %}
         <p>We have athletes, and either coaches or cheerleaders! </p>
     {% endif %}
 {% endif %}

동일한 논리연산자를 여러번 사용하는 것은 좋지만, 다른 연산자를 결합 할 수는 없습니다. 예를 들면 아래와 같습니다.


{% if athlete_list or coach_list or parent_list or teacher_list %}

각 {% if %}와 {% endif %}를 닫아야 합니다. 그렇지 않으면 Django는 TemplateSyntaxError를 던집니다.


* for


{% for %} 태그를 사용하면 시퀀스의 각 항목을 반복할 수 있습니다.


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

반대방향으로 루핑하려면 태그에 반전을 추가하세요


{% for athlete in athlete_list reversed %}
...
{% endfor %}

for태그를 중첩할 수도 있습니다.


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

리스트 안의 리스트를 반복해야 하는 경우 각 하위 목록의 값을 개별 변수로 따낼수 있습니다.


예를 들면 컨텍스트에 point라고 불리는 (x,y) 좌표 목록이 있으면 다음을 사용하여 점 목록을 출력 할 수 있습니다.


{% for x, y in points %}
<p>There is a point at {{ x }},{{ y }}</p>
{% endfor %}

딕셔너리의 항목에 엑세스하는 경우에도 유용하게 사용할 수 있습니다.


{% for key, value in data.items %}
{{ key }}: {{ value }}
{% endfor %}

매우 일반적인 패턴은 반복하기 전에 list의 크기를 확인하고 목록이 비어있는 경우에는 특수 텍스트를 출력하는 방법입니다.


{% if athlete_list %}

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

{% else %}
<p>There are no athletes. Only computer programmers.</p>
{% endif %}

이 패턴은 매우 일반적이므로 for 태그는 목록이 비어있는 경우 출력할 내용을 정의할수 있는 {% empty %} 절을 지원합니다!.


{% for athlete in athlete_list %}
<p>{{ athlete.name }}</p>
{% empty %}
<p>There are no athletes. Only computer programmers.</p>
{% endfor %}

알아 두어야 할 것은 break 와 continue를 지원하지 않는 다는것을 유념하십시오.

각 {% for %} 루프 내에서 forloop이라는 템플릿 변수에 엑세스 할 수 있습니다.


이 변수는 루프의 진행상황에 대한 정보를 제공하는 몇가지 속성이 있습니다.


forloop.counter는 루프가 돈 count 입니다. 1부터 시작합니다.


 {% for item in todo_list %}

  <p>{{ forloop.counter }}: {{ item }}</p>
  {%  endfor %}

forloop.counter0 는 1이아니고 0부터 시작하는것만 빼고는 위와같습니다.

forloop.revcounter는 항상 루프의 나머지 항목수를 나타냅니다. 마지막루프를 돌때 1입니다.

forloop.revcounter0는 마지막 0입니다. 위와같습니다.

forloop.first는 루프를 처음 실행 할 경우 True입니다. (특수 한경우 처리에 편합니다.)



  {% for object in objects %}

  {% if forloop.first %}<li class="first">{% else %}<li>
      {% endif %}
      {{ object }}
  </li>
  {% endfor %}

forloop.last 동일한데 마지막입니다.


{% for link in links %}
  {{ link }}{% if not forloop.last %} | {% endif %}
{% endfor %}

위의 결과는 아래처럼 나올 수 있습니다.


  Link1 | Link2 | Link3 | Link4

단어사이에 쉼표도 넣을수 있죠


  <p>Favorite places:</p>
      {% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}
      {% endfor %}

forloop.parentloop 부모 실행에 대한 forloop 객체에 대한 참조입니다.


 {% for country in countries %}
  <table>
      {% for city in country.city_list %}
      <tr>
          <td>Country #{{ forloop.parentloop.counter }}</td>
          <td>City #{{ forloop.counter }}</td>
          <td>{{ city }}</td>
      </tr>
      {% endfor %}
  </table>
  {% endfor %}

forloop 변수는 루프 내에서만 사용할 수 있습니다.

템플릿 파서가 {% endfor %}에 도달하면 forloop를 소멸시켜버립니다.


* ifequal/ifnotequal


<<우선 여기까지만 적기로 했습니다.>>

'Python > Django' 카테고리의 다른 글

[Django] RestFrameWork 튜토리얼 - 2. Request와 Response  (0) 2017.03.10
[Django] RestFrameWork 튜토리얼 - 1. 직렬화  (0) 2017.03.10
[Django] 템플릿  (0) 2017.03.08
[Django] Dynamic URL  (0) 2017.03.08
[Django] VIew와 URL conf  (0) 2017.03.07
Posted by C마노
,