<!-- home/question_form.html -->
<h1>질문 등록 페이지</h1>
<!-- home/question_list.html -->
...
<a href="{% url 'home:question_create' %}">질문 등록하기</a>
버튼을 누르면 home앱의 question_create라는 경로로 이동한다. (아직 안 만듦)
# home/urls.py
urlpatterns = [
...
path('question_create', question_create, name="question_create"),
]
question_cerate라는 함수를 실행한다. (아직 안 만듦)
# home/views.py
...
def question_create(request):
return render(request, 'home/question_form.html')
페이지를 새로 만들어 연결까지 해 주었다.
# home/forms.py
from django import forms
from home.models import Question
class QuestionForm(forms.ModelForm): # 모델 폼을 상속받은 QuestionForm 클래스
class Meta: # 내부 Meta 클래스
model = Question
fields = ['subject', 'content']
위와 같은 클래스를 장고 폼이라고 한다. 장고 폼은 2개의 폼으로 구분할 수 있는데, forms.Form
을 상속받으면 폼이라고 하고, forms.ModelForm
을 상속받으면 모델 폼이라고 한다.
현재는 모델 폼을 만들었고, 모델 폼은 말 그대로 모델과 연결한 폼이며, 모델 폼 객체를 저장하면 연결된 모델의 데이터를 저장할 수 있다.
장고 모델 폼은 내부 클래스로 Meta 클래스를 반드시 가져야 하며, Meta 클래스에는 모델 폼이 사용할 모델과 모델의 필드들을 적어야 한다.
QuestionForm 클래스는 Qeustion 모델과 연결되어 있으며, 필드로 subject와 content를 사용한다고 정의하였다.
# home/views.py
...
from .forms import QuestionForm # QuestionForm 클래스 import 하기
...
def question_create(request):
a_form = QuestionForm() # QuestionForm 클래스로 생성한 객체 a_form을 사용할 것이다.
context = {'form' : a_form }
return render(request, 'home/question_form.html', context)
<!-- home/question_form.html -->
{% extends 'base.html' %}
{% block content %}
<div>
<h5>질문 등록</h5>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<!-- form이 views.py > question_create 함수에서 전달한 QuestionForm 객체이다. -->
<!-- {{ form.as_p }} 이 코드는 모델 폼과 연결된 입력 항목 subject, content에 값을 입력할 수 있는 HTML 코드를 자동으로 만들어 준다. -->
<button>저장하기</button>
</form>
</div>
{% endblock %}
# home/views.py
...
def question_create(request):
if request.method == 'POST':
a_form = QuestionForm(request.POST)
if a_form.is_valid():
question = a_form.save(commit=False) # 폼에 없는 필드인 create_date부분을 자동입력으로 모델을 설정하였기 때문에 a_form.save()라고 작성하여도 오류가 발생하지는 않는다.
question.save()
return redirect('home:question_list')
else: # request.method == 'GET'인 경우
a_form = QuestionForm() # QuestionForm 클래스로 생성한 객체 a_form을 사용할 것이다.
context = {'form' : a_form }
return render(request, 'home/question_form.html', context)
GET 방식
으로 질문 등록 화면이 나타나고, 저장하기 버튼을 누르면 POST 방식
으로 요청되어 데이터가 저장된다.GET 방식
의 경우, QuestionForm()과 같이 입력값 없이 객체를 생성했고, POST 방식
의 경우에는 QuestionForm(request.POST)처럼 화면에서 전달받은 데이터로 폼의 값이 채워지도록 객체를 생성했다. a_form.is_valid
함수는 POST 요청으로 받은 a_form이 유효한지 검사한다. 폼이 유효하지 않다면 폼에 오류가 저장되어 화면에 전달될 것이다.question = a_form.save(commit=False)
는 form으로 Question 모델 데이터를 저장하기 위한 코드이다. 여기서 commit=False
는 임시 저장을 의미한다. 즉, 실제 데이터는 아직 저장되지 않은 상태를 말한다. 이렇게 임시 저장을 사용하는 이유는 폼으로 질문 데이터를 저장할 경우 Question 모델의 create_date에 값이 설정되지 않아 오류가 발생하기 때문이다. (폼에는 현재 subject, content 필드만 있고 create_date 필드는 없다) 이러한 이유로 임시 저장을 한 question 객체를 반환받아 create_date에 값을 설정한 후 question_save()로 실제 저장하는 것이다.question = a_form.save()
를 수행하면 create_date 속성값이 없다는 오류 메시지가 나타난다.create_date = models.DateTimeField()
라고 작성하였다면 오류가 발생한다.
잘 생성된다.
# home/forms.py
...
class QuestionForm(forms.ModelForm): # 모델 폼을 상속받은 QuestionForm 클래스
class Meta: # 내부 Meta 클래스
model = Question
fields = ['subject', 'content']
# labels 코드 추가하기
labels = {
'subject' : '제목',
'content' : '내용',
}
모델폼을 이용하지 않고 create를 구현하기 위한 로직은 다음과 같다.
1. 글 작성하기 버튼을 클릭하면 -> question_new.html로 이동
2. 글을 작성하고 작성완료 버튼을 클릭하면 -> question_create 함수가 실행되어 글 작성을 완료한다.
<!-- question_new.html -->
{% extends 'base.html' %}
{% block content %}
<h1>질문 등록</h1>
<form action="#" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div>
<label>글 제목</label>
<input type="text" name="subject">
</div>
<div>
<label>글 내용</label>
<textarea name="content"></textarea>
</div>
<input type="submit" value="글 작성">
</form>
{% endblock %}
일단 form태그의 action 메소드는 빈칸으로 둔다. 글 작성 버튼을 누르면 action이 실행되어 create가 완료되게 할 것이다.
# views.py
def question_new(request):
return render(request, 'home/question_new.html')
# urls.py
...
path('question_new', question_new, name="question_new"), # 작성 페이지로 이동
페이지 연결까지 완료하였다.
<!-- question_list.html -->
...
<a href="{% url 'home:question_new' %}">질문 등록하기</a>
질문 등록하기 버튼을 누르면 question_new라는 이름을 가진 url이 실행된다.
def question_create(request):
if request.method == "POST":
subject=request.POST.get('subject') # HTML의 name에서 받아온 값을 subject에 담는다.
content=request.POST.get('content')
Question.objects.create(subject=subject, content=content)
return redirect('home:question_list')
<!-- question_new.html -->
{% extends 'base.html' %}
{% block content %}
<h1>질문 등록</h1>
<form action="{% url 'home:question_create' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div>
<label>글 제목</label>
<input type="text" name="subject">
</div>
<div>
<label>글 내용</label>
<textarea name="content"></textarea>
</div>
<input type="submit" value="글 작성">
</form>
{% endblock %}
글 작성 버튼을 누르면 form의 action이 실행된다. home앱의 question_create라는 이름을 가진 함수가 실행된다.