Django

Django Form Class

monster route 2024. 8. 17. 03:13

Django Form Class

 

일부 반복되는 작업 및 코드를 줄일 수 있는 기능으로 Model과 흡사한 형식으로 진행된다.

폼에 입력받고 싶은 데이터 형식을 정의한 후, 그렇게 정의해놓은 걸 기준으로 자동으로 폼이 생성되게 해준다.

 

 

1) Form 선언하기

 

articles/ forms.py 

from django import forms

class ArticleForm(forms.Form):
    title = forms.CharField(max_length=50)
    content = forms.CharField() # max_lenth를 지정하지 않으면 길이 제한 없게 입력받는 형식이 됨

  • Model과 비슷하게 이 Form에서 입력받고자 하는 데이터에 대한 내용을 작성한다.
  • 형식이나 속성도 일부 Model과 비슷하다.

 

2) Form 적용하기

...
{{ form.as_p }}
...

 

현재 new.html기존의 form이 있다. 

 

여기서 우리가 위에서 지정한 제목 title이랑 내용 content 부분을 지워주고

 

 

얘로 바꿔주면 됨  →  {{ forms.as_p }} 

신기🫢

 

forms는 context로 내용을 받아온거기 때문에 view로 가서 받아올 수 있게 작성해줘야 한다.

 

 

views.py 열어서

우리가 만든 클래스 ArticleForm class를 뷰에서 만들어주면 된다.

 

forms에서 ArticleForm 임포트 해주고

from .forms import ArticleForm

 

이렇게 forms 가져오고

context에 담아서 인자로 넘겨주면 된다.

 

 

서버실행 해보면 잘 나오는 걸 볼 수 있다. 왜 이렇게 감동이지..🥹 ㅎㅎ

근데...🤔 

 

이럴 때 쓰는게

 

Form Widget

 

  • 웹 페이지에서 Form Input 요소가 어떻게 렌더링 되어서 보여질지 정의한다.
  • Form Fields에 할당해서 사용한다.

*공식문서

 

articles/forms.py (text field)

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)

from django import forms

class ArticleForm(forms.Form):
    # 앞은 데이터베이스에 저장될 값, 뒤는 사용자에게 보여질 값
    GENRE_CHOICES = [
        ("technology", "Technology"),
        ("life", "Life"),
        ("hobby", "Hobby"),
    ]

    title = forms.CharField(max_length=10)
    content = forms.CharField(widget=forms.Textarea)
    genre = forms.ChoiceField(choices=GENRE_CHOICES)

 


 

Django Model Form Class

 

알아서 Model을 참조해 Form을 만들어주는 ModelForm Class

 

폼 클래스와 마찬가지로 articles/forms.py에서 만들어주면 된다.

 

폼 클래스에서는 (forms.Form)을 상속받았다면, 얘는 (forms.ModelForm)을 상속받는다.

from django import forms

from articles.models import Article

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = "__all__"
        # exclude = ["title"] 제외하고자 하는 옵션

 

 

 

어떤 Model을 참조해야 되는지 알려주는 코드 : Meta class 

class Meta:

 

 

이 model에 있는 모든 field에 대해서 입력을 받겠다는 의미 : "__all__"

fields = "__all__"

 

 

 

서버 실행 해보면

 

에러 없이 한번에 되니 세상을 가진 것 같다...ㅎㅎ 

 


 

view에서 Django Model Form 사용하기

게시글이 작성됐다면, 폼에는 반드시 데이터가 채워져서 저장되었을거다.

 

기존에 작성했던 코드↓ 

def create(request):
	title = request.POST.get("title")
	content = request.POST.get("content")
	article = Article.objects.create(title=title, content=content)
	return redirect("article_detail", article.pk)

 

 

즉, Form에 데이터가 채워져있는 상태로 요청을 받도록 코드를 수정해보자.

 

→ articles/views.py 

...
def create(request):
  form = ArticleForm(request.POST) # form에 request.POST에 있는 데이터 채워
  if form.is_valid(): # form 형식에 맞으면
      article = form.save() # 저장하고 해당 객체 반환 
      return redirect("article_detail", article.id)
  return redirect("new")
...

 

 

이렇게 수정해주면, 서버 실행해서 확인해봐도 데이터가 채워져야만 저장이 되는 걸 확인할 수 있다.

 

 

🤔 조금 더 생각해보자

 

현재 new 함수create 함수가 많이 흡사하니까

def new(request):
    form = ArticleForm()
    context = {
        "form": form,
    }
    return render(request, "new.html", context)

 

⇒ 그냥 create 함수 하나로 처리해보자.

  • request가 GET 방식으로 들어오면 비어있는 Form 렌더링해서 주고, POST 방식으로 들어오면 데이터 채워서 보낸거니까 새로운 article을 생성하면 된다.

 

new - create 수정하기

 

  • articles/views.py 로 들어와서 create 코드 수정
def create(request):
  if request.method == "POST":
      form = ArticleForm(request.POST)
      if form.is_valid():
          article = form.save()
          return redirect("article_detail", article.id)
  else:
      form = ArticleForm()

  context = {"form": form}
  return render(request, "create.html", context)

 

 

  • 이제 new 함수필요 없어졌으니까 지워주고, urls.py 들어가서 path도 지워준다.
  • new.html을 create.html로 변경해준다.
{% extends "base.html" %}


{% block content %}
<h1>New Article</h1>

<form action="{% url 'create' %}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">저장</button>
</form>
{% endblock content %}

 

 

  • articles.html

 

{% extends 'base.html' %}

{% block content %}
<h1>Articles</h1>
<a href="{% url 'create' %}">새 글 작성하기</a> # 'new'를 'create'로 변경
{% for article in articles %}
     <a href="{% url 'article_detail' article.pk %}">
        <p>[ {{ article.pk }} ] {{ article.title }}</p>
     </a>
    
{% endfor %}

{% endblock content %}

 

 

 

edit - update

 

edit과 update 얘네도 하나로 합쳐주자.

 

로직을 살펴보자 🤔

 

update

  • 일단, get으로 들어오든 post로 들어오든 조회해야 한다.
  • 만약, request.method가 POST방식이면, POST로 넘어온 데이터로 새로운 Article을 만들건데, 원래의 article에 업데이트 해야해.
  • 만약에, 이 폼에 채워진 데이터가 유효하다면 저장해. article = form.save
  • 저장한 후에는 article_detail(게시글 상세페이지)로 리다이렉트

edit

  • edit은 게시글을 수정해주는 것이기 때문에, 폼이 비어있으면 안 된다. 채워져있는 폼을 수정해주는 거다. 
  • 이전에 작성했던 데이터는 article 개체에 들어있다. article 개체를 form에 넣는게 instance=article이므로 
form = ArticleForm(instance=article)
  • ↑ 이렇게 하면 이 article에 들어있는 title과 content를 빼서 form에 채운 상태로 작성된다.
  • 이렇게 데이터를 채워서 모델 폼을 만들어 놓고나서, context 만들어서 렌더링
def update(request, pk):
    article = Article.objects.get(pk=pk)
    if request.method == "POST":
        form = ArticleForm(request.POST, instance=article)
        if form.is_valid():
            article = form.save()
            return redirect("article_detail", article.pk)
    else:
        form = ArticleForm(instance=article)
    context = {
        "form": form,
        "article": article,
    }
    return render(request, "update.html", context)

 

마찬가지로 이제 edit 필요없음

뷰에서 edit 함수 지우고, urls에서도 지워주고, 코드 확인해서 그 외 edit 이 쓰이고 있으면 다 지워주면 됨.

 

edit.html 도 update.html 로 바꿔주고 코드도 수정

{% extends "base.html" %}

{% block content %}
<h1>Update Article</h1>

<form action="{% url 'update' article.pk %}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">수정</button>
</form>

<a href="{% url 'article_detail' article.pk %}">이전으로</a>
{% endblock content %}

 

 

잘 된다. ㅎㅎ 이제 서버 실행했을 때 에러나면 수정 바로잡는 법도 조금 익숙해진 것 같다😊