미리보는 프로젝트 완성코드 -->https://github.com/leeceo97/python_community
태그 기능은 게시글을 작성할때 그글이 포함되어 있는 내용을 단어로 요약한것입니다. 게시글을 작성할때마다 개수의 제한 없이 태그를 입력받을수 있고 입력받은 값을 저장하되 기존에 겹치는 태그는 늘리지 저장이아닌 불러오는 형식으로 구현하겠습니다.
1.model구성
-tag/models.py
from django.db import models
class Tag(models.Model):
name =models.CharField(max_length=32, verbose_name='태그명')
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
db_table = 'community_tag'
verbose_name = '태그'
verbose_name_plural = '태그'
별다른건 없습니다!
-boards/models.py
from django.db import models
class Board(models.Model):
title = models.CharField(max_length=64)
contents = models.TextField()
writer = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
tags = models.ManyToManyField('tag.Tag')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Meta:
db_table = 'boards'
verbose_name = '커뮤니티 게시판'
verbose_name_plural = '커뮤니티 게시판'
기존의 Board모델에 tags를 ForeignKey로 선언해주었습니다. 기존의 방식과 같게 참조할 모델을 첫번째 인자로 입력했지만 on_delete=models.CASCADE를 입력하지 않은이유는 게시글이 지워지더라도 기존에 존재하는 태그명은 지워지지 않도록 하기위해 넣지 않았습니다.
tag같은경우는 별도로 tag디렉터리 안에서의 작업은 이루어지지 않고 board디렉터리의 form, view, templates에서 이뤄집니다. --> 사실 boards디렉터리 의 models.py안에 tag모델을 선언해도되지만 추후 추가될 comment 모델까지 있기때문에 가시성을 위해 따로 분리하였습니다.
2. view구성
-board/forms.py
from django import forms
class BoardForm(forms.Form):
title = forms.CharField(
error_messages={
'required': '제목을 입력해주세요.'
}, max_length=64, label="제목")
contents = forms.CharField(
error_messages={
'required': '내용을 입력해주세요.'
},widget=forms.Textarea, label = "내용")
tags = forms.CharField(required=False, label = "태그")
태그를 입력하지 않아도 오류가 뜨지 않게 기존의 필드 선언과는 다르게 required=False로 선언해주었습니다.
-boards/views.py
def board_write(request):
if not request.session.get('user'):
return redirect('/accounts/login')
if request.method =='POST':
form = BoardForm(request.POST)
if form.is_valid():
user_id = request.session.get('user')
user = User.objects.get(pk=user_id)
tags = form.cleaned_data['tags'].split(',')
board=Board()
board.title = form.cleaned_data['title']
board.contents = form.cleaned_data['contents']
board.writer = user
board.save()
for tag in tags:
if not tag:
continue
_tag, _ = Tag.objects.get_or_create(name=tag)
board.tags.add(_tag)
return redirect('/boards/list')
else:
form = BoardForm()
return render(request, 'board_write.html', {'form':form})
board.tags.add(_tag)에서 board에 _tag를 저장한다는 의미인데 그렇기 위해서는 board는 이미 저장되어 있어야 하므로board저장 코드가 먼저 실행되어야 한다.
for tag in tags:
if not tag:
continue
_tag, _ = Tag.objects.get_or_create(name=tag)
board.tags.add(_tag)
입력받은 tags안의 값들이 기존에 존재하는지 않하는지 알기위해 반복문을 위와 같이 사용했고
처음보는 get_or_create같은 경우 정의가
get_or_create 메서드는 객체(object)를 조회할 때 유용하게 사용되는 메서드이다. 이 메서드는 (object, created) 라는 튜플 형식으로 반환을 한다. 첫번째 인자(object)는 우리가 꺼내려고 하는 모델의 인스턴스이고, 두번째 인자(created)는 boolean flag이다.
라고 한다.
그래서 총 2개의 인자를 받게 되는데 사실상 2번째 인자같은경우 우리가 사용하지 않기때문에 두번째 인자는 '_'으로 처리하였습니다.
3. templates
-board_write.html
{% extends "base.html" %}
{% block contents %}
<div class="row mt-5">
<div class="col-12">
<form method="POST" action=".">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_lable }}">{{ 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_lable }}"
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>
<button type="button" class="btn btn-primary" onclick="location.href='/boards/list/{{ board.id }}'">돌아가기</button>
</form>
</div>
</div>
{% endblock %}
-board_detail.html
{% 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>
<label for="tags">태그</label>
<span id="tags" class="form-control">
{{ board.tags.all|join:"," }}
</span>
</div>
<button class="btn btn-primary" onclick="location.href='/boards/list/'">돌아가기</button>
</div>
</div>
{% endblock %}
이후 적절한 위치에 태그를 입력받고 보여주면 끝입니다!
4. 마무리 멘트
이번 챕터에서 느낀것은 장고를 잘 다루기 위해서는 파이썬 문법을 잘 다뤄야 한다고 느꼇습니다. 지금이야 튜토리얼 형식으로 간단한 코드들만 작성해서 문제 될일 없겠지만 나중에 프로젝트를 제대로 시작할때는 파이썬 문법공부가 제대로 되어있어야 한다고 느끼며 알고리즘 공부하러 가봐야겠네요!! 이번 얼마 안남았으니 끝가지 열심히!! 감사합니다:)
'기술 > Django' 카테고리의 다른 글
django 커뮤니티 만들기-(9)python anywhere배포 (0) | 2021.06.03 |
---|---|
django 커뮤니티 만들기-(8)댓글 (0) | 2021.06.01 |
django 커뮤니티 만들기-(6)게시판(form ,view) (0) | 2021.06.01 |
django 커뮤니티 만들기-(5)게시판 구현(templates, url) (0) | 2021.06.01 |
django 커뮤니티 만들기-(4)회원가입, 로그인 구현(form) (0) | 2021.05.26 |