EMDI는 지금도 개발중

Python with Django : 장고 웹 프로그래밍 등록 화면 만들기(5) 본문

언어/Python

Python with Django : 장고 웹 프로그래밍 등록 화면 만들기(5)

EMDI 2020. 6. 18. 17:06

저번 글에서는 static 디렉터리를 가지고 css, js, img 등의 문서를 어떻게 관리하는지에 대해 알아보았습니다. 이번 글에서는 본격적으로 CRUD에 대해 배워보도록 하겠습니다. 우선 현재까지 만든 화면으로는 메인화면과 팀목록을 보여주는 화면 달랑 두 개 밖에 없기 때문에 팀을 추가할 수 있는 화면을 만들어 보도록 하겠습니다.

1. 팀추가 버튼 생성(teamInfo.html)

{% extends 'base.html' %}
{% block content %}
<div class="container" style="width:100%;">
  <div style="width:1024px;height:400px;margin:0 auto;">
      <div style="margin:0 21 0 22px">
          <h1 style="margin-top:30px;">Project Management Page (TeamInfo)</h1>
          <div class="toptextarea">
              <span>* 팀 목록을 보여주는 홈페이지입니다. </span>
          </div>
          <!-- Table Layout -->
          <div style="margin-top: 20px;">
            <div class="tableline">
                <div class="tablerow">
                    <div class="tablecell_h" style="width:130px;">팀명</div>
                    <div class="tablecell_h" style="width:180px;">팀닉네임</div>
                    <div class="tablecell_h" style="width:180px;">팀멤버수</div>
                    <div class="tablecell_h" style="width:130px;">비고</div>
                </div>
                {% for team in teams %}
                <div class="tablerow">
                    <div class="tablecell" style="width:130px;">{{ team.team_nm }}</div>
                    <div class="tablecell" style="width:180px;">{{ team.team_nick }}</div>
                    <div class="tablecell" style="width:180px;">{{ team.team_mems_cnt }}</div>
                    <div class="tablecell" style="width:130px;">{{ team.bigo }}</div>
                </div>
                {% endfor %}
            </div>
          </div>
          <!-- Table Layout -->
          <!-- Button START -->
          <div style="margin-top: 20px; float: right;">
            <a href="{% url 'teamAdd' %}"><button type="button" class="btn btn-primary">팀추가하기</button></a>
          </div>
          <!-- Button END -->
      </div>
  </div>
</div>
{% endblock %}

 

우선 팀 등록하는 화면을 만들기에 앞서 새롭게 만들 화면 경로에 들어갈 수 있는 버튼을 생성하도록 하겠습니다. 버튼은 teamInfo.html에 버튼을 추가하였습니다.

버튼을 추가한 화면의 모습입니다. 버튼은 부트스트랩의 css을 활용하여 생성하였습니다. 만약 저와 같은 버튼을 만들고 싶으신 분들은 부트스트랩 사이트에 접속하셔서 원하는 코드를 복사붙여넣기 하세요.

 

2. forms.py 생성

여태까지는 팀을 등록하려면 관리자 페이지에서 등록할 수밖에 없었습니다. 이제는 클라이언트 홈페이지에 등록이 가능하도록 데이터베이스 모델에서 해당 항목들을 가져오는 작업을 해야합니다. 이 작업을 하기 위해서는 forms.py 파일을 생성해줍니다. forms.py는 fin(APP)폴더 안에 생성해줍니다.

from django import forms
from .models import Team

class TeamUpload(forms.ModelForm):
    class Meta:
        model = Team
        fields = [ 'team_seq', 'team_nm', 'team_nick', 'bigo']

 

우리는 장고에서 기본적으로 지원하는 forms를 impot받고 또한 Team 모델을 사용할 것이라 Team도 가져옵니다. TeamUpload는 팀 정보를 업로드하는데에 쓰는 class를 의미합니다. Meta 클래스는 장고에서 내부 클래스로 활용되며, 이는 기본 필드의 값을 재정의할 때 사용합니다. 

# models.py
from django.db import models
from django.urls import reverse

class Team(models.Model):
    # primary_key로 지정할 컬럼들은 꼭 primary_key=True 주기
    team_seq = models.CharField('team_seq', max_length=9, primary_key=True)
    team_nm = models.CharField('team_nm', max_length=50, blank=True)
    team_nick = models.CharField('team_nick', max_length=50, blank=True)
    team_mems_cnt = models.IntegerField('team_mems_cnt', default=0 )
    team_reg_dt = models.DateTimeField(max_length=8, auto_now=True)
    bigo = models.TextField('bigo', blank=True)
    use_yn = models.CharField('use_yn', max_length=1, default='Y')
    reg_dt = models.DateTimeField('reg_dt', max_length=14, auto_now=True)
    sort_order = models.IntegerField('sort_order', default=0 )

    def __str__(self):
        return self.team_nm

 

혹시 몰라서 models.py에 설정한 Team 모델도 같이 올리도록 하겠습니다.

 

3. 등록할 화면 생성 (teamAdd.html)

우선 등록화면 html을 생성합니다.

 

4. views.py와 urls.py(path설정) 등록

# views.py
from django.shortcuts import render, redirect
from django.views.generic import TemplateView, ListView, DetailView

from .models import Team
from django.http import HttpResponse

# Function-Based Views
def index(request):
    return render(request, 'index.html')

def teamInfo(request):
    teams = Team.objects.all()
    context = {'teams': teams}
    return render(request, 'content/teamInfo.html', context)

def teamCreate(request):
    return render(request, 'content/teamAdd.html')
# urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url #추가
import fin.views

app_name = 'fin'
urlpatterns = [
    path('admin/', admin.site.urls),
    # 추가로 생성한 urls
    path('', fin.views.index , name='index'),
    path('team/teamInfo/',  fin.views.teamInfo, name='teamInfo'),
    path('team/teamAdd/',  fin.views.teamCreate, name='teamAdd'),
]

그 다음은 views.py에서 뷰를 생성해주도록 합니다. 뷰 생성이 끝났으면 해당 뷰의 url을 추가해주도록 합시다. 

 

5. views.py 수정(forms.py의 폼을 연결하기)

from django.shortcuts import render, redirect
from django.views.generic import TemplateView, ListView, DetailView

from .models import Team
from .forms import TeamUpload #추가
from django.http import HttpResponse

# Function-Based Views
def index(request):
    return render(request, 'index.html')

def teamInfo(request):
    teams = Team.objects.all()
    context = {'teams': teams}
    return render(request, 'content/teamInfo.html', context)

def teamCreate(request):
    upload = TeamUpload()
    if request.method == 'POST':
        upload = TeamUpload(request.POST)
        if upload.is_valid():
            upload.save()
            return redirect('teamInfo')
        else:
            return redirect('index')
    else:
        upload =  TeamUpload()
        return render(request, 'content/teamAdd.html', {'form': upload})

 

해당 내용을 천천히 살펴보면, forms.py에 설정했던 TeamUpload()를 upload이라는 객체 안에 우선 생성합니다. 그 다음 teamAdd.html에서 POST방식으로 요청이 들어오면 TeamUpload() 폼에 값을 전달한 상태로 upload 객체를 만들고 그 데이터들이 올바른 형식으로 들어왔으면 데이터베이스에 저장하는 것을 의미합니다. 작업이 끝났으면 return redirect('teamInfo') 팀정보 화면으로 이동시킵니다.

 

6. teamAdd.html

{% extends 'base.html' %}
{% block content %}
<div class="container" style="width:100%;">
  <div style="width:1024px;height:400px;margin:0 auto;">
      <div style="margin:0 21 0 22px">
            <h1 style="margin-top:30px;">Project Management Page (TeamAdd)</h1>
            <div class="toptextarea">
                <span>* 새로운 팀을 등록하는 홈페이지입니다. </span>
            </div>
            <!-- Form START -->
            <form method="POST">
                <div style="margin-top: 20px;">
                    {% csrf_token %}
                    {{ form.as_p }}
                </div>
                <!-- Button START -->
                <div style="margin-top: 20px; float: right;">
                    <button type="submit" class="btn btn-primary">등록</button>
                    <a href="{% url 'teamInfo' %}"><button type="button" class="btn btn-primary">취소</button></a>
                </div>
                <!-- Button END -->
            </form>
            <!-- Form END -->
      </div>
  </div>
</div>
{% endblock %}

{{ form.as_p }}란, views.py에서 return render(request, 'content/teamAdd.html', {'form': upload })의 세 번째 인자 upload 객체를 'form' 키 값으로 전달하였기 때문에 html에서 {{ form }}이라고 다루는 것입니다. .as_p는 폼을 <p>태그로 감싼 형태로 출력한다는 의미입니다.

* csrf_token :  장고에서는 POST 데이터 전달과정에서 보안을 위해 csrf_token이라는 것을 반드시 사용해야합니다.

만약 정상적으로 코딩하셨으면 위의 사진과 같이 등록화면이 생성되는 것을 확인할 수 있습니다. 실제 등록해보시면 테이블에도 정상적으로 들어가는걸 알 수 있었습니다.

 

7. teamAdd.html 꾸미기

{% extends 'base.html' %}
{% block content %}
<div class="container" style="width:100%;">
  <div style="width:1024px;height:400px;margin:0 auto;">
      <div style="margin:0 21 0 22px">
            <h1 style="margin-top:30px;">Project Management Page (TeamAdd)</h1>
            <div class="toptextarea">
                <span>* 새로운 팀을 등록하는 홈페이지입니다. </span>
            </div>
            <!-- Form START -->
            <form method="POST">
                <div style="margin-top: 20px;">
                    {% csrf_token %}
                    <div class="form-group">
                        <label for="inputTeamSeq">팀 SEQ</label>
                        {{ form.team_seq }}
                    </div>
                    <div class="form-group">
                        <label for="inputTeamNm">팀 이름</label>
                        {{ form.team_nm }}
                    </div>
                    <div class="form-group">
                        <label for="inputTeamNick">팀 닉네임</label>
                        {{ form.team_nick }}
                    </div>
                    <div class="form-group">
                        <label for="inputTeamBigo">비고</label>
                        {{ form.bigo }}
                    </div>
                    
                </div>
                <!-- Button START -->
                <div style="margin-top: 20px; float: right;">
                    <button type="submit" class="btn btn-primary">등록</button>
                    <a href="{% url 'teamInfo' %}"><button type="button" class="btn btn-primary">취소</button></a>
                </div>
                <!-- Button END -->
            </form>
            <!-- Form END -->
      </div>
  </div>
</div>
{% endblock %}

그대로 사용하려고 하니 디자인이 너무 구리네요. 그래서 살짝 바꿔보도록 하겠습니다.  우선 teamAdd.html에서 {{ form.as_p }}를 각각 할당받을 수 있도록 나눠줍니다.

 

8. forms.py 수정

from django import forms
from .models import Team
class TeamUpload(forms.ModelForm):
    class Meta:
        model = Team
        fields = [ 'team_seq', 'team_nm', 'team_nick', 'bigo']

        widgets = {
            'team_nm': forms.TextInput(
                attrs={'class': 'form-control', 'style': 'width: 100%', 'placeholder': '팀 명을 입력하세요.'}
            ),
            'team_nick': forms.TextInput(
                attrs={'class': 'form-control', 'style': 'width: 100%', 'placeholder': '팀 닉네임을 입력하세요.'}
            ),
            'bigo': forms.Textarea(
                attrs={'class': 'form-control', 'style': 'width: 100%'}
            ),
        }

그 다음은 부트스트랩의 class가 적용될 수 있도록 forms.py에서 widgets을 이용해서 적용시킵니다.

그럼 아까보다는 예쁜 화면으로 바뀌었네요. 팀SEQ는 나중에 안보이게 설정할 데이터라 현재는 저렇게 냅두었습니다. 다음 글에서는 Add에 이어 Update와 Delete를 해보도록 하겠습니다.

Comments