cleanded_data
딕셔너리를 생성(cleaned_data 딕셔너리에서 데이터를 가져온 후 .save()
호출)is_valid()
이후 .save()
호출 가능Django의 HTML input element 표현
HTML 렌더링 처리
주의사항
어플.forms.py
생성하기class ArticleForm(forms.FORM) :
title = forms.CharField(max_length= 10)
content = forms.CharField(widget = forms.Textarea)
어플.views.py
에서 forms.py
import 받기from .forms import ArticleForm
def new(request):
articleForm = ArticleForm()
context = {
'articleForm' : articleForm,
}
return render(request, 'articles/new.html', context)
해당페이지.html
{{ 넘겨줬던form인스턴스 }}
를 넣어주기인스턴스명.as_p
: 각각 input 태그를 p로 감싸줌인스턴스명.as_ul
: 각각 input 태그를 ul로 감싸줌인스턴스명.as_table
: 각각 input 태그를 table로 감싸줌어플.forms.py
에서 생성한 변수명에 따라 id
, name
이 자동으로 붙어짐required
{% extends 'base.html' %}
{% block content %}
<h1>NEW</h1>
<form action="{% url 'articles:create' %}" method="POST">
{% csrf_token %}
{{ articleForm }}
<input type="submit">
</form>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>
{% endblock %}
어플.forms.py
from django import forms
class ArticleForm(forms.Form) :
title = forms.CharField(max_length=10)
content = forms.CharField(widget = forms.Textarea)
REGION_A = 'seoul'
REGION_B = 'gwangju'
REGION_C = 'gumi'
REGION_D = 'daejeon'
REGION_CHOICES = [
(REGION_A, '서울'),
(REGION_B, '광주'),
(REGION_C, '구미'),
(REGION_D, '대전'),
]
region = forms.ChoiceField(choices = REGION_CHOICES)
만약 widget = radioselect를 선택해준다면?
region = forms.ChoiceField(choices = REGION_CHOICES, widget = forms.RadioSelect)
https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/
model을 통해 Form Class를 만들수 있는 Helper
일반 Form Class와 완전히 같은 방식(객체 생성)으로 view에서 사용 가능
Meta Class
어플.forms.py
fields= '__all__'
: 어떤 것을 사용할지exclude = ('title', )
: 어떤것을 제외하고 사용할지class ArticleForm(forms.ModelForm) :
class Meta :
model = Article
fields= '__all__' # 어떤 변수들을 사용할건지 지정
어플.views.py
modelFom 으로 정보를 받았을 때 더 편하게 받는법
ModelForm을 이용한 유효성 검사
유효성 검사는 크게 두 단계로 이루어진다.
(프론트방어)사용자가 HTML 페이지에서 내가 원하는 형태로 데이터를 작성할 수 있게 만든다.
(ex-required 속성을 줘서 작성하지 않으면 submit 하지 못하도록 만들기)
(서버단검증)사용자가 데이터를 submit 하면 서버 단에서 데이터 형태가 올바른지 다시 한번 검증한다.
(ex- 사용자가 required를 뻬버리고 submit을 눌렀을 경우, ModelForm에 있는 is_valid 메서드를 호출하여 다시 한번 검증한다.)
save mehtod
def create(request):
title = request.POST.get('title')
content = request.POST.get('content')
article = Article(title=title, content=content)
article.save()
return redirect('articles:detail', article.pk)
######를 이렇게 바꿀 수 있음
def create(request):
# 1. POST Dat에 들어있는 ModelForm 인스턴스를 생성한다.
form = ArticleForm(request.POST)
# 2. Form 에 들어있는 데이터에 대한 유효성 검사를 실시한다.
if form.is_valid() :
# 3. 새로운 Article 인스턴스를 생성하고 DB에 저장한다.
article = form.save()
# 4. 생성한 Article 인스턴스의 PK값과 함게 상세정보 페이지로 Redirect 한다.
return redirect('articles:detail', article.pk)
# 유효성 검사가 실패했을 경우
return redirect('articles:new')
어플.views.py
def create(request) :
"""
사용자가 /articles/create/로 요청을 보낸 경우,
1) GET : 비어있는 ModelForm 을 던진다.
2) POST : 데이터를 받아서 DB에 저장한다.
"""
if request.method == "POST" :
form = ArticleForm(request.POST)
if form.is_valid() :
article = form.save() # 저장한 Article객체 반환됨
return redirect('articles:detail', article.pk)
else :
form= ArticleForm()
# form에 들어올 수 있는 데이터 형태
# 1) GET 요청 : 사용자가 데이터를 입력할 수 있는 비어있는 form
# 2) POST 요청
# - 사용자가 입력한 데이터가 유효성 검사에서 실패한 경우
# - 에러 메시지를 포함한 form
context={
'form' : form,
}
return render(request, 'articles/create.html', context)
어플.templates/어플/create.html
{% extends 'base.html' %}
{% block content %}
<h1>CREATE</h1>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>
{% endblock %}
어플.form.py
class ArticleForm(forms.ModelForm) :
title = forms.CharField(
label='제목', # label에 보이는 글씨값 조정
widget=forms.TextInput( # 해당 HTML 요소 꾸미기
attrs={
'class' : 'my-title', # 띄어쓰기로 여러 클래스 입력가능
'placeholder' : '제목을 입력해주세요',
}
),
error_messages={
'required' : '입력값이 없는 상태로 오셨습니다.',
}
)
content = forms.CharField(
label="내용",
widget=forms.Textarea(
attrs={
'class' : 'my-content',
}
)
)
class Meta :
model = Article
fields= '__all__'
어플.views.py
def update(request, pk):
article = Article.objects.get(pk= pk)
if request.method == 'POST' :
form =ArticleForm(request.POST, instance=article) # 인스턴스를 넘겨주고 save를 하면 update를 하고, 인스턴스 안넘겨주고 save하면 새로운 인스턴스 create함
if form.is_valid() :
form.save()
return redirect('articles:detail', article.pk)
else :
form =ArticleForm(instance=article)
context = {
'form' : form,
'article' : article,
}
return render(request, 'articles/update.html', context)
어플.templates/어플/update.html
{% extends 'base.html' %}
{% block content %}
<h1>UPDATE</h1>
<form action="{% url 'articles:update' article.pk %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
<hr>
<a href="{% url 'articles:index' %}">[back]</a>
{% endblock %}
pip install django-bootstrap-v5
프로젝트.settings.py > INSTALLED_APPS
"bootstrap5"
추가하기{% load_bootstrap %}
을 {% extend %}
밑에 작성{% bootstrap_css %}
{% bootstrap_javascript %}
{{ 폼객체.as_p }}
로 썼던 것을 {% bootstrap form 폼이름 %}
으로 씀
<input type="submit">
을 밑에 코드로 수정
{% buttons %}
<button type=submit class="btn btn-primary">
Submit
</button>
{% endbuttons %}
만약 horizontal로 정렬된 form 을 쓰고 싶다면
{% bootstrap_form form layout='inline' %}
{% buttons submit='OK' reset="Cancel" %}{% endbuttons %}
하는 이유
base.html
이 굉장히 깔끔해짐navbar.html
를 만들고, navbar 코드만 넣는다.
프로젝트.templates
에 만듬. (공통으로 쓰는 것이기 때문에)<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
navbar 가 필요한 HTML 페이지에 include로 넣는다.
{% include navbar.html %}
프로젝트.settings
에 DIR에 프로젝트.templates
위치가 등록되어있어야함. Decorator(데코레이터)
Allowed HTTP methods
from django.views.decorators.http import require_http_method
require_http_methods()
- 특정 request 방식에 따른 접근 허용@require_http_methods(["GET", "POST"])
def my_view(request) :
...
pass
require_GET()
: GET method만 허용 - 이건 안씀require_POST()
: POST method만 허용require_safe()
: GET method만 허용/ GET method가 아니면 require not allowed 에러 발생