Django
20210204_ Django 게시판 리스트 화면, 글쓰기 화면, 글 보기 화면 만들기, template language, form
Django 게시판 만들기
게시판 리스트 화면 만들기
기본 html 화면 구성만들고 연결
base.html
가져오기
- base.html
{% raw %}
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> -->
<!-- bootstrap에서 다운받은 stylesheet 를 연결시켜 적용 -->
<link rel="stylesheet" href="/static/bootstrap.min.css" />
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js" integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
{% block contents %}
{% endblock %}
</div>
</body>
</html>
{% endraw %}
board_list.html
테이블 요소의 태그
- 테이블 요소 설명 사이트
<table>
: 테이블 태그<tr>
: 행 태그 (보통 모두 행 태그로 묶음)<th>
: 헤더 셀 태그<td>
: 셀 태그
기본적인 틀만 만들어 둔 상태
{% raw %}
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12">
<table class="table table-light">
<thead class="thead-light">
<tr>
<th>#</th>
<th>제목</th>
<th>아이디</th>
<th>일시</th>
</tr>
</thead>
<tbody class="text-dark">
<tr>
<th>1</th>
<td>테스트 제목</td>
<td>테스트 아이디</td>
<td>2021-02-04 21:11:00</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 글쓰기 버튼 -->
<div class="row">
<div class="col-12">
<buttton class="btn btn-primary">글쓰기</buttton>
</div>
</div>
{% endblock %}
{% endraw %}
- 테스트를 위한 간단한 views 생성
from django.shortcuts import render
# Create your views here.
def board_list(request):
return render(request, 'board_list.html')
- 테스트를 위한 urls 연결
- 프로젝트 urls.py
from django.contrib import admin
from django.urls import path, include
from fcuser.views import home
urlpatterns = [
path('admin/', admin.site.urls),
path('fcuser/', include('fcuser.urls')),
path('board/', include('board.urls')),
path('', home)
]
- board urls.py
from django.urls import path
from.import views
urlpatterns = [
path('list/', views.board_list),
]
python manage.py runserver
를 통해서 확인해 보기
models 만들기
models.py
models.Foreignkey(to, on_delete, **options)
: to 옵션에 해당하는 모델클래스의 key값을 받아 올수 있음, on_delete 옵션을 통해서 받아오는 모델 클래스 삭제시 해당 모델에서도 삭제할지 어떻게 할지 설정 가능전에 했던것 처럼 Meta 클래스를 통해서 테이블 이름 지정 가능
from django.db import models
# Create your models here.
class Board(models.Model):
title = models.CharField(max_length=128, verbose_name='제목')
contexts = models.TextField(verbose_name='내용')
writer = models.ForeignKey(
'sl_user.Sl_user', on_delete=models.CASCADE, verbose_name='작성자')
# on_delete=models.CASCADE 는 models의 key가 삭제 되면 해당 모델도 지우겠다.
registered_dttm = models.DateTimeField(
auto_now_add=True, verbose_name='등록시간')
def __str__(self):
return self.title
class Meta:
db_table = 'slowbuscamp_board'
verbose_name = '슬로우버스캠프 게시글' # 기본적으로 복수형을 지원하기 때문에 s가 자동으로 붙게 되어 있음
verbose_name_plural = '슬로우버스캠프 게시글' # 복수형이름을 따로 지정하여 자동으로 붙는 s를 제거 가능
- 만들고
migrations
,migrate
를 해야 반영됨
admin 연결
- 관리자 창에서도 볼 수 있게 admin 연결
- Django reference_django-admin and manage.py
from django.contrib import admin
from .models import Board
# Register your models here.
class BoardAdmin(admin.ModelAdmin):
list_display = ('title', 'writer', 'registered_dttm')
admin.site.register(Board, BoardAdmin) # 연결
view 만들기
views.py
views에 models에서 만든 Board import
order_by
,objects.all(), get() 등
- 데이터베이스 접근하는 methods(QuerySet API)Django reference_QuerySet API reference
from django.shortcuts import render
from .models import Board
# Create your views here.
def board_list(request):
# all()은 모든 오브젝트를 가져오고 order_by는 정렬인데 id필드를 기준으로 '-'는 역순을 의미 즉, 최신것으로 가져오겠다.
boards = Board.objects.all().order_by('-id')
return render(request, 'board_list.html', {'boards': boards})
# board_list.html의 boards context 를 key로 하여 board_list request에서 지정한 boards 변수를 value로 한다.
# 즉, models에서 가져온 것을 html에 넣겠다.
html 데이터 표현형식 변환하기 (view를 통해서 가져온 models를 표시하기 위해서)
- board_list.html
- The Django template language
- views에서 변수를 끌어와서 for, if등 자유롭게 사용 가능
- 여기에서는 views에서 render로 설정한 boards를 끌어와서 for문에서 board 변수로 하나씩 꺼내서 반복
- 그래서
{{}}
를 통해서 포맷팅시.
을 통해서 field를 지정할 수도 있음
{% raw %}
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12">
<table class="table table-light">
<thead class="thead-light">
<tr>
<th>#</th>
<th>제목</th>
<th>아이디</th>
<th>일시</th>
</tr>
</thead>
<tbody class="text-dark">
{% for board in boards %}
<tr>
<th>{{ board.id }}</th>
<td>{{ board.title }}</td>
<td>{{ board.writer }}</td>
<td>{{ board.registered_dttm }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- 글쓰기 버튼 -->
<div class="row">
<div class="col-12">
<buttton class="btn btn-primary">글쓰기</buttton>
</div>
</div>
{% endblock %}
{% endraw %}
게시판 글쓰기 화면 만들기
form class 만들기 (forms.py)
- 게시판에 들어갈 부분은 제목, 내용만 있으면 됨
widget
옵션의 경우 html input 태그를 생성하는데 옵션값을 무엇을 주느냐에 따라 input되는 type이 바뀐다. (widget의 속성은 form field의 속성에 따라 맞춤, 그리고 form field는 model field의 속성에 따라 맞춤)forms.Textarea
로 설정하여 내용을 쓸수 있는 기능을 실현(일반 text 형식과 다르게 긴 내용으로 여러줄 입력 가능 )
from django import forms
# 입력 받을 값은 제목과 내용 두개
class BoardForm(forms.Form):
title = forms.CharField(error_messages={
'required': '제목을 입력해 주세요.'
}, max_length=128, label="제목")
contents = forms.CharField(error_messages={
'required': '내용을 입력해 주세요.'
}, widget=forms.Textarea, label="내용")
view 만들기 (views.py)
- 만들어 놓은 form 형식을 view를 통해서 html과 조합해서 렌더링 시킬수 있게 먼저 작업함
return render(request, 'board_write.html', {'form': form})
- 글을 입력하고 POST 요청시 글이 잘써 졌는지 체크하는 로직을 작성
- 입력 값이 제대로됬으면 세션을 받아 데이터베이스에서 작성자 이름을 찾아 가져오는 로직 작성
- 해당 값을 model에 접근하여 database에 저장하는 로직 작성(저장할 값은 로그인된 사람의 작성자, 제목, 내용)
from django.shortcuts import render, redirect
from sl_user.models import Sl_user
from .models import Board
from .forms import BoardForm
def board_write(request):
if request.method == "POST": # POST 요청 조건
form = BoardForm(request.POST)
# form 변수에 BoardForm 폼 클래스에 POST 값을 적용한 폼 객체를 할당
if form.is_valid(): # form 변수 타당성 검증
user_id = request.session.get('user')
# user에 해당하는 세션 값(user의 그냥 id값) 가져와서 user_id에 할당
sl_user = Sl_user.objects.get(pk=user_id)
# Sl_user 모델 객체에서 pk가 user_id인 것을 가져와 sl_user에 할당
board = Board() # Board 모델을 board 변수에 할당하여 생성
board.title = form.cleaned_data['title']
# form에서 검증된 데이터의 title 필드의 값을 board모델 title 필드에 할당
board.contents = form.cleaned_data['contents']
# form에서 검증된 데이터의 contents 필드의 값을 board모델 contents 필드에 할당
board.writer = sl_user # sl_user 모델 자체는 name속성이라서 name을 board모델 writer필드에 할당
board.save() # board모델 SQL INSERT
return redirect('/board/list/')
# 저장후 list 페이지로 이동
else:
form = BoardForm() # POST 요청 하지 않으면 form에 BoardForm 폼 생성할당
return render(request, 'board_write.html', {'form': form})
# board_write.html 파일에 form 을 form 변수로 렌더링
html 만들기 (board_write.html)
- view에서 렌더링 요청한 form을 받아서 html 만들기
- label 태그의 경우 for와 요소의 id를 일치시켜 결합하게 함 Django Working with forms
- 그래서 요소에서의 id, label의 for에
{{ 필드변수.id_for_label }}
를 넣어 일치 시켜 주는데 html 결과는id_필드명
으로 나타난다. {{ 필드변수.label }}
의 경우에는 그냥 필드의 labe 이름을 불러옴
- 그래서 요소에서의 id, label의 for에
{{ field.field }}
의 경우 field라는 필드 변수의 필드 속성에 접근할수 있다.{{ field.field.widget.input_type }}
을 요소의 type에 포맷팅 하여 넣을수 있다.{% ifequal a b %}
...{% endifequal %}
는{% if a == b %}
...{% endif %}
을 쓴것과 같다.
{% raw %}
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12">
<form method="POST", action=".">
{% csrf_token %}
{% for field in form %}
<!-- form이라는 폼객체를 받아서 field라는 변수로 필드 객체를 하나씩 반복 -->
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field.field.widget.name}}
{% ifequal field.name 'contents' %}
<textarea class="form-control" name="{{ field.name }}" placeholder="{{ field.label }}"></textarea>
{% else %}
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}" placeholder="{{ field.label }}" name="{{ field.name }}">
{% endifequal %}
</div>
{% if field.errors %}
<span style="color: red">{{ field.errors }}</span>
{% endif %}
{% endfor %}
<button type="submit" class="btn btn-primary">글쓰기</button>
</form>
</div>
</div>
{% endblock %}
{% endraw %}
- url 연결하기(board 앱 urls.py)
from django.urls import path
from.import views
urlpatterns = [
path('list/', views.board_list),
path('write/', views.board_write),
]
게시판 글 상세보기 화면 만들기
view 만들기
- 상세 페이지의 경우에는 각 글마다 다르게 열려야 함으로 pk값을 더 받아야 한다.
- pk 값의 경우 model에서 self를 title로 해 놓았기 때문에 title을 기준으로 pk가 생기는 것이다.
from .models import Board
from django.shortcuts import render, redirect
def board_detail(request, pk): # pk 값을 받는다는 것 선언
board = Board.objects.get(pk=pk) # board 변수(인스턴스)에 모델의pk 값이 받아오는 pk값과 같은 경우의 Board 모델 객체를 할당
return render(request, 'board_detail.html', {'board': board})
# board 를 대체하여 렌더링 표시 할수 있게
html 만들기
- 표시될 정보는 제목과 내용 뿐이고 읽기 전용
- post를 보내지 않으므로 보안 토큰이 필요 없고, 폼도 필요없다.
- 폼이 필요 없으므로 폼과 연결시킬 필요 없이 여러 내용은 default 값으로 해 놓아도 된다.
- 그냥 모델의 정보를 html과 연결시켜 보여주기만 하면 되고 세션도 필요 없다.
input
요소에서value
옵션에 해당 pk board모델의 title 필드 값을 포맷팅 하게 한다.readonly
옵션을 통해서 읽기 전용으로 한다.textarea
요소의 경우에는 contents 필드 값을 포맷팅
{% raw %}
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12">
<div class="form-group">
<label for="title">제목</label>
<input type="text" class="form-control" id="title" value="{{ board.title }}" readonly>
<label for="contents">내용</label>
<textarea class="form-control" readonly>{{ board.contents }}</textarea>
</div>
<button class="btn btn-primary">목록</button>
</div>
</div>
{% endblock %}
{% endraw %}
url 연결하기
- view pk 설정(하위 주소에
<int:pk>/
를 넣어서 pk를 숫자 형태로 넣게 조건 설정 가능)
from django.urls import path
from.import views
urlpatterns = [
path('list/', views.board_list),
path('detail/<int:pk>/', views.board_detail),
path('write/', views.board_write),
]
- 참고로 github markdown 문서 사용시 liquid tag
{{% %}}
는 코드블럭에서 표현되지 않는다. 방법으로는 liquid rawtag로 감싸는 것이라고 한다.{{% raw %}}
,{{% endraw %}}
로 감싸주면 된다고 하는데 테스트 중이다. 그래서 tistory의 경우 귀찮아서 그냥 코드블럭안에는 rawtag있는것이다.
'Django' 카테고리의 다른 글
20210206_Django 태그 기능, get_or_create, ManyToManyField, 배포(pythonanywhere) (0) | 2021.02.07 |
---|---|
20210205_Django 예외 처리, 기능보완, request.get, request.GET, 페이징(paginator, page) (0) | 2021.02.06 |
20210203_ Django 로그인,세션처리, render, redirect, is_valid, clean(), form 활용 (0) | 2021.02.04 |
20210202_ Django admin, template,view만들기, url연결 - 회원가입, 로그인 (0) | 2021.02.03 |
20210129_ Django 가상환경 설정, MVC, MVT (0) | 2021.01.29 |