TIL#12

아직·2022년 9월 5일
0

Django Toy Project

목록 보기
12/13
post-thumbnail

1)

def item_new(request):
    if request.method == "POST":
        form = ItemForm(request.POST, request.FILES)
        if form.is_valid():
            item = form.save(commit=False)
            return redirect(item)
    else:
        form = ItemForm()

    return render(request, 'gallery/item_form.html', {
        'form': form,
    })

ModelForm에서 'commit=False' 옵션은 instance.save()를 지연시키고자 할 때 사용한다. instance를 생성하지만, 저장하지 않기 때문에 form에 내용을 기입하고 저장 버튼을 누르더라도 pk가 생성되지 않아서 reverse 접근에 실패하게 된다.

form.save()를 한다는 말이 instance.save()를 한다는 말과 동일하지 않음에 주의하자. django/forms/models.py의 BaseModelForm에서 instance.save() 관련 사항을 확인할 수 있는데, 공식 문서에 나온대로 "당장 저장하지 않는다." 차원으로 이해하는 게 좋을 것 같다.

2)

urlpatterns=[
... 
    path('<int:pk>/edit/', views.item_edit, name='item_edit'),
...
]
+
@login_required
def item_edit(request, pk):
    item = get_object_or_404(Item, pk=pk)

    if item.author != request.user:
        messages.error(request, '작성자만 수정할 수 있습니다.')
        return redirect(item)

    if request.method == "POST":
        form = ItemForm(request.POST, request.FILES, instance=item )
        if form.is_valid():
            item = form.save()
            return redirect(item)
    else:
        form = ItemForm(instance=item)

    return render(request, 'gallery/item_form.html', {
        'form': form,
    })
+
<hr/>
<a href="{% url 'gallery:item_list' %}">
    목록
</a>

<a href="{% url 'gallery:item_edit' item.pk %}" class="btn btn-info">
    수정
</a>

edit 기능을 추가하는 과정에서 'item_edit' 함수의 매개변수가 request뿐만 아니라 pk도 있다는 점과 따라서 html 파일에서도 url reverse 기능을 사용할 때 'item.pk' 인자도 넘겨준다는 점에 주목하자.

그리고 전달받은 pk를 이용해서 get_object_or_404 메커니즘으로 '어떤 item instance를 수정할 것인지' 결정해줘야 한다.(사실 결정이라고 이야기했지만, item을 정의했을 뿐 이용하기 전에는 결정이 아닌 셈이라고 생각한다.) item_detail 함수 역시 같은 코딩으로 시작한다.

item을 정의하는 것뿐만 아니라 이것을 '이용'하기 위해서는 request 이후 ModelForm에서 이를 instance 인자로 넘어주는 작업이 필요하다. 비로소 '결정'이 의미가 있어지는 순간이 아닐까?

작성자와 접근자를 비교하는 항목을 추가해서 잘못된 request에 대해 message 처리와 redirect 처리를 넘겨주었다.

3)

{{ item.description | linebreaks }}

db에 입력한 text를 가져올 때 줄 바꿈 옵션을 추가하려면 linebreaks나 linebreaksbr 옵션을 사용할 수 있다.

4)

IntegrityError at /gallery/new/
NOT NULL constraint failed: gallery_item.author_id
+

@login_required
def item_new(request):
    if request.method == "POST":
        form = ItemForm(request.POST, request.FILES)
        if form.is_valid():
            item = form.save(commit=False)
            item.author = request.user
            item.save()
            return redirect(item)
    else:
        form = ItemForm()

    return render(request, 'gallery/item_form.html', {
        'form': form,
    })

기존 __all__을 전달받았 던 ModelForm의 fields 영역에서 몇 개 만을 선택해주고 author는 선택하지 않았을 때, 기입된 form을 저장하면 해당 오류가 발생한다. 필수인 author 영역에 null이나 blank 옵션이 없기 때문이다.

is_valid()는 fields에 선택된 영역에만 기능하기 때문에 이와 전혀 다른 차원의 문제라고 할 수 있다.

정확히는 form instance.save() 시에 오류가 발생하므로 commit=False 옵션을 활성화하고 request.user를 author란에 우겨넣고 instance.save()를 진행한다.

활성화된 user를 이용하려면 @login_required도 필요할 것이다.

5)

form.is_valid() 이후에 데이터를 가져올 경우에는 form.cleaned_data['description']의 경로로 접근할 것. request.POST['description']은 바람직하지 못하다.

이는 source의 BaseForm 영역에서 (validator 기능뿐만 아니라) clean()도 갖추고 있으므로, 이를 거치면 데이터가 변환될 수 있기 때문이다.

0개의 댓글