IT world

[Django] 24.02.21 Django 실습 본문

모두의 연구소(오름캠프)/AI 모델 활용 백엔드 개발 과정

[Django] 24.02.21 Django 실습

엄킹 2024. 2. 21. 16:45

Django 강의의 두번째 시간이다. 어제는 Django의 설치와 명령어, 간단한 예제를 만들었고, 오늘은 Django 실습을 통해 페이지를 만드는 실습을 진행했다.

 

Django 실습

실습 내용으로는 main 페이지 하나만이 아닌 여러 페이지를 만들고 관리하는 방법을 실습했다.

1. 예를 들어 쇼핑몰을 만들 예정으로 쇼핑몰을 만들 url 목록은 아래와 같다.

 

 'www.hojunshopping.com' => 잘 나가는 상품 10개 소개
 'www.hojunshopping.com/about' => 회사 소개
 'www.hojunshopping.com/product' => 상품 목록
 'www.hojunshopping.com/product/1'=> 상품 목록 상세 게시물
 'www.hojunshopping.com/contact' => 오시는 길
 'www.hojunshopping.com/qna' => Q&A 목록
 'www.hojunshopping.com/qna/1'=> Q&A 상세 게시물
 'www.hojunshopping.com/notice' => 자유게시판, 1:1게시판 선택 페이지
 'www.hojunshopping.com/notice/free' => 자유게시판 목록
 'www.hojunshopping.com/notice/free/1' => 자유게시판 상세 게시물
 'www.hojunshopping.com/notice/onenone' => 1:1 상담 안내
 'www.hojunshopping.com/notice/onenone/1'  => 1:1 상담 상세 게시물
 

 

2. 우선 main 앱과 그 외 앱을 정의했고, detail이 만들어지는 URL들은 detail이 생성되는 걸로 판단하여 총 4개의 앱을 만들었다. 즉 detail이 없는 '', about, contact는 main 앱에서 관리하고 나머지는 각각의 명칭으로 앱을 생성하였다.

# 터미널 작업입니다.

python manage.py startapp main    # detail 내용이 없는 것들은 main에 모아서 관리
python manage.py startapp product # detail 숫자가 존재하므로 별도로 관리
python manage.py startapp qna     # qna/x
python manage.py startapp notice  # notice/str/x

 

3. tutorialdjango > settings.py 에서 INSTALLED_APPS = [...] 값에 추가한 main, product, qna, notice 앱을 작성해주고 

tutorialdjango > urls.py를 수정했다.

아래 예시 코드에서 include()란 해당 url 경로로 접속이 되면 해당 앱의 urls에서 처리하겠다는 뜻이다. 즉 https://localhost/product/, https://localhost/product/1 처럼 product 경로로 접속하는 것들은 product app의 urls.py에서 관리하겠다는 뜻이고,  tutorialdjango > urls.py로 들어온 작업을 product > urls.py에서 처리한다.

각 url에 해당되는 내용들을 목적에 맞게 관리할 수 있다.

# tutorialdjango > urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("", include('main.urls')), 
    path("product/", include('product.urls')),
    path("qna/", include('qna.urls')),
    path("notice/", include('notice.urls')),
]

 

4. 위 코드처럼 include()를 사용하여 각 앱에서 처리하도록 설정했지만 start app을 통해 생성된 앱들은 urls.py가 자동으로 생성되지 않아 해당 파일을 추가해주고 작업을 해야한다.

product > urls.py을 생성했으며 해당 코드에서는 product/ 경로를 작성하지 않는다! 이미 tutorialdjango > urls.py에서 product의 경로로 접속한 것을 확인하고 처리했기 때문에 여기서는 그 이후의 경로에 대한 작업을  처리한다. 즉 ""인 것은

https://localhost/product/"" 의 경로이다. (https://localhost/product/ 경로는 이미 확인했기 때문에 그 이후 경로만 작성)

<int:pk>/ 코드는 상품 페이지는 1~2개만 존재하는 것이 아니라 수십, 수백개가 존재하는데 그것을 1.html, 2.html...n.html처럼 각각 만드는 것은 비효율적이다. 따라서 해당 문법을 통해 상세 페이지로 접속하는 값을 통해 해당 값에 대한 페이지를 동적으로 생성할 수 있다. https://localhost/product/1 로 접속했다면 pk 값은 1이 되고 1페이지에 대한 내용을 찾아 출력하면 된다.

# product > urls.py

from django.urls import path
from .views  import product, productdetails

urlpatterns = [
    path("", product), 
    path("<int:pk>/", productdetails),
]
# product > views.py

from django.shortcuts import render
from django.http import HttpResponse


def product(request):
    return HttpResponse("product Page")


def productdetails(request, pk):
    return HttpResponse(f"product Details Page: {pk}")

urls.py는 해당 경로로 접근 시 정의된 함수와 연결하고 views.py는 해당 경로의 페이지를 출력하기 위한 공간이다.

 

5. notice의 경우 free/1, onenone/1 과 같이 notice 내에 또 다른 경로가 나뉘어지고 세부 페이지가 출력된다. 

나 같은 경우 간단한 테스트용이기에 아래 코드 처럼 처리했다.

# notice > urls.py

from django.urls import path
from .views import details # free, freedetails, onenone, onenonedetails

urlpatterns = [
    # # 자유게시판 목록
    # path('free/', free),
    # # 자유게시판 상세 게시물
    # path('free/<int:pk>/', freedetails),
    # # 1:1 상담 안내
    # path('onenone/', onenone),
    # # 1:1 상담 상세 게시물
    # path('onenone/<int:pk>/', onenonedetails),
    
    # 다중 작성 가능
    path('<str:word>/<int:pk>/', details),
]
# notice > views.py

from django.shortcuts import render
from django.http import HttpResponse


# def free(request):
#     return HttpResponse("free Page")


# def freedetails(request, pk):
#     return HttpResponse(f"free Details Page: {pk}")


# def onenone(request):
#     return HttpResponse("onenone Page")


# def onenonedetails(request, pk):
#     return HttpResponse(f"onenone Details Page: {pk}")

def details(request, word, pk):
    return HttpResponse(f"{word} Details Page: {pk}")

 

[실행 결과]

 


위의 예시의 경우 간단한 테스트용 코드로 HttpResponse를 사용하여 해당 경로에 맞는 내용을 출력했다.

하지만 실제 배포 시 render를 사용하여 해당 경로에 맞는 html 페이지를 출력해야한다.

# main > views.py

from django.shortcuts import render
from django.http import HttpResponse

blog_list = [ 
    {
        "id": 1,
        "title": "장고는 너무 재미있어!!!",
        "content": "This is the content of blog 1",
        "author": "Author 1",
    },
    {
        "id": 2,
        "title": "파이썬도 너무 재미있어!!!!",
        "content": "This is the content of blog 2",
        "author": "Author 2",
    },
    {
        "id": 3,
        "title": "자바스크립트는 별로였어!!!",
        "content": "This is the content of blog 3",
        "author": "Author 3",
    },
]

user_list = [
    {
        "id": 1,
        "username": "hojun",
        "email": "hojun@gmail.com",
        "password": "1234",
    },
    {
        "id": 2,
        "username": "jihun",
        "email": "jihun@gmail.com",
        "password": "1234",
    },
    {
        "id": 3,
        "username": "junho",
        "email": "junho@gmail.com",
        "password": "1234",
    },
]

def index(request):
    return render(request, "main/index.html")


def bloglist(request):
    context = {"blogitems": blog_list} 
    return render(request, "main/bloglist.html", context) 
    

def blogdetails(request, pk):
    blog = blog_list[pk - 1]
    language = ["html", "css", "js", "python"]
    context = {"blog": blog, "language": language}
    return render(request, "main/blogdetails.html", context)


def userdetails(request, user):
    finduser = None
    for i in user_list:
        if i["username"] == user:
            finduser = i
    if finduser is None:
        return render(request, "main/notfound.html")
    return render(request, "main/userdetails.html", {"user": finduser})

위의 예시 코드를 보면 render를 통해 해당 경로에 맞는 html 파일을 출력하고 있다.

 

우선 context = {"blogitems": blog_list} 의 사용은 blogitems라는 이름으로 blog_list 객체를 사용하겠다는 뜻으로 dict 형태로 context 변수에 할당하여 해당 페이지를 출력하는 html에 인자로 전송할 수 있다. 그렇게 되면 bloglist.html에서는 context로 받은 매개변수를 통해 blogitems라는 변수 이름으로 views.py에서 정의한 blog_list 객체의 값을 사용할 수 있는 것이다! 또한 context = {"blogitem": blogitem, "useritem": useritem} 처럼 여러 개의 객체를 할당하여 전달할 수 있다.

 

# bloglist.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>bloglist</title>
</head>
<body>
    <h1>bloglist 페이지 입니다.</h1>
    <ul>
        {% for i in blogitems %} 
        <li><a href="/blog/{{i.id}}">{{ i.title }} {{i.id}}번째 게시물이야!</a></li>
        {% endfor %} 
    </ul>
</body>
</html>

위의 코드를 보면 알고 있던 html 코드와는 다른 것을 확인할 수 있다.

 

해당 페이지는 블로그의 세부 항목을 나타내는 페이지 이다. 100개가 존재하면 100개에 대한 코드를 작성하는 건 비효율적이므로 반목문을 통해 세부 항목에 대한 리스트를 출력하고 있다. 

 

여기서 사용된 문법에는 {{}} 처럼 중괄호를 두번 사용하면 변수를 출력하는 것이고, {%%} 처럼 사용하면 파이썬 문법으로 쓰겠다는 뜻이다. {{ i.title }} 처럼 title 변수를 출력했고, {% for ~ %} 를 통해 반복문을 수행했다. 여기서 반복문을 실행했다면 반드시 닫아줘야하고 {% for i in list %} ~ {% endfor %} 를 사용했다

 

blogitmes라는 값은 앞서 views.py에서 context = {}를 통해 전달된 값이다. context를 전달 받았고 blogitems라는 이름으로 blog_list를 사용하고 있는 것이다.


Django를 배운지 이틀이 된 날이지만 너무나도 쉽게 페이지가 만들어지고 관리할 수 있어, 나만의 사이트를 만들어서 관리하고 싶다는 생각을 하게 된다.

Comments