Form은 사용자와 웹사이트를 연결하는 다리라고 할 수 있다.
단순히 서버에서 사용자에게 일방적으로 전달하던 것에서 Form을 통해 사용자가 서버로 정보를 전송할 수 있게 되었다.
대부분의 form은 대부분 동일한 작업을 반복한다.
Django Form은 이를 적은 코드로 쉽게 처리할 수 있도록 해준다.
기존의 방법대로 HTML에 직접 폼 태그를 작성하고,
백엔드에서는 POST method로 입력된 정보를 받아 처리한다.
<form method="POST">
{% csrf_token %}
<div><input type="text" name="title" maxlength="100" required></div>
<div><textarea name="content" cols="40" rows="10" required></textarea></div>
<div><input type="submit" value="저장"></div>
</form>
name
옵션에 백엔드가 어떤 데이터인지 구분할 수 있도록 이름을 지정해주어야 한다.csrf_token
: csrf_token은 임의의 난수값을 생성하여 세션에 저장한다. 또한 사용자의 요청시 난수값을 포함시켜 전송하는 역할을 한다. 이 난수값은 세션에 저장된다.if req.method == 'POST':
new_post = models.Post(
title = req.POST.get('title'),
content = req.POST.get('content'),
)
new_post.save()
req.POST.get('<name\>')
: HTML 태그에 선언했던 <name>
속성의 value를 가져올 수 있다.# forms.py
class PostForm (forms.Form):
title = forms.CharField(max_length= 100)
content = forms.CharField(widget=forms.Textarea())
forms.py를 통해 사용할 django 폼을 한번에 모아 관리할 수 있다.
CharField
는 기본적으로type=’text’
인 input 태그가 된다.widget
옵션을 이용하면 된다. 위 코드의 경우 content를 받기 위해 input태그 대신 textarea 태그를 사용할 것이다.from . import forms
def create_form(req):
form = forms.PostForm()
if form.is_valid():
new_post = models.Post(
title = form.cleaned_data['title'],
content = form.cleaned_data['content'],
)
new_post.save()
return redirect('/blog/')
forms.py
에 선언한 폼을 가져와서 이용하면 된다.is_valid()
: Form 클래스로 선언한 유효성 검사를 만족하는지 여부를 반환하는 함수cleaned_data
: 유효성 검사를 만족한 값만 담겨있다. 또한, DateField에 저장될 값을 일정한 Format으로 변환해주거나, Field에 맞게 형변환을 해주는 등 DB에 일관적인 형태의 데이터가 저장될 수 있도록 정제된 데이터를 제공한다.이렇게 자동으로 유효성 검사를 수행해주며, DB가 일관성있게 관리될 수 있도록 데이터 정제까지 해준다.
<form method="POST">
{% csrf_token %}
<table>
{{form}}
</table>
<div><input type="submit" value="저장"></div>
</form>
Django Form을 이미 백엔드에서 정의하여 데이터로 보내주고 있기 때문에, HTML에서 작성할 필요가 없다.
대신 넘겨받은 변수명에 맞게 폼이 들어갈 자리를 지정해주면 된다.
# forms.py
class PostModelForm(forms.ModelForm):
class Meta:
model = models.Post
fields = ('title, content, published_at')
ModelForm
을 상속받은 클래스 안에 Meta
라는 또다른 클래스가 들어가는 형식의 문법을 사용한다.fields
변수명에 튜플 또는 리스트 형태로 선언한다.# views.py
def create_model_form(req):
if req.method == "POST":
form = forms.PostModelForm(req.POST)
if form.is_valid():
form.save()
return redirect( "/blog/" )
II. Django Form을 통한 처리
와 동일하다.{% csrf_token %}
이 바로 CSRF를 자동으로 생성해주는 django의 기능이다.https://docs.djangoproject.com/ko/4.0/intro/tutorial01/
설문조사 Pool을 간단히 구현하는 튜토리얼 예제이다.
질문 Question
과 질문에서 선택할 수 있는 Choice
의 일대다 관계로 이루어진 모델 구조를 갖고 있다.
__str__
: 출력 시 표시될 텍스트를 설정하는 매직메서드관리자 페이지에서 어떤 데이터가 어떤 내용을 담고 있는지 확인할 수 없다.
def __str__(self):
return f"{self.question.question_text} : {self.choice_text}"
이제 기존 질문의 내용과 선택지의 내용을 한눈에 확인할 수 있다.
관리자 페이지에서 보이는 필드를 추가할 수 있다.
우선 관리자페이지의 설정을 담당하는 admin.py
에 클래스를 선언하여 등록해주어야 한다.
# Customizing
class QuestionAdmin(admin.ModelAdmin):
list_display = ('question_text', 'publish_date', 'was_published_recently')
admin.site.register(models.Question, QuestionAdmin)
admin.site.register
메서드를 통해 클래스와 모델을 연결한다.list_display
에 선언한 필드가 추가되었다.관리자 페이지에서는 원하는 데이터만 필터링하여 볼 수 있는 필터 기능을 제공한다.
이것 역시 원하는 페이지에 추가하거나 커스터마이징 할 수 있다.
# Customizing
class QuestionAdmin(admin.ModelAdmin):
list_display = ('question_text', 'publish_date', 'was_published_recently')
list_filter = ('publish_date',)
admin.site.register(models.Question, QuestionAdmin)
list_display
와 동일한 방식으로 필터로 사용할 필드명을 리스트 또는 튜플 형태로 선언하면 된다.위 상황에서 하나의 질문에 있는 선택지를 모두 바꾸고 싶다고 가정하자.
현재 상황에서는 일일히 선택지 하나씩 하나씩 들어가 수정해주어야 한다.
하지만 Inline을 이용하면 Question에서 관계를 맺고있는 Choice를 모두 불러와 한꺼번에 처리할 수 있다.
class ChoiceInline(admin.TabularInline):
model = models.Choice
extra = 0
class QuestionAdmin(admin.ModelAdmin):
# ... 중략 ...
inlines = (ChoiceInline,)
admin.TabularInline
또는 admin.StackedInline
을 상속받는다. 두 클래스의 차이는 화면에 표시될 모양의 차이이며 기능은 동일하다.model
변수명을 사용하여 인라인안에 들어갈 모델을 입력한다.extra
옵션을 통해 생성을 원할 때 별도로 생성버튼을 누르지 않아도 양식이 미리 표시되게 끔 할 수 있다.화면 길이상 잘렸지만, 스크롤을 내리면 다른 CHOICE들이 모두 보인다.
세션과 쿠기는 웹을 위한 저장 공간이다.
둘의 차이점은 저장 장소인데, 클라이언트에 저장하면 쿠키, 서버에 저장하면 세션이다.
사용자를 식별하고, 사용자 행동에 대한 정보를 기억하기 위해 필요하다.
def cookie_counter(req):
visits = int(req.COOKIES.get('visits', 0)) + 1
res = HttpResponse(f"너를 위해 구웠지: {visits}")
res.set_cookie('visits', visits)
return res
visits = int(req.COOKIES.get('visits', 0)) + 1
req.COOKIES
는 딕셔너리이다..get()
메서드를 통해 key 값으로 조회가 된다면 해당 값을 가져오고, 없다면 default 값(0)을 가져온다.def session_counter(req):
req.session['count'] = req.session.get('count', 0) + 1
return HttpResponse( f"이건 니꺼 아님: {req.session['count']}")
req.session['count'] = req.session.get('count', 0) + 1
django는 놀랍게도 회원 페이지 기능까지 제공하기 때문에 별도로 구현할 필요가 없다.
심지어 기본 템플릿도 제공된다.
물론 실무 수준에서는 login페이지를 직접 만들어 사용하지만, 빠르게 개발하려고 할 때 이보다 유용한 것이 없다.
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("", include('django.contrib.auth.urls')),
]
urls.py
에 위와 같은 설정을 해주면 된다./accounts/login/
과 같은 형대가 되도록 subpath도 설정할 수 있다.django 기본 설정으로 이들은 베이스 템플릿 경로의 registraion/
디렉토리에서 회원 페이지에 표시할 템플릿을 찾는다.
django 기본 설정으로는 로그인후 account/profile
페이지로 리다이렉션 된다.
이를 변경하고 싶다면 settings.py
를 다음과 같이 수정하자.
LOGIN_REDIRECT_URL = '/blog/'
이제 로그인 후 이 주소로 이동하게 된다.