실습
먼저, 우리는 Blog 객체를 만드는데 있어서
글쓰기
를 눌러 만들 수 있었다.이 과정을 사실 앞에서 배운 내용처럼, form 클래스를 html에 만들어놓고,
값을 넘겨 만들 수 있다.
하지만 이번에는 그 form 이라는 것을
form.py
라는 것에 분리해서 만들고이걸 import 해서
views.py
에 함수를 만드는데에 있어조금더 간결하고 수월한 방향으로 만드는 방법을 배울 것이다.
먼저, blog 라는 앱안에
form.py
를 만들어주자.우리는 이 form 으로 부터 blog에 관해 입력을 넘길 것이기에 이 앱안에 만들어준다.
그럼 우리는 뭘 import 해줘야 하냐면,
# form.py from django import forms from .models import Blog
모델에 값을 넣어줄 것이기 때문에, Blog 객체 역시 import 해준다.
자, 이제 클래스를 만들어줄 건데,
우리는 모델 기반의 form을 만들고 싶으니 아래와 같이 써준다.
# form.py from django import forms from .models import Blog class BlogPost(forms.ModelForm):
만약 임의의 form을 만들고 싶다면
class BlogPost(forms.Form):
이렇게 만들어주면 된다.
자, 다시 돌아와서,
# form.py from django import forms from .models import Blog class BlogPost(forms.ModelForm): class Meta: model = Blog fields = ['title', 'body']
Blog 모델을 기반으로 한, 입력공간을 만들건데,
그중에서
title
,body
를 받는 녀석을 만들거다.자 그러면, 다시 옛날에 배웠던 것을 상기해보자.
먼저, 사용자가 글을 쓰고 싶을 때, 가장 먼저 만지는 URL 부터 설계를 해보자.
블로그 안에 URL을 저번에 따로 처리 했으므로 path 함수의 첫번째 인자는,
blog/newblog/
이런식으로 적어줄 필요가 없다.# blog.urls.py urlpatterns = [ path('<int:blog_id>', views.detail, name = "detail"), path('new', views.new, name = "new"), path('create', views.create, name = "create"), path('newblog', views.blogpost, name = "newblog"), ]
자 URL을 만들었으면, 이번에는
views.py
를 만들어야 한다.우리는 여기서 작성한
form.py
로 부터 form을 가져다가 쓸거니까import부터 해준다.
# blog.views.py ~~~ from .form import BlogPost
그리고 나서
blogpost
함수를 만들어 줘야 한다.여기서 두가지 기능을 만들어 줘야 하는데,
# blog.views.py def blogpost(request): # 1. 입력된 내용을 처리하는 기능 => POST # 2. 빈 페이지를 띄워주는 기능 => GET
코드로 만들어 보자.
# blog.views.py def blogpost(request): if request.method == 'POST': else: form = BlogPost() return render(request, 'new.html', {'form':form})
빈 페이지를 띄울때는, 그냥
form.py
로 부터, BlogPost 객체를 만들어서html에 출력해주면 된다.
1번 문제에 대해서 생각해보자.
# blog.views.py def blogpost(request): if request.method == 'POST': form = BlogPost(request.POST) else: form = BlogPost() return render(request, 'new.html', {'form':form})
여기까지 해주면, 요청한 것중 POST 로 보낸 것을 인자로 받아,
form.py
에서 만들어준 메타클래스에서 자동으로 form 안에 받아준다.그리고 나서, 이 form에 제대로 들어왔는지에 대한 검사가 필요하다.
그런데, Blog 객체는
pub_date
라는 녀석도 모델안에 넣어줘야 한다.지금 만약 이대로
form.save()
를 해버리면, 그 녀석은 적용되지 않게 된다.그러니까, 지금까지 작성한 form이 담긴 객체만 리턴하고,
이녀석을 저장하는 일은 추후에 해주도록 만들어야 한다.
그 방법은,
form.save(commit=False)
로 구현가능하다.# blog.views.py def blogpost(request): if request.method == 'POST': form = BlogPost(request.POST) if form.is_valid(): post = form.save(commit=False) post.pub_date = timezone.now() else: form = BlogPost() return render(request, 'new.html', {'form':form})
여기서 알 수 있는 사실은, 결국
post = form
이런식으로 선언해주게 되었을 때,post
는 결국 Blog 객체이라는 사실을 알 수 있다.그렇기 때문에
post.pub_date
와 같이 기존에create
함수에서 했듯 처리할 수 있는 것이다.그러면 굳이
form.py
를 사용하는 이유는 무엇일까?이렇게 사용했을 때 장점은, 내가 일일히
views.py
에서 어떤 변수는 어떻게 받아서 넣어줘!와 같은 작업을 할 필요 없이 자동으로 넣어준다는 장점이 있다.
잠깐 기존에 했던 방식을 보고가면,
# blog.views.py def create(request): blog = Blog() blog.title = request.GET['title'] blog.body = request.GET['body'] blog.pub_date = timezone.datetime.now() blog.save() return redirect('/blog/' + str(blog.id))
이런식으로 작성해줬다.
title은 GET 방식으로 받아서 넣어주고, body는 어쩌구저쩌구.
그런데
form.py
에 다가, 난 어떤 모델 객체를 쓸거고,request 를 받았을 때, form의 이름이
title
이면 자동으로 form 에다가 담아줘!이런식으로 뚝딱! 처리할 수 있다.
만약에 지금처럼
title
,body
두가지 말고 훨씬 입력 받을게 많다면이런 방식이 훨씬 효율적이다!
이어서 가보자.
# blog.views.py def blogpost(request): # 1. 입력된 내용을 처리하는 기능 => POST if request.method == 'POST': form = BlogPost(request.POST) if form.is_vaild(): post = form.save(commit=False) post.pub_date = timezone.now() post.save() return redirect('home') # 2. 빈 페이지를 띄워주는 기능 => GET else: form = BlogPost() return render(request, 'new.html', {'form':form})
이제 저장해주고, home 화면으로 돌아가면 된다.
이제
new.html
에 출력해주면 완료다.<!-- new.html --> <!-- 원래 작성했었던 파일 --> <div class = "container"> <form action="{% url 'create' %}"> <h4> 제목 : </h4> <input type = "text" name = "title"> <br> <br> <h4> 본문 : </h4> <textarea cols=40 rows=10 name = "body"></textarea> <br> <br> <input class="btn btn-dark" type = "submit" value = "제출하기"> </form> </div>
저 위에 있는 녀석을 이렇게 바꿔주자.
<!-- new.html --> {% extends 'base.html' %} {% block contents %} <div class = "container"> <br> <form method = "POST"> {% csrf_token %} <table> {{ form.as_table }} </table> <br> <input class = "btn btn-dark" type = "submit" value="제출하기"> </form> </div> {%endblock%}
아까보다 훨씬 해줄일이 없어졌다!
<table>
태그 안에{{ form.as_table }}
을 써주면 알아서 작성된다!이래서 사용하는 거다
이 때,
{{ form.as_p }}
같은 걸 써주면 p태그로 감싸서 출력된다.이제 서버를 켜고,
서버주소/newblog
로 들어가보자.잘 작동되는 것을 볼 수 있다.
만약 입력값을 안넣고 제출을 누르면?
다시 그 화면이 뜨면서,
이런화면이 뜨는 것을 확인할 수 있다.
한단계만 더 나아가서,
모델기반이 아니고, 임의의 입력공간을 만들어보자.
# form.py from django import forms from .models import Blog class BlogPost(forms.Form): email = forms.EmailField() files = forms.FileField() url = forms.URLField() words = forms.CharField(max_length=200) max_number = forms.ChoiceField(choices = [('1','one'), ('2','two'), ('3', 'three')])
ChoiceField
뒤에 나오는 인자는,one
,two
,three
를 각각, 1,2,3 으로 간주하겠다!라는 의미이다.
이렇게 바꿔주고 실행해보면,
이렇게 뜬다!
이렇게 사용할 수 있고, 이걸 받아서 어떻게 할지는 다시 views.py 에서 관리해 줘야 한다.
그런데 이렇게 되었을 때는, 모델 인터페이스를 흉내내서 구현을
form.py
에 해줘야한다.from django import forms class PostForm(forms.Form): title = forms.CharField() content = forms.CharField(widget=form.Textarea) # ModelForm.save 인터페이스를 흉내내어 구현 def save(self, commit=True): post = Post(**self.cleaned_data) if commit: post.save() return post
이런식으로.
이건 추가적으로 공부하는 걸로 하고, 지금은 넘어가자.