본문 바로가기
코딩 연습/코딩배우기

파이썬 장고(django) 웹 프로그래밍 - 웹 페이지 만들기 # 1

by good4me 2021. 9. 23.

goodthings4me.tistory.com

 

파이썬 장고(django) 웹 프로그래밍 - 웹 페이지 만들기(1)

- 프로젝트 생성과 로그인 페이지(accounts 앱) 만들기

 

※ 쿠팡 파트너스 API 데이터를 추출하고 파이썬 장고(django)를 활용해 웹 서비스 페이지 만들어보기

- 초급 수준의 장고를 익히고 다음 단계로 넘어가기 위한 실전 경험 차원에서 웹 사이트 하나를 만들어 보려고 도전함

- 일부 기능과 오류 해결을 위해 구글 등에서 검색하여 사이트를 완성해가기 때문에 소스가 투박할 수 있음 

- 에디터는 파이참 사용, 파이썬 3.95 버전과 장고 3.2 버전 설치 후 개발

- 쿠팡 파트너스 API로 쿠팡 상품을 추출하고, db.sqlite3에 insert 한 후 웹 페이지에서 서비스 하는 기능을 단계별로 기술함

 

 

01. 파이참(PyCharm)에서 프로젝트 생성 

- 가상환경 설정 후 프로젝트 진행 (파이참이 아닌 Visual Studio Code도 가능)

파이참 - New Project 만들기

D:\에 borame라는 폴더를 만들고, Location에서 불러온 후, Base Interpreter로 설치한 파이썬 버전을 선택한다.

 

 

02. 장고 설치

- 프로젝트 진입 후 파이참 터미널에서 venv/Scripts/activate 명령으로 가상환경에 접속한 후 장고를 설치한다.

(venv) PS D:\borame> pip install django==3.2  # 장고 3.2 버전 설치

장고 설치

# pip 업그레이드도 하라고 하니 실행한다.

(venv) PS D:\borame> python.exe -m pip install --upgrade pip

 

 

03. 프로젝트 생성

(venv) PS D:\borame> django-admin startproject config .

 

good4me.co.kr

 

04. 기본 앱(DB) migrate --> db.sqlite3 파일 생성

(venv) PS D:\borame> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
(venv) PS D:\borame>

 

 

05. 어드민 계정 생성

(venv) PS D:\borame> python manage.py createsuperuser
Username (leave blank to use 'haemi'): admin
Email address:
Password:
Password (again):
Superuser created successfully.
(venv) PS D:\borame>

 

 

06. Window 명령 프롬프트 실행 후 테스트서버 실행 (파이참에서 직접 실행도 가능)

- 배치 파일을 만들어 놓고 사용하면 편리함 (bo.bat)

@echo off
cd/
d:
cd borame
cd venv
cd Scripts
activate

# 명령 프롬프트 실행 : 윈도우키 + q 또는 r 누른 후 "cmd" 입력

python manage.py runserver

 

# 서버 구동 확인 : localhost:8000 or 127.0.0.1:8000

장고 runserver

 

 

# localhost:8000/admin 입력 후 Username과 Password 입력

장고 admin 페이지

 

 

07. 사용자 계정 관리용 accounts 앱 생성 및 settings.py에 등록

(venv) PS D:\borame> python manage.py startapp accounts

accounts 앱 등록

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

 

# 언어 및 TIME_ZONE 설정 (settings.py / TIME_ZONE 설정은 개인마다 차이 있음)

LANGUAGE_CODE = 'ko-kr'  # 'en-us'
TIME_ZONE = 'Asia/Seoul'  # 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = False

 

 

08. accounts 앱 하위에 templates 폴더 생성과 URLConf 정의를 위한 urls.py 파일 생성

※ URLConf 란, 특정 URL과 뷰를 매핑하는 List(settings.py에 최상위 URLConf 모듈 지정)

- URL로부터 뷰(View)를 얻기 위해, Django는 URLConf 라는 것을 사용한다.
- 어떤 url 요청이 들어오면 URLconf는 URL 패턴에 대해 어떤 views.py의 함수를 실행시킬지 정의한다.

 

# accounts 앱은 간단하게 입력 폼만을 다시 만들고, 계정은 admin 페이지에서 관리토록 함

- borame 사이트가 회원가입을 위한 것이 아니기 때문에 accounts 모델(models) 작성은 안하고 뷰(views)는 CBV(Class Based View)를 사용함

- 계정 관리 앱(accounts)에서는 'app_name' 사용하지 말라는 전문가의 의견이 있어서 사용 안함

from django.urls import path
from django.contrib.auth import views as auth_views

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

 

- 로그인 페이지 URLConf 적용 : config>urls.py 수정

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

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

 

- login.html 템플릿 생성

login.html 템플릿 파일 생성

 

 

09. 웹 페이지 레이아웃 만들기

- login.html 템플릿 파일과 이후 만들어질 템플릿 파일들의 레이아웃 통일을 위해 전체 페이지 레이아웃을 만들고 그 페이지를 상속받아서 사용함

- 전체 페이지 레이아웃 설정 위해 폴더(템플릿 layout 폴더) 생성후 settings.py에 등록하고, 그 폴더에 base.html 파일을 만들어서 사용한다. (base.html 은 bootstrap 사용함)
- layout 템플릿 폴더는 프로젝트 root인 borame 밑에 만듦 : borame>layout


- settings.py 설정 (os 모듈이 필요함. 상단에 import os 추가)

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,

여기서 'DIR':[] 부분을
'DIRS': [os.path.join(BASE_DIR, 'layout')], 처럼 수정

 

- layout 밑에 base.html 템플릿 파일 생성
https://getbootstrap.com/docs/5.1/getting-started/introduction/ 에서 CSS 부분과 JS 부분의 코드를 복사하여 base.html에 붙여넣기 함

# css : https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css

# js : https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js

 

- bootstrap navbar layout 그대로 사용할 것이고, 템플릿 상속을 위해
<body> 부분에 아래 내용을 추가한다.
    {% block content %}
    {% endblock %}

# 전체 레이아웃 템플릿 파일 : base.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>Borame</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
    <div class="container-fluid">
        <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
            <div class="container-fluid">
                <a class="navbar-brand" href="#">BORAME</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
                    data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
                    aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                        <li class="nav-item"><a class="nav-link active" aria-current="page" href="#">Home</a></li>
                        <li class="nav-item"><a class="nav-link" href="#">상품리스트</a></li>
                        {% if user.is_authenticated %}
                        <li class="nav-item dropdown">
                            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
                                data-bs-toggle="dropdown" aria-expanded="false">상품등록/수정</a>
                            <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                                <li><a class="dropdown-item" href="#">상품 등록</a></li>
                                <li><a class="dropdown-item" href="#">쿠팡 Redirect URL</a></li>
                                <li><hr class="dropdown-divider"></li>
                                <li><a class="dropdown-item" href="#">쿠팡 Update(Detail)</a></li>
                            </ul>
                        </li>
                        <li class="nav-item"><a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a></li>
                        <li class="nav-item"><a class="nav-link" href="#">로그아웃</a></li>
                        {% else %}
                        <li class="nav-item"><a class="nav-link" href="#">로그인</a></li>
                        {% endif %}
                    </ul>
                    <form class="d-flex">
                        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
                        <button class="btn btn-outline-success" type="submit">Search</button>
                    </form>
                </div>
            </div>
        </nav>
    </div>

    {% block content %}

    {% endblock %}

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>

 

- 로그인 여부(user.is_authenticated)에 따라 보여주는 메뉴가 틀림 (일반 사용자와 관리자만 구분)

 

 

10. 로그인 페이지 만들기

- 로그인 템플릿 파일 : login.html

{% extends "base.html" %}
{% block content %}

<div class="container p-3 my-3">
    <form class="post-form my-3" method="post" action="{% url 'login' %}">
        {% csrf_token %}
        <div class="form-group my-3">
            <label for="username">사용자 ID</label>
            <input type="text" class="form-control" name="username" id="username" value="{{ form.username.value|default_if_none:'' }}">
        </div>
        <div class="form-group my-3">
            <label for="password">비밀번호</label>
            <input type="password" class="form-control" name="password" id="password" value="{{ form.password.value|default_if_none:'' }}">
        </div>
        <button type="submit" class="btn btn-primary">로그인</button>
    </form>
</div>

{% endblock %}

 

# 로그인 페이지 : http://localhost:8000/accounts/login/ 접속 시

로그인 페이지

 

 

- 오류 발생 시 메시지를 보기 위해 layout 폴더에 form_errors.html (에러 메시지 표시) 파일 만듦 

* 참고 사이트 : https://wikidocs.net/71259

# 파일 위치 : layout>form_errors.html

{% if form.errors %}
    {% for field in form %}
        {% for error in field.errors %}
            <!-- 필드 오류를 출력한다. -->
            <div class="alert alert-danger">
                <strong>{{ field.label }}</strong>
                {{ error }}
            </div>
        {% endfor %}
    {% endfor %}
    {% for error in form.non_field_errors %}
        <!-- 넌필드 오류를 출력한다. -->
        <div class="alert alert-danger">
            <strong>{{ error }}</strong>
        </div>
    {% endfor %}
{% endif %}

 

# 오류 메시지가 보이도록 login.html 파일에서 아래 부분을 수정 : {% include "form_errors.html" %} 부분 추가

<div class="container p-3 my-3">
    <form class="post-form my-3" method="post" action="{% url 'login' %}">
        {% csrf_token %}
        {% include "form_errors.html" %}

 

비밀번호 오류 메시지 보이기

 

 

11. 로그인 후 redirect 오류, 그리고 로그아웃 후 페이지 설정

- 장고는 로그인 후 profile로 자동 redirect 되도록 되어있다. 이런 로그인 경로를 localhost:8000 으로 가도록 하고, 로그아웃 부분도 동일 경로로 가도록 설정한다.
- 경로 설정은 settings.py에서 하며, base.html의 각 메뉴에도 연결할 것이고,
- 해당 프로젝트의 첫 페이지(root인 localhost:8000)가 앞으로 만들 쿠팡 파트너스 상품 리트스가 보이도록 products 앱을 만들어서 웹 페이지 default 파일인 index.html이 open 될 수 있도록 할 것임

 

# settings.py 하단 맨 마지막에 다음 내용을 추가한다.
LOGIN_URL = '/accounts/login/'  # 로그인 버튼 클릭 또는 로그인 경로 지정 시 셋팅 
LOGIN_REDIRECT_URL = '/'  # 로그인 후 보내는 URL
LOGOUT_REDIRECT_URL = '/'  # 로그아웃 후 보내는 URL

 

# base.html 수정
<li class="nav-item"><a class="nav-link" href="#">로그아웃</a></li> 부분을
<li class="nav-item"><a class="nav-link" href="{% url 'logout' %}">로그아웃</a></li> 로 수정

<li class="nav-item"><a class="nav-link" href="#">로그인</a></li> 부분을
<li class="nav-item"><a class="nav-link" href="{% url 'login' %}">로그인</a></li> 로 수정

 

# 로그인 후 localhost:8000 으로 보낸다. 현재 템플릿 파일이 없어서 Page not found (404) 오류 발생

 

 

>> 파이썬 장고(django) 웹 프로그래밍 - 웹 페이지 만들기 # 2

댓글