영웅은 죽지 않는다

[Web] Django 구성요소 및 기본 설치/세팅 예제 본문

Programming/Web

[Web] Django 구성요소 및 기본 설치/세팅 예제

YoungWoong Park 2022. 5. 4. 01:35

 

Django 개념

 

  • MVC (MVT) 패턴을 갖고 있는 파이썬 기반 웹 어플리케이션 구현 프레임워크
    • Model : 안전하게 데이터를 저장
    • View : 데이터를 적절하게 유저에게 보여줌
    • Control, Template(Django) : 사용자의 입력과 이벤트에 반응하여 Model과 View를 업데이트

→ 이전에는 통합해서 모델을 다루었지만, 커뮤니티가 점차 커지게 되며 MVC 패턴으로 분리하여 모델과 프로젝트를 다루는 방법으로 바뀌게 됨

 

  • 세부 구성 파일
    • wsgi.py : 신호를 받아 웹 서버와 장고를 적절하게 결합해주는 게이트웨이 역할
    • urls.py : 정규표현식으로 구성되어 있으며, views.py로 특정 view를 보내주는 역할
    • views.py : 사용자 요청에 의해서 데이터를 다룰 방법을 결정. models.py로 신호를 보내거나, 가져온 데이터를 가공
    • models.py : 데이터베이스로부터 데이터를 가져올 때 클래스의 변수를 정의하고 지정함
    • MANAGERS : Model과 Database를 연결짓는 역할을 하며, query 문을 번거롭게 작성하지 않아도 변수에 맞는 데이터를 가져오게끔 하는 편리성의 역할
    • TEMPLATE : html파일이며, 내부에 간단한 script 로직 구현 가능. 

 


Django 설치 및 기본 세팅

  • 가상환경 생성
python -m venv my_env
  • 가상환경 활성화 (윈도우) : my_env에 접속한 후
\\Scripts\\activate.bat
  • Django 설치
pip install Django
  • 버전 확인
import django
print(django.VERSION)
  • 프로젝트 디렉토리 생성
mkdir my_project
  • Django 프로젝트 저장소 생성
cd my_project
django-admin.py startproject config .
  • DB 생성
python manage.py migrate

→ 기본적으로 Django에서 필요한 데이터베이스 테이블 생성

 

  • 관리자 생성
python manage.py createsuperuser

→ 원하는 Username, Email, Password를 입력

  • 테스트 서버 구동
python manage.py runserver

이와 같이 정상적으로 웹 서버가 실행되는지 확인

 


프로젝트 구조

 

  • config 폴더 : 프로젝트 설정 파일, 웹 서비스 실행 파일이 들어 있고, django-admin start project 명령으로 생성된 폴더
    1. _ init _. py
      • 파이썬 2.x대 버전과의 호환을 위해 만들어진 비어있는 파일
    2. settings.py : 프로젝트 설정에 관한 내용이 들어 있는 파일
      • DEBUG : 디버그 모드 설정
      • INSTALLED_APPS : pip으로 설치한 앱 또는 본인이 만든 app을 추가
      • MIDDELWARE_CLASSES : request와 response 사이의 주요 기능 레이어
      • TEMPLATES : django template 관련 설정, 실제 뷰(html, 변수)
      • DATABASES : 데이터베이스 엔진의 연결 설정
      • STATIC_URL : 정적 파일의 URL(css, javascript, image 등)
      • 참고 : 추가로 설정하면 좋은 것
        • ALLOWED_HOSTS = ['*']
        • LANGUAGE_CODE = 'ko-kr’
        • TIME_ZONE = 'Asia/Seoul’
        • USE_TZ = False
    3. urls.py
      • 특정 기능을 수행하기 위해 접속하는 주소(url) 설정 및 기록하는 파일
      • 한 프로젝트 안에 여러 개의 urls 파일을 만들게 됨
      • config 파일 내의 urls.py가 최초로 탐색되는 기준
    4. wsgi.py
      • 웹 서비스를 실행하기 위한 wsgi 관련 내용이 들어 있는 파일

  • db.sqlite3 : SQLite3 DB 파일, 다른 DB를 사용할 경우 불필요

  • manage.py : 장고의 다양한 프로젝트 관리 명령어를 실행하기 위한 파일
    • 주요 명령어
      • startapp : 앱 생성
      • runserver : 서버 실행
      • createsuperuser : 관리자 생성
      • makemigrations app : app의 모델 변경 사항 체크
      • migrate : 변경 사항을 DB에 반영
      • shell : 쉘을 통해 데이터를 확인
      • collectstatic : static 파일을 한 곳에 모음
    • ex) ./manage.py runserver 0.0.0.0:8080

 

  • 앱 추가
python manage.py startapp app_default

  1. admin.py : 생성한 DB 테이블의 CRUD 확인을 위해 장고의 기본 관리자 페이지에서 확인하거나 특별한 기능 추가를 가능하도록 함
  2. models.py : DB의 구조를 결정하는 모델의 명세를 관리. DB 종류에 상관 없이 ORM을 사용
  3. views.py : 페이지를 만들 때 작성. Class Based와 Function Based로 나뉘며, 대부분의 프로그래밍 작업은 뷰를 만들고 수정하는 일
  4. urls.py : views.py에 기능을 만들면 기능을 동작시키는 방식은 url을 통한 호출 방식이고, 그것을 결정하게 해 주는 파일

 


앱 기본 설정

 

  • http://127.0.0.1:8000/admin/ 으로 접속하면 user, group 등을 지정할 수 있다.

  • 앱 등록 : settings.py 에서 INSTALLED_APPS에 ‘app_default’ 추가하기

 

  • 게시글 클래스 모델 생성 (models.py)
from django.db import models

# Create your models here.
class Article(models.Model):
    name = models.CharField(max_length=50)
    title = models.CharField(max_length=50)
    contents = models.TextField()
    url = models.URLField()
    email = models.EmailField()
    cdate = models.DateTimeField(auto_now_add=True)

-> 다양한 필드 인자를 넣고 싶다면 django docs에서 확인

 

  • 생성한 모델을 적용 ( cmd )
python manage.py makemigrations app_default
python manage.py migrate

→ 생성한 모델을 de.sqlite 3 파일에 적용

 

  • 주소 및 화면 설정 - User들이 접근할 수 있는 url 주소를 설정 (urls.py)
    from django.contrib import admin
    from django.urls import path
    from app_default.views import *
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('write/', write, name='write'),
    ]
    

    → views.py에서 write 함수를 설정해야 한다.

 

  • 주소 및 화면 설정 - write 함수 설정 (view.py)
from django.shortcuts import render
# Create your views here.

def write(request):
    return render(request, 'write.html')

→ app_default 폴더 내 templates/write.html 파일을 생성하여 화면 구성을 설정한다.

  • 주소 및 화면 설정 - html 설정 (templates/write.html)
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>write</title>
  </head>
  <body>
    hello django!
    </form>
  </body>
</html>

→ 위 코드 작성 후 http://127.0.0.1:8000/write/ 에 접속하여 body 부분이 잘 출력되었는지 확인한다.

 

 

  • 글쓰기 폼 만들기
    • app_default 폴더 내에 forms.py 파일 생성
    from django.forms import ModelForm
    from app_default.models import *
    
    class Form(ModelForm):
        class Meta :
            model = Article
            fields = ['name','title','contents','url','email']
    
    • form 뷰 생성 (views.py)
    from django.shortcuts import render
    from app_default.forms import *
    # Create your views here.
    def write(request):
        form = Form()
        return render(request, 'write.html', { 'form':form })
    
    → write.html 파일에 form 데이터를 전달하게 된다.
    → html 파일에서 태그를 생성해야 한다.

  • form 태그 생성 (write.html)
    • Django에서는 손쉽게 폼을 생성할 수 있는 툴을 제공한다.
      <!DOCTYPE html>
      <html lang="en" dir="ltr">
        <head>
          <meta charset="utf-8">
          <title>write</title>
        </head>
        <body>
          hello django!
          <form action="" method="post">
            {{form.as_p}}
            <button type="submit" class='btn btn-primary'>저장</button>
          </form>
        </body>
      </html>
      
      → 버튼 클릭 이벤트가 발생했을 때 해당 데이터를 DB에 저장하기 위해서는 form을 저장하는 기능을 추가해야 한다.


    • 폼을 DB에 저장 (views.py)
      from django.shortcuts import render
      from app_default.forms import *
      # Create your views here.
      
      def write(request):
          if request.method == 'POST':
              form = Form(request.POST)
              if form.is_valid():
                  form.save()
          else:
              form = Form()
      
          return render(request, 'write.html', { 'form':form })
      
      → 기존 방식이라면, Form을 직접 생성한 후 변수로 데이터를 넣은 후 그 데이터를 sql문을 작성하여 query 형태로 보내야 하는데, Django에서는 그 과정이 위 조건문으로 단순하게 해결될 수 있다.

 

 

위와 같이 작성한 후 저장 버튼을 누르게 되면,

 

CSRF라는 토큰이 발생되어 공격으로부터 막기 위해 이슈가 발생한다.

이 때, html 폼에서 토큰을 생성하고 전달하는 코드를 추가해야 한다.

 

(write.html)

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>write</title>
  </head>
  <body>
    hello django!
    <form action="" method="post">
      <!-- {% comment %}
          {{ form.as_table }}
          {{ form.as_p }}
          {{ form.as_ul }} -->
      <!-- {% endcomment %} // 이 부분은 생략해도 된다. --> 
      {{form.as_p}}
      {% csrf_token %} // 이 부분을 추가한다.
      <button type="submit" class='btn btn-primary'>저장</button>
    </form>
  </body>
</html>

 

-> 저장을 눌렀을 때 내용이 유지되어 있다면 DB에 저장이 완료된 상태이다.

 

It is impossible to add the field 'cdate' with 'auto_now_add=True' to article without providing a default. This is because the database needs something to populate existing rows.

1. Provide a one-off default now which will be set on all existing rows

2. Quit and manually define a default value in models.py.

 

—> 위와 같은 에러 발생시에는, 1번을 선택하여 default 값을 자동으로 추가해준다.

 

 

DB 리스트 생성

  • list 경로를 추가 (urls.py)
from django.contrib import admin
from django.urls import path
from app_default.views import *

urlpatterns = [
    path('admin/', admin.site.urls),
    path('write/', write, name='write'),
    path('list/', list, name='list'),
]

 

 

  • list 함수 추가 (views.py)
from django.shortcuts import render
from app_default.forms import *
# Create your views here.

def write(request):
    if request.method == 'POST':
        form = Form(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = Form()

    return render(request, 'write.html', { 'form':form })

def list(request):
    articleList = Article.objects.all()
    return render(request, 'list.html',{'articleList':articleList})

→ list.html으로 Article 함수의 모든 데이터를 보낸다.

 

 

  • html 파일 생성 (templates/list.html)
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>list</title>
  </head>
  <body>
    {% for article in articleList %}
    {{ article.title}} | {{article.name}} | {{article.cdate|date:"D d M Y " }}
    {% endfor %}
  </body>
</html>
  • 127.0.0.1:8000/list/ 접속 시 입력한 값이 잘 출력되는지 확인

→ write 페이지에서 글을 추가하면 바로 업데이트가 된다.

 

 

DB 상세 정보 페이지 생성

  • 정규표현식이 포함된 url 생성 및 전달 (urls.py)
from django.contrib import admin
from django.urls import path, re_path
from app_default.views import *

urlpatterns = [
    path('admin/', admin.site.urls),
    path('write/', write, name='write'),
    path('list/', list, name='list'),
    re_path(r'^view/(?P<num>[0-9]+)/$',view),
]

→ 정규표현식 작성을 위해 re_path 메소드를 불러와야 한다.

 

  • views.py
from django.shortcuts import render
from app_default.forms import *
# Create your views here.

def write(request):
    if request.method == 'POST':
        form = Form(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = Form()

    return render(request, 'write.html', { 'form':form })

def list(request):
    articleList = Article.objects.all()
    return render(request, 'list.html',{'articleList':articleList})

def view(request, num="1"):
    article = Article.objects.get(id=num)
    return render(request, 'view.html',{'article':article})

→ request와 num(default : 1)을 불러와 id에 매칭 및 article 변수에 적용한 후 response에 전달

 

→ 127.0.0.1:8000/view/2/ 에 접속 시 해당 정보가 잘 출력되는 것 확인

 

 

  • 해당 list에 하이퍼링크 생성 (list.html)
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>list</title>
  </head>
  <body>
    <ul>
      <li>제목 | 저자 | 날짜</li>
    {% for article in articleList %}
      <li><a href="/view/{{article.id}}">{{ article.title}}</a> | {{article.name}} | {{article.cdate|date:"D d M Y " }}</li>
    {% endfor %}
    </ul>
  </body>
</html>

→ list 페이지에서 링크가 제대로 적용되었는지 확인

→ 클릭 시 view/1 페이지로 잘 넘어가는지 확인

 


참고 사이트 url

 

https://wikidocs.net/9714

https://blog.nerdfactory.ai/2021/02/24/creating-an-api-&-collecting-html-elements-with-django-rest-framework.html

https://woolbro.tistory.com/50?category=910053

https://woolbro.tistory.com/47