Model을 활용해 DB 관리하기

 

데이터베이스란? 데이터를 저장하는 시스템. 특히, 구조화한다는 특징이 있다. 단순히 정보를 저장한다는 창고의 개념이 아니라 쉽게 정보를 탐색할 수 있게 정렬해두어 유저가 정보를 참조하고 싶을 때 바로 참조할 수 있는 시스템이다.

 

- Relational DB : 테이블 형태. row와 column으로 데이터를 관리하는 것.

- 데이터베이스 인터페이스 프로그래밍 언어 = SQL

- Django에는 ORM이 내장되어 있다. 

 

models.py

 

class <모델 이름>(models.Model):
    # field1 = models.FieldType()...
    """
    문자열 : CharField
    숫자 : IntegerField, SmallIntegerField, ...
    논리형 : BooleanField
    시간 / 날짜 : DateTimeField
    """

 

admin.py

 

from .models import <모델 이름>

admin.site.register(<모델 이름>)

 

다음과 같이 admin.py에 생성한 모델을 등록하여 주면

 

 

다음과 같이 관리자 홈페이지에서 모델을 관리할 수 있게 된다. 그러나 Coffee(<모델 이름>) 테이블을 눌러보면

 

그림 출처 : 프로그래머스 스쿨

 

아직은 반영이 되지 않은 것을 확인할 수 있다. 이를 반영시켜주기 위해선 migrate을 해주어야 한다.

장고에서는 데이터베이스를 관리할 때 모델을 git의 commit과 유사한 migration이란 단위로 관리하게 된다.

 

cmd에서 migrate를 진행해보도록 하자.

 

'''git add와 유사'''
> python manage.py makemigrations homepage
'''result'''
Migrations for 'homepage':
  homepage\migrations\0001_initial.py
    - Create model <모델 이름>
 
 '''만들어진 migration들을 실제 DB에 반영'''
 >python manage.py migrate
 '''result'''
 Operations to perform:
  Apply all migrations: admin, auth, contenttypes, homepage, sessions
Running migrations:
  Applying homepage.0001_initial... OK

 

위 작업 이후 다시 admin 사이트의 Coffee 테이블을 눌러서 확인하면

 

 

다음과 같이 정상적으로 페이지가 참조되는 것을 확인할 수 있다.

위 페이지에서 Object를 추가하면 다음과 같이 나타나게 된다.

 

 

<모델 이름> obejct(1),

<모델 이름> obejct(2), ...

굉장히 가독성이 떨어지는 이름으로 생성이 되게 된다. 

무슨 Object를 지칭하는지 한 번에 알 수 있는 좋은 이름으로 각 Object가 생성되도록 하기 위해 코드를 수정해보도록 하자.

 

models.py

 

class <모델 이름>(models.Model):

def __str__(self):
        return self.<객체를 대표하는 파라미터>

 

다음과 같이 설정을 해주고 다시 admin 사이트로 가서 확인을 하면

 

 

다음과 같이 각 객체를 잘 나타내어 주는 것을 확인할 수 있다.


Template에서 Model 확인하기

 

views.py

 

from .models import Coffee

def coffee_view(request):
    coffee_all = Coffee.objects.all() #select * from Coffee랑 동일한 결과를 갖고 옴
    return render(request, 'coffee.html',{"coffee_list":coffee_all})

 

coffee.html

 

<!DOCTYPE html>
<html lang="en">
<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>Coffee List</title>
</head>
<body>
    <h1>My Coffe List</h1>
    <p>{{coffee_list}}</p>
</body>
</html>

 

url을 지정 후 coffee.html을 확인해보면 다음과 같은 결과를 얻을 수 있다.

 

 

QuerySet이 반환된 것을 확인할 수 있었다.

이번엔 각 요소들 하나하나를 순회하며 그에 대한 Field를 다 살펴보고자 한다.

 

coffee.html

 

<!DOCTYPE html>
<html lang="en">
<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>Coffee List</title>
</head>
<body>
    <h1>My Coffe List</h1>
    {% for coffee in coffee_list %}
        <p>{{coffee.name}}, {{coffee.price}}</p>
    {% endfor %}
</body>
</html>

 

실행 결과

 


Form으로 Template에서 Model 수정하기

 

forms.py

 

from django import forms
from .models import Coffee

class CoffeeForm(forms.ModelForm): # ModelForm을 상속받는 CoffeeForm 생성
    class Meta: #form을 만들기 위해 어떤 model을 써야 하는지 지정하게 됨
        model = Coffee
        fields = ('name', 'price', 'is_ice')

 

views.py

 

from .forms import CoffeeForm

def coffee_view(request):
    coffee_all = Coffee.objects.all()
    form = CoffeeForm() #Form 객체 생성
    return render(request, 'coffee.html',{"coffee_list":coffee_all,"coffee_form":form})

 

coffee.html

 

<!DOCTYPE html>
<html lang="en">
<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>Coffee List</title>
</head>
<body>
    <h1>My Coffe List</h1>
    {% for coffee in coffee_list %}
        <p>{{coffee.name}}, {{coffee.price}}</p>
    {% endfor %}

    <form>
        {{ coffee_form.as_p }}
    </form>
</body>
</html>

 

실행 결과

 

 

Form이 생성된 모습을 확인할 수 있다. Form에 대한 틀은 생성이 되었는데 이 form에 정보를 입력 후 서버로 전송하는 버튼이 있어야 한다. 그 버튼도 만들어 보도록 하겠다.

 

coffee.html

 

<form method="POST">
    {{ coffee_form.as_p }}
    <button type="submit">Save</button>
</form>

 

실행 결과

 

 

실제로 Save 버튼이 생긴 것을 확인할 수 있다.

그래서 Save를 하기 위해 버튼을 누르면

 

 

다음과 같이 403 에러 메시지를 표시하는 사이트가 뜨는 것을 확인할 수 있다.

왜 이런 에러가 떴냐하면

Form의 옵션에는 보안 옵션이 들어가야 한다.

Djagno에 CSRF를 구현하지 않으면 403 오류가 발생하게 된다. 즉, 서버 입장에서 CSRF 토큰을 Form 안에 삽입해 주어야 한다는 것이다. 토큰을 삽입해 주려면 다음과 같이 한 줄의 코드만 입력해주면 된다.

 

coffee.html

 

<form method="POST">{% csrf_token %}
    {{ coffee_form.as_p }}
    <button type="submit">Save</button>
</form>

 

form 태그 사이에 오직 {% csrf_token %}만 추가해주면 된다. 이를 추가해준 후에 Save 버튼을 누르면 아까와 같은 에러 사이트는 안 뜨고 정보가 전달이 된 것을 확인할 수 있다. 그러나 전달된 정보는 DB에 들어가지 않게 된다. 왜냐하면 view에서 POST 요청이 들어왔을 때 어떤 logic을 행해야 하는지에 대한 정보를 담지 않았기 때문이다.

 

view에서 POST 요청이 들어왔을 때 모델에 정보를 담아주는 logic을 구현해 보도록 하자.

 

views.py

 

def coffee_view(request):
    coffee_all = Coffee.objects.all() 
    # 만약 request가 POST라면:
        # POST를 바탕으로 Form을 완성하고
        # Form이 유효하면 -> 저장!
    if request.method=='POST':
        form = CoffeeForm(request.POST) # 완성된 Form
        if form.is_valid(): # 채워진 Form이 유효하다면:
            form.save() # 이 Form의 내용을 Model에 저장!

    form = CoffeeForm()
    return render(request, 'coffee.html',{"coffee_list":coffee_all,"coffee_form":form})

 

실행 결과

 

 

다음과 같이 Form에 입력한 정보가 테이블에 바로 반영되는 것을 확인할 수 있다.

Django

 

Python 기반 웹 프레임 워크. 한 Project는 여러 App으로 구성되어 있다. App 각각은 특정 명령을 수행하는 View나 Template의 모음이라고 생각하면 된다.

 

Djnago vs Flask

 

둘 다 Python 기반 웹 프레임 워크지만, 지향성이 다르다.

 

flask는 늘 앞에 micro가 붙는다. 이는 최소한의 기능을 갖고 있다는 것으로, 여기에 추가적 모듈을 붙여가며 빌드업을 하는 구조이고,

 

Django는 이미 거의 모든 것이 내장되어 있는 구조로 되어 있다. 큰 것 안에 우리가 원하는 것을 부분부분 채워 나가면서 프로젝트를 이뤄나가는 구조이다.


Django의 구성 요소

 

  • manage.py
    • 장고를 실행하게 하는 파일
  • (proj_name) file
    •  __init__.py
      • proj_name file 디렉토리가 파이썬 모듈로써 인식되게 하는 역할
    • asgi.py / wsgi.py
      • 서버에서 실제 장고 프로젝트를 가동할 때 다루게 되는 곳
    • settings.py
      • 전반적 python django 프로젝트에 설정 사항을 반영하는 파일
      • 내부 구성 요소
        • SECRET_KEY
          • 장고 프로젝트에 대한 secret key
        • DEBUG 
          • True면 파이썬 프로젝트를 디버깅 모드로 실행
        • ALLOWED HOST 
          • 리스트 내 주소를 넣어 어떤 주소에 대해 장고 프로젝트에 접근할 수 있는지 결정하게 됨
        • INSTALLED_APPS / MIDDLEWARE
          • 여러 앱 / 미들웨어 중 어떤 것을 설치하게 되는지 확인할 수 있다
        • ROOT_URLCONF
          • 프로젝트에서 URL 관리를 어떤 모듈에서 진행할 것인지 담당
        • TEMPLATES
          • 실제 보는 화면에 관한 요소들이 담겨 있는 부분
        • WSGI-APPLICATION
          • 파이썬 상에서 웹 서버와 소통하는 데 필요한 어플리케이션 담당
        • DATABASE
          • 프로젝트 상에서 다루게 되는 여러 자료들을 저장하는 곳을 담당
        • AUTH_PASSWORD_VALIDATORS
          • 패스워드 관리
        • STATIC_URL
          • 정적 파일들(CSS, JavaScript, Images)을 어느 폴더에 담아둘지 결정
    • urls.py
      • URL 관리

App의 구성요소

 

  • admin.py
    • admin 페이지에 관한 부분
  • apps.py 
    • 앱에 관한 설정에 관한 부분
  • models.py
    • 앱에 쓰일 데이터베이스 스키마 등을 클래스 형태로 작성해줄 수 있다.
  • tests.py
    • 프로젝트의 테스트 케이스에 대해 설명
  • views.py
    • 앱에서 view를 어떻게 관리해줄 것인가에 대한 코드 작성 가능

Django의 MVT Pattern

 

그림 출처 : www.onlinetutorialspoint.com/django/django-mvt-basic-application-example.html

 

어떤 User가 있을 때 그 User가 Request를 보낸다. Django(server) 입장에선 이 Request를 URL(urls.py)이 인식하게 된다. 즉, 어떤 경로에 대한 요청이 들어갔는지 체크한다.

들어온 경로가 urls.py에 있다면 View(view.py)에 보내게 된다. view에는 들어온 요청을 처리하는 logic이 담겨있다.

이 요청을 처리하다 보면 데이터베이스를 처리하는 경우도 생길텐데 그 데이터베이스를 처리하는 부분은 Model이라는 부분이다. 장고는 DB를 ORM 구조(Object Related Model)로 관리한다.

응답하는 과정에서 특정 웹페이지를 보여줘야 하는 경우도 생길텐데 이는 Template에서 관리한다. 이는 html 파일등 + template 언어로 전달해줄 수 있다. template 언어를 이용하면 view에서 처리한 변수들을 html에 임베딩해서 함께 출력해줄 수 있다.


Django 프로젝트 시작하기

 

장고 프로젝트 생성

 

django-admin startproject <proj_name>

 

서버 가동

 

python manage.py runserver

 

django App 만들기

 

django-admin startapp <app_name>

 

※ 이 때 프로젝트 폴더로 이동한 후에 만들어 주어야 한다! (cd proj_name) (manage.py있는 폴더에서 만들어 주면 됨)

 

Django 관리자 계정 생성

 

python manage.py migrate => default로 만들어진 데이터베이스들에 대한 여러 정보가 반영되게 된다.

python manage.py createsuperuser

 

http://127.0.0.1:8000/admin/에서 관리자 계정으로 로그인을 하면 추가한 데이터베이스에 대해서도 관리가 가능해진다.


View로 Request Handling 하기

 

정말 간단한 View를 만들어보자

 

view.py

 

from django.shortcuts import render, HttpResponse # HttpResponse 모듈 추가

# Create your views here.
def index(request):
    return HttpResponse('Hello World!')

 

urls.py

 

from homepage.views import index # 실행할 함수 명시

urlpatterns = [
    path('admin/', admin.site.urls), # 127.0.0.1/admin/
    path('', index) # 127.0.0.1/ URL 요청이 들어오면 index 함수를 실행하라.
]

 

settings.py

 

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'homepage' # 생성한 앱 이름을 꼭 추가해주어야 한다. 그래야 앱으로 인식하여 실행을 해준다.
]

 

실행 결과

 

 


Template으로 보여줄 화면 구성하기

 

render -> html 문서를 따로 관리해주는 함수

 

render 인자 -> render ( request, '.html', {} )

 

생성한 어플 폴더 내에 template 폴더를 생성 후 그 안에

index.html 파일을 생성한 후 이를 django에 반영시켜보자 

 

visual studio code에서 ! + tab을 눌러주면 기본 html 규격 자동완성이 된다. 편리함!

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
    </body>
</html>

 

views.py

 

from django.shortcuts import render

def index(request):
    return render(request, 'index.html', {})

 

settings.py

 

import os

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR,'hompage','template')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

 

실행 결과

 


고정된 자료가 아닌 동적으로 변화하는 자료 보여주기

 

views.py

 

def index(request):
    number = 10
    return render(request, 'index.html', {"my_num":number})

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
        <!-- Template language -->
        <p>{{ my_num }}</p>
    </body>
</html>

 

실행 결과

 

 

 

{{}}라는 템플릿 문법을 이용해 직접적으로 데이터를 넣어줄 수 있다.


템플릿 필터 적용

 

views.py

 

def index(request):
    name = "Michael"
    return render(request, 'index.html', {"my_name":name})

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
        <!--Template language-->
        <!--Template filter | -->
        <p>{{ my_name|length }}</p>
        <p>{{ my_name|upper }}</p>
    </body>
</html>

 

실행 결과

 


Template tag

 

views.py

 

def index(request):
    # return HttpResponse('<h1>Hello World!<h1>')
    nums= [1,2,3,4,5]
    return render(request, 'index.html', {"my_list":nums})

 

index.html

 

<!DOCTYPE html>
<html>
    <head>
        <title>Python django example</title>
    </head>
    <body>
        <!--열린 태그--> 
        <h1>
            Title
        </h1>
        <!--닫힌 태그-->
        <p>나는 능이버섯이당</p>
        {% for element in my_list %}
            {%if not element|divisibleby:"2"%}
                <p>{{element}}</p>
            {%endif%}
        {% endfor %}
    </body>
</html>

 

실행 결과

 

 

+ Recent posts