장고앱을 만드는 순서가 좀 애매한 부분이 있다 ...


"urls 패턴정의가 먼저냐 뷰생성이 먼저냐 ?" 인데...


urls 패턴을 정의하려면 뷰이름이 필요하고 

뷰를 만들고 호출하려면 urls 패턴이 먼저 정의 되야하고... 


순서가 애매하다 보니 자주 실수 하는것이 urls 패턴에 정의된 뷰이름과 실제 작성한 뷰함수이름이 틀려서 에러가 발생하거나 

뷰함수만 작성하고 urls 패턴을 정의 하지 않아서 페이지가 안보이는 경우가 있다. 약간의 삽질일 수 있겠다.

 

그래서 장고가 익숙하지 않는 사람이라면(나) 빈페이지라도 동작 할 수 있는 구조를 만들어 페이지 열림을 확인하고 

나머지 코딩을 진행해하는 것이 좋다.


1. 일단 글목록 뷰 테스트를 위한 앱을 하나 생성하자

(개인적으로다가 manager.py 에서 startapp param 으로 인덱스뷰이름도 추가적으로 받아서 자동으로 views.py, urls.py 파일을 만들어 줬음 좋겠다 -_-;)

]# manager.py startapp catalog index 

위처럼 커맨드를 입력하면 아래처럼 수행되게...


]# cd /home/myproject
]# /usr/local/python3.4/bin/python3 manage.py startapp catalog
]# tree /home/myproject
/home/myproject
├── myproject
│?? ├── __init__.py
│?? ├── settings.py
│?? ├── urls.py
│?? └── wsgi
├── catalog
│?? ├── __init__.py
│?? ├── admin.py
│?? ├── apps.py
│?? ├── migrations
│?? │?? ├── __init__.py
│?? ├── models.py
│?? ├── tests.py
│?? └── views.py
└── manage.py

]# cat <<EOF > catalog/urls.py
from django.conf.urls import url
from .views import index

urlpatterns = [
    url(r'^$', index),
]
EOF

]# cat <<EOF > catalog/views.py
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello world")
EOF


2. catalog 앱을 프로젝트에서 인식 할 수 있도록 INSTALLED_APPS 에 추가한다.

]# vi myproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'catalog',
]


3. catalog 앱에서 사용할 catalog/urls.py 파일을 프로젝트 myproject/urls.py 에 include 해준다

]# vi myproject/urls.py
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^catalog/', include('catalog.urls')),
]

/usr/local/python3.4/bin/python3 manage.py runserver 0.0.0.0:8080

   

4. django 를 실행하고  페이지 열림을 확인한다.

http://127.0.0.1:8080/catalog/



5. 리스트페이지에서 보여줄 모델을 작성해보자

]# cat <<EOF > catalog/models.py
from django.db import models

class GuestBook(models.Model):

    auth = models.CharField(max_length=20)
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-id']
EOF

]# /usr/local/python3.4/bin/python3 manage.py makemigrations catalog
]# /usr/local/python3.4/bin/python3 manage.py migrate


6. GuestBook 모델에 데이터를 넣어보자

/usr/local/python3.4/bin/python3 manage.py shell
>>> from catalog.models import GuestBook
>>> for i in range(1,1001):
...     GuestBook.objects.create(title='{} 째글입니다'.format(i), auth='관리자', content='{} 째 글입니다'.format(i))
>>> GuestBook.objects.all()


7. GuestBook 모델을 갖고 오는 뷰와 템플릿을 작성해보자.

cat <<EOF > catalog/views.py
> from django.shortcuts import render
> from django.http import HttpResponse
> from .models import GuestBook
> def index(request):
>     guest_book_list = GuestBook.objects.all()
>     return render(request, 'catalog/index.html', {'guest_book_list': guest_book_list})
> EOF

cat <<EOF > catalog/templates/catalog/index.html 
<!DOCTYPE html>
<html lang="en">
<head>
  <title>GuestBook Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
  <h2>GuestBook</h2>
  <ul class="list-group">
    {% for guest_book in guest_book_list %}
      <li class="list-group-item">{{ guest_book.title }}</li>
    {% endfor %}
  </ul>
</div>

</body>
</html>
EOF



8. 위그림처럼 모든 게시물이 쭉 출력이 되므로 django의 Paginator 를 사용하여 페이징을 붙여 보자.

# catalog/views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import GuestBook
from django.core.paginator import Paginator

def index(request):
    """
    GET 방식으로 page 변수를 받는다.
    """
    page = request.GET.get('page''1')
    if len(page) == 0: page = '1'
    if type(page) != int : page = int(page)

    """
    guestbook queryset 얻는다.

    """

    guest_book_list = GuestBook.objects.all()

    """
    guest_book_list 를 10개씩 paging 한다.
    """
    num = 10
    guest_book_paginator = Paginator(guest_book_list, num)
    guest_book_page = guest_book_paginator.page(page)

    """
    현재페이지가 속해있는 페이지구룹(리스트)를 구하여 페이지네비게이터로 사용한다.
    page 페이지와 제일 가까운 num 의 배수를 구하여 시작페이지인덱스를 구하고 
    시작페이지인덱스에 num 을 더하여 마지막페이지인덱스를 구한다.
    """
    for i in reversed(range(1,page+1)):
        if i%num == 1:
            start_page_index = i
            break
    end_page_index = min(start_page_index + num, max(guest_book_paginator.page_range)+1)
    page_list = range(start_page_index, end_page_index)

    """
    위 페이지네비게이터를 구하는 방법이 마음에 안든다면 간단한 수식을 이용해서도 구현할수 있다.
    참조: https://jupiny.com/2016/11/22/limit-pagination-page-numbers-range/

    max_index = len(guest_book_paginator.page_range)
    start_index = int((page - 1) / num) * num
    end_index = start_index + num
    if end_index >= max_index:
        end_index = max_index
    page_list = guest_book_paginator.page_range[start_index:end_index]
    """
    return render(request, 'catalog/index.html', {'guest_book_list': guest_book_page, 'page_list': page_list})


# catalog/templates/catalog/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <title>GuestBook Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
  <h2>GuestBook</h2>
  <ul class="list-group">
    {% for guest_book in guest_book_list %}
      <li class="list-group-item">{{ guest_book.title }}</li>
    {% endfor %}
  </ul>
  <ul class="pagination">
    {% if guest_book_list.has_previous %}
      <li>
        <a href="?page={{ guest_book_list.previous_page_number }}">
          <span>Previous</span>
        </a>
      </li>
    {% else %}
      <li class="disabled">
        <a href="#">
          <span>Previous</span>
        </a>
      </li>
    {% endif %}

    {% for page in page_list %}
      <li {% if page == guest_book_list.number %}class="active"{% endif %}>
        <a href="?page={{ page }}">{{ page }}</a>
      </li>
    {% endfor %}

    {% if guest_book_list.has_next %}
      <li>
        <a href="?page={{ guest_book_list.next_page_number }}">
          <span>Next</span>
        </a>
      </li>
    {% else %}
      <li {% if not guest_book_list.has_next %}class="disabled"{% endif %}>
        <a href="#">
          <span>Next</span>
        </a>
      </li>
    {% endif %}
  </ul>
</div>

</body>
</html>


결과페이지

http://sdevvm001.cafe24.com:8080/catalog/ 

+ Recent posts