티스토리 뷰
python 활용 #12 : Django Form을 이용한 model, form, view, url, template 패턴
jinozpersona 2022. 1. 8. 13:22INTRO
0. Test 용 template 만들기 : bootstrap 활용
1. model 생성 및 migration : django 관리자를 이용한 CRUD control
2. view 만들기
3. template 적용하기
4. model-form을 이용한 CRUD Control
Create : 생성, New(model-form + POST method)
Read : 조회, Detail
Update : 수정(model-form + Post method)
Delete : 삭제
들어가기 전에 사전 이해가 필요한 사항
- django 가상환경 및 프로젝트 생성/설정 : 참고1, 참고2
- app 생성과 template 및 static/css 기초 : 참고
- bootstrap 적용 및 template 분리(base/sidebar/topbar/footer) : 참고1, 참고2
0. Test 용 template 만들기
web-site에서 기본으로 구성되는 template를 구성해본다.
django의 back-end test를 위해 front-end에 해당하는 html, css, javascript 접근이 용이한 bootstrap을 이용
step1. bootstrap sbadmin2 theme 다운 : https://startbootstrap.com/theme/sb-admin-2
step2. css/style.css와 js/datatables-simple-demo.js를 django project의 static/css, static/js에 각각 복사
step3. board app을 생성하고 board/templates/board/test_index.html을 생성
board/templates/board/test_index.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>{% block title %}{{ section.title }}{% endblock %}</title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet" />
</head>
<body class="sb-nav-fixed">
<div id="layoutSidenav">
<!-- Topbar -->
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
<!-- Navbar Brand-->
<a class="navbar-brand ps-3" href="{% url 'board:test_index' %}" style="color:lightgray; font-size:1.7em">App_Test</a>
<!-- Navbar Top-->
<div style="color:darkgray; font-size:2em">Test_title</div>
</nav>
<!-- Sidebar -->
<div id="layoutSidenav_nav">
<nav class="sb-sidenav accordion sb-sidenav-dark" id="sidenavAccordion">
<div class="sb-sidenav-menu">
<div class="nav">
<a class="nav-link" href="#">
hyperlink 1
</a>
<a class="nav-link" href="#">
hyperlink 2
</a>
</div>
</div>
</nav>
</div>
<!-- Main_Contents -->
<div id="layoutSidenav_content">
<main>
<div class="container-fluid px-4">
<!-- Main_content_#1 -->
<h3 class="mt-4">QuerySet View</h3>
<div class="card mb-4">
<div class="card-header">
QuerySet Board | <a href="#">글쓰기</a>
</div>
<div class="card-body">
<p>{{ orms template tag part }}</p>
</div>
</div>
<!-- Main_content_#2 -->
<h3 class="mt-4">Form View</h3>
<div class="card mb-4">
<div class="card-header">
Form Board | <a href="#">글쓰기</a>
</div>
<div class="card-body">
<p>{{ forms template tag part }}</p>
</div>
</div>
<!-- Main_content_#3 -->
<h3 class="mt-4">Table View</h3>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Table Board | <a href="#">글쓰기</a>
</div>
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>작성자</th>
<th>내용</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
{% for orm in orms %}
<tr>
<td>{{ orm.field0 }}</td>
<td>{{ orm.field1 }}</td>
<td>{{ orm.field2 }}</td>
<td>{{ orm.field3 }}</td>
<td>{{ orm.field4 | date:'Y-m-d' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Main_content_#4 -->
</div>
</main>
</div>
</div>
<!-- Table js source -->
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" crossorigin="anonymous"></script>
<script src="{% static 'js/datatables-simple-demo.js' %}"></script>
</body>
</html>
step4. config/urls.py, board/urls.py, board/views.py를 개발서버에 띄운다.
config/urls.py
from django.contrib import admin
from django.urls import path, include
from board import urls
urlpatterns = [
path('admin/', admin.site.urls),
path('board/', include('board.urls')),
]
board/urls.py
from django.urls import path
from . import views
app_name = 'board'
urlpatterns = [
path('test_index/', views.test_index, name='test_index'),
]
board/views.py
from django.shortcuts import render
# Create your views here.
def test_index(request):
return render(request, 'board/test_index.html')
browser : localhost:8000/board/test_index/
1. model 생성 및 migration
model 생성
DB migration, migrate
admin control : django 관리자 admin을 이용하여 CRUD 기본 형태 이해
board/models.py
from django.db import models
# Create your models here.
class BoardTest(models.Model):
title = models.CharField(db_column='title', max_length=200)
author = models.CharField(db_column='author', max_length=30)
article = models.TextField(db_column='article', null=True)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
$ ./manage.py makemigrations board
$ ./manage.py migrate
board/admin.py
from django.contrib import admin
from board.models import BoardTest
# Register your models here.
class BoardTestAdmin(admin.ModelAdmin):
search_fields = ['title']
admin.site.register(BoardTest, BoardTestAdmin)
admin에 접속하여 BOARD TEST 추가를 이용하여 CRUD(생성/읽기/수정/삭제) 사용해보기
board/views.py의 template rendering을 위해 boardtest에 record 4개를 생성한다
browser : localhost:8000/admin/board/boardtest/
2. view 만들기
views.py
from django.shortcuts import render
from .models import BoardTest
from .forms import BoardTestForm
# Create your views here.
def test_index(request):
boards = BoardTest.objects.all()
forms = BoardTestForm()
ctx = {'boards':boards, 'forms':forms}
return render(request, 'board/test_index.html', ctx)
3. template 적용하기
{{ template tag part }} 부분을 수정하여 django 관리자에서 작성한 ORM의 QuerySet, Form, Table View 적용
board/templates/board/test_index.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>{% block title %}{{ section.title }}{% endblock %}</title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet" />
</head>
<body class="sb-nav-fixed">
<div id="layoutSidenav">
<!-- Topbar -->
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
<!-- Navbar Brand-->
<a class="navbar-brand ps-3" href="{% url 'board:test_index' %}" style="color:lightgray; font-size:1.7em">App_Test</a>
<!-- Navbar Top-->
<div style="color:darkgray; font-size:2em">Test_title</div>
</nav>
<!-- Sidebar -->
<div id="layoutSidenav_nav">
<nav class="sb-sidenav accordion sb-sidenav-dark" id="sidenavAccordion">
<div class="sb-sidenav-menu">
<div class="nav">
<a class="nav-link" href="#">
hyperlink 1
</a>
<a class="nav-link" href="#">
hyperlink 2
</a>
</div>
</div>
</nav>
</div>
<!-- Main_Contents -->
<div id="layoutSidenav_content">
<main>
<div class="container-fluid px-4">
<!-- Main_content_#1 -->
<h3 class="mt-4">QuerySet View</h3>
<div class="card mb-4">
<div class="card-header">
QuerySet Board | <a href="#">글쓰기</a>
</div>
<div class="card-body">
<p>{{ boards }}</p>
</div>
</div>
<!-- Main_content_#2 -->
<h3 class="mt-4">Form View</h3>
<div class="card mb-4">
<div class="card-header">
Form Board | <a href="#">글쓰기</a>
</div>
<div class="card-body">
<p>{{ forms }}</p>
</div>
</div>
<!-- Main_content_#3 -->
<h3 class="mt-4">Table View</h3>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Table Board | <a href="#">글쓰기</a>
</div>
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>작성자</th>
<th>내용</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td>{{ board.id }}</td>
<td>{{ board.title }}</td>
<td>{{ board.author }}</td>
<td>{{ board.article }}</td>
<td>{{ board.date | date:'Y-m-d' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Main_content_#4 -->
</div>
</main>
</div>
</div>
<!-- Table js source -->
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" crossorigin="anonymous"></script>
<script src="{% static 'js/datatables-simple-demo.js' %}"></script>
</body>
</html>
4. form을 이용한 CRUD Control
django 관리자 /admin에서 CRUD control을 직접 template에서 form을 이용하여 수행
model-forms 기반 CRUD control을 위한 views.py, urls.py를 추가하고 template를 생성하여 구현
- index 기준으로 views.py, urls.py CRUD 4종 추가
- template에서는 delete를 제외한 CRU 3종을 추가
전체 List를 보여주는 list_index.html 새로 만들어 다음 CRUD를 구현해보자
C : 글쓰기를 클릭하여 new_board.html에서 form 생성
R : list_index.html의 제목을 클릭하여 detail_board/pk/로 이동
U : detail_board/pk/ 수정을 클릭하여 수정 form 생성
D : detail_board/pk/ 삭제를 클릭하여 해당 record 제거
list_index.html
test_index.html을 다른 이름으로 저장하여 Table Board만 남기고 hyperlink를 생성
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>{% block title %}{{ section.title }}{% endblock %}</title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet" />
</head>
<body class="sb-nav-fixed">
<div id="layoutSidenav">
<!-- Topbar -->
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
<!-- Navbar Brand-->
<a class="navbar-brand ps-3" href="{% url 'board:test_index' %}" style="color:lightgray; font-size:1.7em">App_Test</a>
<!-- Navbar Top-->
<div style="color:darkgray; font-size:2em">Test_title</div>
</nav>
<!-- Sidebar -->
<div id="layoutSidenav_nav">
<nav class="sb-sidenav accordion sb-sidenav-dark" id="sidenavAccordion">
<div class="sb-sidenav-menu">
<div class="nav">
<a class="nav-link" href="#">
hyperlink 1
</a>
<a class="nav-link" href="#">
hyperlink 2
</a>
</div>
</div>
</nav>
</div>
<!-- Main_Contents -->
<div id="layoutSidenav_content">
<main>
<div class="container-fluid px-4">
<!-- Main_content_#1 -->
<!-- Main_content_#2 -->
<!-- Main_content_#3 -->
<h3 class="mt-4">Table View</h3>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Table Board | <a href="{% url 'board:brd_create' %}">글쓰기</a>
</div>
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>작성자</th>
<th>내용</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td>{{ board.id }}</td>
<td><a href="{% url 'board:brd_read' board.pk %}">{{ board.title }}</a></td>
<td>{{ board.author }}</td>
<td>{{ board.article }}</td>
<td>{{ board.date | date:'Y-m-d' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Main_content_#4 -->
</div>
</main>
</div>
</div>
<!-- Table js source -->
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" crossorigin="anonymous"></script>
<script src="{% static 'js/datatables-simple-demo.js' %}"></script>
</body>
</html>
browser : localhost:8000/board/list_index/
board/forms.py
from django import forms
from .models import BoardTest
class BoardTestForm(forms.ModelForm):
class Meta:
model = BoardTest
fields = ['author','title', 'article']
widgets = {
'author' : forms.TextInput(attrs={'class':'form-control', 'style':'width: 30em'}),
'title' : forms.TextInput(attrs={'class':'form-control', 'style':'width: 30em'}),
'article' : forms.Textarea(attrs={'class':'form-control', 'style':'width: 80em', 'rows':10}),
}
labels = {
'author' : '작성자',
'title' : '제목',
'article' : '내용',
'date' : '날짜',
}
board/views.py
from django.shortcuts import render, redirect
from .models import BoardTest
from .forms import BoardTestForm
# Create your views here.
def test_index(request):
boards = BoardTest.objects.all()
forms = BoardTestForm()
ctx = {'boards':boards, 'forms':forms}
return render(request, 'board/test_index.html', ctx)
def list_index(request):
boards = BoardTest.objects.all()
ctx = {'boards':boards}
return render(request, 'board/list_index.html', ctx)
def brd_create(request):
boards = BoardTest.objects.all()
if request.method == 'POST':
form = BoardTestForm(request.POST)
if form.is_valid():
board_create = BoardTest()
board_create.author = form.cleaned_data['author']
board_create.title = form.cleaned_data['title']
board_create.article = form.cleaned_data['article']
board_create.save()
return redirect('board:list_index')
else:
form = BoardTestForm()
boards = BoardTest.objects.all()
ctx = {'form':form, 'boards':boards}
return render(request, 'board/board_create.html', ctx)
def brd_read(request,pk):
boards = BoardTest.objects.all()
board_read = BoardTest.objects.get(pk=pk)
ctx = {'boards':boards,'board_read':board_read}
return render(request, 'board/board_read.html', ctx)
def brd_update(request,pk):
boards = BoardTest.objects.all()
board_upate = BoardTest.objects.get(pk=pk)
if request.method == 'POST':
form = BoardTestForm(request.POST)
if form.is_valid():
board_upate.author = form.cleaned_data['author']
board_upate.title = form.cleaned_data['title']
board_upate.article = form.cleaned_data['article']
board_upate.save()
return redirect('board:list_index')
else:
form = BoardTestForm(instance=board_upate)
boards = BoardTest.objects.all()
ctx = {'form':form, 'boards':boards}
return render(request, 'board/board_update.html', ctx)
def brd_delete(request,pk):
board_del = BoardTest.objects.get(pk=pk)
board_del.delete()
return redirect('board:list_index')
board/urls.py
from django.urls import path
from . import views
app_name = 'board'
urlpatterns = [
path('test_index/', views.test_index, name='test_index'),
path('list_index/', views.list_index, name='list_index'),
path('brd_create/', views.brd_create, name='brd_create'),
path('brd_read/<int:pk>/', views.brd_read, name='brd_read'),
path('brd_read/<int:pk>/update', views.brd_update, name='brd_update'),
path('brd_read/<int:pk>/delete', views.brd_delete, name='brd_delete'),
]
templates 4종은 body의 <main></main> 부분만 수정
-1- board_create
-2- board_read/<int:pk>/
-3- board_read/<int:pk>/update
board_read/<int:pk>/delete : template가 필요없음
-1- board_create
board/templates/board/board_create.html
- 글쓰기 hyperlink
- post method를 이용한 새글 작성 form
<main>
<div class="container-fluid px-4">
<!-- Main_content_#1 -->
<!-- Main_content_#2 -->
<!-- Main_content_#3 -->
<h3 class="mt-4">Table View</h3>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Table Board | <a href="{% url 'board:brd_create' %}">글쓰기</a>
</div>
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>작성자</th>
<th>내용</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td>{{ board.id }}</td>
<td><a href="{% url 'board:brd_read' board.pk %}">{{ board.title }}</a></td>
<td>{{ board.author }}</td>
<td>{{ board.article }}</td>
<td>{{ board.date | date:'Y-m-d' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Main_content_#4 -->
<div class="card mb-4">
<div class="card-header">
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<a href="{% url 'board:list_index' %}"><button type="submit">생성</button></a>
</form>
</div>
</div>
</div>
</main>
browser : localhost:8000/board/brd_create/
-2- board_read/<int:pk>/
board/templates/board/board_read.html
- form field 내용 표시
- 수정 | 삭제 hyperlink
<main>
<div class="container-fluid px-4">
<!-- Main_content_#1 -->
<!-- Main_content_#2 -->
<!-- Main_content_#3 -->
<h3 class="mt-4">Table View</h3>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Table Board | <a href="{% url 'board:brd_create' %}">글쓰기</a>
</div>
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>작성자</th>
<th>내용</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td>{{ board.id }}</td>
<td><a href="{% url 'board:brd_read' board.pk %}">{{ board.title }}</a></td>
<td>{{ board.author }}</td>
<td>{{ board.article }}</td>
<td>{{ board.date | date:'Y-m-d' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Main_content_#4 -->
<div class="card mb-4">
<div class="card-header">
<span style="font-size:1.3em">{{ board_read.title }} | {{ board_read.author }}</span><br>
<span style="font-size:0.9em"><a href="{% url 'board:brd_update' board_read.pk %}">수정</a> | <a href="{% url 'board:brd_delete' board_read.pk %}">삭제</a></span>
</div>
<div class="card-body">
{{ board_read.article }}
</div>
</div>
</div>
</main>
browser : localhost:8000/board/brd_read/1/
-3- board_read/<int:pk>/update
board/templates/board/board_update.html
- post method를 이용한 수정 작성 form
<main>
<div class="container-fluid px-4">
<!-- Main_content_#1 -->
<!-- Main_content_#2 -->
<!-- Main_content_#3 -->
<h3 class="mt-4">Table View</h3>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Table Board | <a href="{% url 'board:brd_create' %}">글쓰기</a>
</div>
<div class="card-body">
<table id="datatablesSimple">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>작성자</th>
<th>내용</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td>{{ board.id }}</td>
<td><a href="{% url 'board:brd_read' board.pk %}">{{ board.title }}</a></td>
<td>{{ board.author }}</td>
<td>{{ board.article }}</td>
<td>{{ board.date | date:'Y-m-d' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Main_content_#4 -->
<div class="card mb-4">
<div class="card-header">
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<a href="{% url 'board:list_index' %}"><button type="submit">수정</button></a>
</form>
</div>
</div>
</div>
</main>
browser : localhost:8000/board/brd_read/3/update/
board_read/<int:pk>/delete
- template가 필요없음
- 삭제 클릭
'python > Lecture' 카테고리의 다른 글
[arduino] LM35 / TMP36 Analog Sensor 연결도 : arduino IDE or VScode 설정 및 모니터링 (0) | 2023.11.21 |
---|---|
python 활용 #13 : Django REST Framework web API 만들기 (0) | 2022.01.10 |
python 활용 #11 : django, model 변경에 따른 migrate error 해결 방안 (0) | 2022.01.05 |
python 활용 #10 : django, model db to csv Export (0) | 2021.12.25 |
python 활용 #9 : django, csv 파일을 이용한 model db 생성 (0) | 2021.12.25 |
- Total
- Today
- Yesterday
- MacOS
- Model
- CSV
- DS18B20
- vscode
- Pandas
- 자가격리
- ERP
- 라즈베리파이
- SSH
- 확진
- template
- github
- sublime text
- analysis
- arduino
- COVID-19
- r
- git
- Python
- 코로나19
- 코로나
- raspberrypi
- server
- DAQ
- Regression
- Django
- Raspberry Pi
- pyserial
- Templates
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |