완숙의 블로그

[Django] Week 6-2 form Practice 본문

Programing Language/Web_Django

[Django] Week 6-2 form Practice

완숙 2019. 3. 9. 11:51

실습

  1. 먼저, 우리는 Blog 객체를 만드는데 있어서 글쓰기 를 눌러 만들 수 있었다.

    이 과정을 사실 앞에서 배운 내용처럼, form 클래스를 html에 만들어놓고,

    값을 넘겨 만들 수 있다.

  2. 하지만 이번에는 그 form 이라는 것을 form.py 라는 것에 분리해서 만들고

    이걸 import 해서 views.py 에 함수를 만드는데에 있어

    조금더 간결하고 수월한 방향으로 만드는 방법을 배울 것이다.

  3. 먼저, blog 라는 앱안에 form.py 를 만들어주자.

    우리는 이 form 으로 부터 blog에 관해 입력을 넘길 것이기에 이 앱안에 만들어준다.

  4. 그럼 우리는 뭘 import 해줘야 하냐면,

    # form.py
    from django import forms
    from .models import Blog
    

    모델에 값을 넣어줄 것이기 때문에, Blog 객체 역시 import 해준다.

  5. 자, 이제 클래스를 만들어줄 건데,

    우리는 모델 기반의 form을 만들고 싶으니 아래와 같이 써준다.

    # form.py
    from django import forms
    from .models import Blog
    
    class BlogPost(forms.ModelForm):
    
  6. 만약 임의의 form을 만들고 싶다면

    class BlogPost(forms.Form):
    

    이렇게 만들어주면 된다.

  7. 자, 다시 돌아와서,

    # form.py
    from django import forms
    from .models import Blog
    
    class BlogPost(forms.ModelForm):
        class Meta:
            model = Blog
            fields = ['title', 'body']
    

    Blog 모델을 기반으로 한, 입력공간을 만들건데,

    그중에서 title, body 를 받는 녀석을 만들거다.

  8. 자 그러면, 다시 옛날에 배웠던 것을 상기해보자.

    먼저, 사용자가 글을 쓰고 싶을 때, 가장 먼저 만지는 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"),
    ]
    
  9. 자 URL을 만들었으면, 이번에는 views.py 를 만들어야 한다.

    우리는 여기서 작성한 form.py 로 부터 form을 가져다가 쓸거니까

    import부터 해준다.

    # blog.views.py
    ~~~
    from .form import BlogPost
    
  10. 그리고 나서 blogpost 함수를 만들어 줘야 한다.

    여기서 두가지 기능을 만들어 줘야 하는데,

    # blog.views.py
    def blogpost(request):
        # 1. 입력된 내용을 처리하는 기능 => POST
        # 2. 빈 페이지를 띄워주는 기능 => GET
    
  11. 코드로 만들어 보자.

    # blog.views.py
    def blogpost(request):
        if request.method == 'POST':
            
        else:
            form = BlogPost()
            return render(request, 'new.html', {'form':form})
    

    빈 페이지를 띄울때는, 그냥 form.py 로 부터, BlogPost 객체를 만들어서

    html에 출력해주면 된다.

  12. 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 안에 받아준다.

  13. 그리고 나서, 이 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 에서 어떤 변수는 어떻게 받아서 넣어줘!

    와 같은 작업을 할 필요 없이 자동으로 넣어준다는 장점이 있다.

  14. 잠깐 기존에 했던 방식을 보고가면,

    # 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 두가지 말고 훨씬 입력 받을게 많다면

    이런 방식이 훨씬 효율적이다!

 

  1. 이어서 가보자.

    # 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 화면으로 돌아가면 된다.

  2. 이제 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>
    
  3. 저 위에 있는 녀석을 이렇게 바꿔주자.

    <!-- 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 }} 을 써주면 알아서 작성된다!

    이래서 사용하는 거다

  4. 이 때, {{ form.as_p }} 같은 걸 써주면 p태그로 감싸서 출력된다.

  5. 이제 서버를 켜고,

    서버주소/newblog 로 들어가보자.

    잘 작동되는 것을 볼 수 있다.

  6. 만약 입력값을 안넣고 제출을 누르면?

    다시 그 화면이 뜨면서,

    2019-03-04 9 24 26

 

이런화면이 뜨는 것을 확인할 수 있다.
  1. 한단계만 더 나아가서,

    모델기반이 아니고, 임의의 입력공간을 만들어보자.

    # 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 으로 간주하겠다!

    라는 의미이다.

    이렇게 바꿔주고 실행해보면,

  2. 이렇게 뜬다!

    2019-03-04 9 30 40

    이렇게 사용할 수 있고, 이걸 받아서 어떻게 할지는 다시 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
    

    이런식으로.

    이건 추가적으로 공부하는 걸로 하고, 지금은 넘어가자.

Comments