๐Ÿ”ฅDjango ๊ธฐ์ดˆ - ๊ณต๋ถ€์‹œ๊ฐ„ ๊ธฐ๋ก๊ธฐ ๋งŒ๋“ค๊ธฐ(2)_์ˆ˜์ •์ค‘

HY_1023ยท2026๋…„ 3์›” 23์ผ

MENTOS

๋ชฉ๋ก ๋ณด๊ธฐ
14/19
post-thumbnail

https://www.figma.com/design/wDh3su4KrlhkzOM1d7vKBT/Django-%EA%B8%B0%EC%B4%88---%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2-?node-id=17-98&t=v5jE7SjThGqnU9an-1


https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B02


์ด๋ฒˆ ํŽธ๋„ ๊ผญ ์ง์ ‘ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜๋ณตํ•ด๋ณด์„ธ์š”.ํŠนํžˆ ์•„๋ž˜ ํ๋ฆ„์€ ๋ฐ˜๋“œ์‹œ ์†์— ์ตํ˜€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

GET
โ†’ ํผ ๋ณด์—ฌ์ฃผ๊ธฐ

POST
โ†’ ๊ฒ€์ฆ
โ†’ ์ €์žฅ
โ†’ redirect
์ด ํŒจํ„ด์ด Django Form ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.


ํ•ต์‹ฌ๋งŒ ๊ธฐ์–ตํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค:

GET = ๋ณด์—ฌ์ฃผ๊ธฐ / POST = ์ฒ˜๋ฆฌํ•˜๊ธฐ / redirect = ๋‹ค์Œ ์žฅ์†Œ๋กœ ๋ณด๋‚ด๊ธฐ

์ด ์„ธ ๊ฐ€์ง€๊ฐ€ ์›น์˜ ๋ชจ๋“  ๋™์ž‘์˜ ๊ธฐ๋ณธ์ž…๋‹ˆ๋‹ค. ๋” ๊ถ๊ธˆํ•œ ๋ถ€๋ถ„ ์žˆ์œผ๋ฉด ๋ง์”€ํ•ด ์ฃผ์„ธ์š”!


GET vs POST ์ฐจ์ด

https://velog.io/@hy_1023/GET-vs-POST-%EC%B0%A8%EC%9D%B4


๊ทธ์ „์—1ํŽธ์—์„œ 0๋ฒˆ~3๋ฒˆ

2~. 4๋ฒˆ~5๋ฒˆ

3~6. 6๋ฒˆ~10๋ฒˆ

7~10. 11๋ฒˆ~14๋ฒˆ

11~14. 15๋ฒˆ~17๋ฒˆ
15~18. 18๋ฒˆ~22๋ฒˆ
19~20. 23๋ฒˆ~25๋ฒˆ
21~. 27๋ฒˆ
22~. 28๋ฒˆ

๊ทธ์™ธ~ 29๋ฒˆ~31๋ฒˆ


Django CRUD ๊ฐ ๊ธฐ๋Šฅ ์—ญํ• 


  1. ModelForm ๋งŒ๋“ค๊ธฐ
# models.py์˜ ํ•„๋“œ๋ฅผ ์ž๋™์œผ๋กœ HTML ํผ์œผ๋กœ ๋ณ€ํ™˜
class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content']

DB ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž…๋ ฅ ํผ์„ ์ž๋™ ์ƒ์„ฑํ•ด์ฃผ๋Š” ์—ญํ• 


์งˆ๋ฌธ

models.py์˜ ํ•„๋“œ๋ฅผ ์ž๋™์œผ๋กœ HTML ํผ์œผ๋กœ ๋ณ€ํ™˜ class PostForm(ModelForm): class Meta: model = Post fields = ['title', 'content'] > DB ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž…๋ ฅ ํผ์„ ์ž๋™ ์ƒ์„ฑํ•ด์ฃผ๋Š” ์—ญํ•  ๋ชจ๋ธํผ์€ ์žฅ๊ณ ๋‚ด์žฅ ํ•จ์ˆ˜์ธ๊ฑด๊ฐ€?

๋‹ต๋ณ€

Django ๋‚ด์žฅ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค

์–ด๋””์„œ ๊ฐ€์ ธ์˜ค๋‚˜์š”?

# Django ๋‚ด์žฅ ๋ชจ๋“ˆ์—์„œ import
from django import forms

class PostForm(forms.ModelForm):  # Django๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํด๋ž˜์Šค ์ƒ์†
    class Meta:
        model = Post
        fields = ['title', 'content']

ModelForm์ด ์ž๋™์œผ๋กœ ํ•ด์ฃผ๋Š” ๊ฒƒ

๊ธฐ๋Šฅ์„ค๋ช…
ํ•„๋“œ ์ž๋™ ์ƒ์„ฑ๋ชจ๋ธ์˜ ํ•„๋“œ๋ฅผ ์ž๋™์œผ๋กœ HTML <input>์œผ๋กœ ๋ณ€ํ™˜
์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์ž…๋ ฅ๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ์ž๋™ ๊ฒ€์ฆ
DB ์ €์žฅ.save() ํ•œ ์ค„๋กœ DB์— ๋ฐ”๋กœ ์ €์žฅ

์ง์ ‘ ๋งŒ๋“ค ๋•Œ vs ModelForm ๋น„๊ต

# โŒ ์ง์ ‘ ๋งŒ๋“ค ๋•Œ (๊ธธ๊ณ  ๋ณต์žก)
<input type="text" name="title">
<input type="text" name="content">
# ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋„ ์ง์ ‘ ์ž‘์„ฑ...
# DB ์ €์žฅ๋„ ์ง์ ‘ ์ž‘์„ฑ...

# โœ… ModelForm ์‚ฌ์šฉ (๊ฐ„๋‹จ!)
form = PostForm()  # ๋!
form.save()        # DB ์ €์žฅ๋„ ํ•œ ์ค„!

๊ฒฐ๋ก 

Django ๋‚ด์žฅ ํด๋ž˜์Šค โœ…
๋ณ„๋„ ์„ค์น˜ ๋ถˆํ•„์š” โœ…
from django import forms ๋กœ ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ โœ…

๐Ÿ’ก Django๊ฐ€ ๋ฐ˜๋ณต์ ์ธ ํผ ์ž‘์—…์„ ์ž๋™ํ™”ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ๊ฐ•๋ ฅํ•œ ๋‚ด์žฅ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค!


2. ์ƒ์„ฑ (Create)

์‚ฌ์šฉ์ž๊ฐ€ ํผ์— ๋ฐ์ดํ„ฐ ์ž…๋ ฅ โ†’ DB์— ์ƒˆ ๋ฐ์ดํ„ฐ ์ €์žฅ
์˜ˆ) ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ, ํšŒ์›๊ฐ€์ž…

์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ


3. ์ƒ์„ธ (Detail)

๋ชฉ๋ก์—์„œ ํ•ญ๋ชฉ ํด๋ฆญ โ†’ ํ•ด๋‹น ๋ฐ์ดํ„ฐ ์ƒ์„ธ ๋‚ด์šฉ ํ‘œ์‹œ
์˜ˆ) ๊ฒŒ์‹œ๊ธ€ ๋ณธ๋ฌธ ๋ณด๊ธฐ

ํŠน์ • ๋ฐ์ดํ„ฐ ํ•˜๋‚˜๋ฅผ ์ž์„ธํžˆ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ


4. ์ˆ˜์ • (Update)

๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€ ํผ์— ํ‘œ์‹œ โ†’ ์ˆ˜์ • ํ›„ ์ €์žฅ
์˜ˆ) ๊ฒŒ์‹œ๊ธ€ ํŽธ์ง‘

๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ธฐ๋Šฅ


5. ์‚ญ์ œ (Delete)

ํŠน์ • ๋ฐ์ดํ„ฐ ์„ ํƒ โ†’ DB์—์„œ ์™„์ „ ์‚ญ์ œ
์˜ˆ) ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ

๋ฐ์ดํ„ฐ๋ฅผ DB์—์„œ ์ œ๊ฑฐํ•˜๋Š” ๊ธฐ๋Šฅ


6. ํŽ˜์ด์ง€๋„ค์ด์…˜ (Pagination)

๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์„ ๋•Œ โ†’ ํ•œ ํŽ˜์ด์ง€์— n๊ฐœ์”ฉ ๋‚˜๋ˆ ์„œ ํ‘œ์‹œ
์˜ˆ) 1ํŽ˜์ด์ง€, 2ํŽ˜์ด์ง€, 3ํŽ˜์ด์ง€...

๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜๋ˆ ์„œ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋Šฅ


์ „์ฒด ํ๋ฆ„ ์š”์•ฝ

ModelForm        โ†’ ์ž…๋ ฅ ํผ ์ž๋™ ์ƒ์„ฑ
Create (์ƒ์„ฑ)    โ†’ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ (INSERT)
Detail (์ƒ์„ธ)    โ†’ ๋ฐ์ดํ„ฐ 1๊ฐœ ์กฐํšŒ (SELECT)
Update (์ˆ˜์ •)    โ†’ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ (UPDATE)
Delete (์‚ญ์ œ)    โ†’ ๋ฐ์ดํ„ฐ ์ œ๊ฑฐ (DELETE)
Pagination       โ†’ ๋ฐ์ดํ„ฐ ๋ถ„ํ•  ํ‘œ์‹œ

๐Ÿ’ก ์ด 6๊ฐ€์ง€๊ฐ€ ํ•ฉ์ณ์ง€๋ฉด ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ CRUD ์™„์„ฑ์ž…๋‹ˆ๋‹ค!


ํ•จ์ˆ˜ํ˜• View (FBV, Function-Based View)

Django์—์„œ ๋ทฐ๋ฅผ ํ•จ์ˆ˜๋กœ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด์—์š”.

# views.py
from django.shortcuts import render

def study_list(request):
    studies = Study.objects.all()
    return render(request, 'study/list.html', {'studies': studies})

CBV (Class-Based View) ์™€ ๋น„๊ต

# โŒ FBV
def study_list(request):
    studies = Study.objects.all()
    return render(request, 'study/list.html', {'studies': studies})

# โœ… CBV
class StudyListView(ListView):
    model = Study
    template_name = 'study/list.html'
FBVCBV
๊ตฌ์กฐํ•จ์ˆ˜ํด๋ž˜์Šค
๋‚œ์ด๋„์‰ฌ์›€์–ด๋ ค์›€
์ฝ”๋“œ๋Ÿ‰๋งŽ์Œ์ ์Œ
์œ ์—ฐ์„ฑ๋†’์Œ๋‚ฎ์Œ

Django ๋ทฐ์˜ ์ข…๋ฅ˜: ํ•จ์ˆ˜๋ทฐ vs ํด๋ž˜์Šค๋ทฐ vs ์ œ๋„ˆ๋ฆญ๋ทฐ

1. ํ•จ์ˆ˜ ๊ธฐ๋ฐ˜ ๋ทฐ (Function-Based View, FBV)

from django.shortcuts import render, get_object_or_404

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

ํŠน์ง•

  • ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ณ  ์ง๊ด€์ 
  • ํ๋ฆ„์ด ๋ช…ํ™•ํ•ด์„œ ์ฝ๊ธฐ ์‰ฌ์›€
  • HTTP ๋ฉ”์„œ๋“œ ๋ถ„๊ธฐ๋ฅผ ์ง์ ‘ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•จ (if request.method == 'POST':)
  • ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋‚ฎ์Œ

2. ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๋ทฐ (Class-Based View, CBV)

from django.views import View

class PostDetailView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, 'blog/post_detail.html', {'post': post})

    def post(self, request, pk):
        # POST ์š”์ฒญ ์ฒ˜๋ฆฌ
        ...

ํŠน์ง•

  • HTTP ๋ฉ”์„œ๋“œ(GET, POST ๋“ฑ)๋ฅผ ๋ฉ”์„œ๋“œ๋กœ ์ž๋™ ๋ถ„๊ธฐ
  • ์ƒ์†๊ณผ ๋ฏน์Šค์ธ(Mixin)์œผ๋กœ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ๋ณต์žกํ•œ ๋ทฐ์ผ์ˆ˜๋ก ๊ตฌ์กฐํ™”ํ•˜๊ธฐ ์œ ๋ฆฌ
  • FBV๋ณด๋‹ค ์ดˆ๊ธฐ ํ•™์Šต ๊ณก์„ ์ด ์žˆ์Œ

3. ์ œ๋„ˆ๋ฆญ ๋ทฐ (Generic View)

CBV๋ฅผ ๋” ์ถ”์ƒํ™”ํ•œ ๊ฒƒ์œผ๋กœ, Django๊ฐ€ CRUD ํŒจํ„ด์„ ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด ๋†“์€ ๋ทฐ

from django.views.generic import ListView, DetailView, CreateView

class PostListView(ListView):
    model = Post
    template_name = 'blog/post_list.html'
    context_object_name = 'posts'

class PostDetailView(DetailView):
    model = Post

class PostCreateView(CreateView):
    model = Post
    fields = ['title', 'content']
    success_url = '/posts/'

์ฃผ์š” ์ข…๋ฅ˜

ํด๋ž˜์Šค์šฉ๋„
ListView๋ชฉ๋ก ์กฐํšŒ
DetailView๋‹จ์ผ ๊ฐ์ฒด ์กฐํšŒ
CreateView๊ฐ์ฒด ์ƒ์„ฑ
UpdateView๊ฐ์ฒด ์ˆ˜์ •
DeleteView๊ฐ์ฒด ์‚ญ์ œ
TemplateView๋‹จ์ˆœ ํ…œํ”Œ๋ฆฟ ๋ Œ๋”๋ง

๋น„๊ต ์š”์•ฝ

๊ตฌ๋ถ„ํ•จ์ˆ˜๋ทฐ (FBV)ํด๋ž˜์Šค๋ทฐ (CBV)์ œ๋„ˆ๋ฆญ๋ทฐ
๊ตฌ์กฐํ•จ์ˆ˜ํด๋ž˜์Šคํด๋ž˜์Šค (CBV ํ™•์žฅ)
์ฝ”๋“œ๋Ÿ‰๋งŽ์Œ์ค‘๊ฐ„๋งค์šฐ ์ ์Œ
๊ฐ€๋…์„ฑ์ง๊ด€์ ๊ตฌ์กฐ์ ์„ ์–ธ์ 
์žฌ์‚ฌ์šฉ์„ฑ๋‚ฎ์Œ๋†’์Œ๋งค์šฐ ๋†’์Œ
์œ ์—ฐ์„ฑ๋งค์šฐ ๋†’์Œ๋†’์Œ๋‚ฎ์Œ (์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•„์š”)
์ ํ•ฉํ•œ ๊ฒฝ์šฐ๋‹จ์ˆœ/ํŠน์ˆ˜ ๋กœ์ง๋ณต์žกํ•œ ๋กœ์งํ‘œ์ค€ CRUD

์–ธ์ œ ๋ฌด์—‡์„ ์“ธ๊นŒ?

  • FBV โ†’ ๋กœ์ง์ด ๋ณต์žกํ•˜๊ฑฐ๋‚˜ ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ, ํŒ€์› ๋ชจ๋‘ Django์— ์ต์ˆ™ํ•˜์ง€ ์•Š์„ ๋•Œ
  • CBV โ†’ ์—ฌ๋Ÿฌ ๋ทฐ์—์„œ ๊ณตํ†ต ๋กœ์ง์„ ๊ณต์œ ํ•ด์•ผ ํ•  ๋•Œ (๋ฏน์Šค์ธ ํ™œ์šฉ)
  • ์ œ๋„ˆ๋ฆญ๋ทฐ โ†’ ๋‹จ์ˆœํ•œ CRUD ํŽ˜์ด์ง€, ๋น ๋ฅธ ๊ฐœ๋ฐœ์ด ํ•„์š”ํ•  ๋•Œ

์‹ค๋ฌด์—์„œ๋Š” ์„ธ ๊ฐ€์ง€๋ฅผ ์ƒํ™ฉ์— ๋งž๊ฒŒ ํ˜ผ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.


FBV vs CBV vs ์ œ๋„ˆ๋ฆญ๋ทฐ โ€” CRUD ํ๋ฆ„ ๋น„๊ต


CREATE (์ƒ์„ฑ)

FBV

def post_create(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('post_list')
    else:
        form = PostForm()
    return render(request, 'post_form.html', {'form': form})

CBV

class PostCreateView(View):
    def get(self, request):
        form = PostForm()
        return render(request, 'post_form.html', {'form': form})

    def post(self, request):
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('post_list')
        return render(request, 'post_form.html', {'form': form})

์ œ๋„ˆ๋ฆญ๋ทฐ

class PostCreateView(CreateView):
    model = Post
    fields = ['title', 'content']
    success_url = '/posts/'
    # GET/POST ์ฒ˜๋ฆฌ, form ์ƒ์„ฑ, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ, ์ €์žฅ, ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ โ†’ ๋ชจ๋‘ ์ž๋™

READ (์กฐํšŒ)

FBV

# ๋ชฉ๋ก
def post_list(request):
    posts = Post.objects.all()
    return render(request, 'post_list.html', {'posts': posts})

# ์ƒ์„ธ
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'post_detail.html', {'post': post})

CBV

class PostListView(View):
    def get(self, request):
        posts = Post.objects.all()
        return render(request, 'post_list.html', {'posts': posts})

class PostDetailView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, 'post_detail.html', {'post': post})

์ œ๋„ˆ๋ฆญ๋ทฐ

class PostListView(ListView):
    model = Post
    # Post.objects.all() ์ž๋™ ์‹คํ–‰, 'post_list.html' ์ž๋™ ํƒ์ƒ‰

class PostDetailView(DetailView):
    model = Post
    # pk๋กœ ๊ฐ์ฒด ์ž๋™ ์กฐํšŒ, ์—†์œผ๋ฉด 404 ์ž๋™ ์ฒ˜๋ฆฌ

UPDATE (์ˆ˜์ •)

FBV

def post_update(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == 'POST':
        form = PostForm(request.POST, instance=post)  # โ† instance ์ง์ ‘ ๋„˜๊ฒจ์•ผ ํ•จ
        if form.is_valid():
            form.save()
            return redirect('post_detail', pk=pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'post_form.html', {'form': form})

CBV

class PostUpdateView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        form = PostForm(instance=post)
        return render(request, 'post_form.html', {'form': form})

    def post(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            form.save()
            return redirect('post_detail', pk=pk)
        return render(request, 'post_form.html', {'form': form})

์ œ๋„ˆ๋ฆญ๋ทฐ

class PostUpdateView(UpdateView):
    model = Post
    fields = ['title', 'content']
    success_url = '/posts/'
    # ๊ธฐ์กด ๋ฐ์ดํ„ฐ ์ž๋™ ๋ฐ”์ธ๋”ฉ, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ, ์ €์žฅ ๋ชจ๋‘ ์ž๋™

DELETE (์‚ญ์ œ)

FBV

def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == 'POST':
        post.delete()
        return redirect('post_list')
    return render(request, 'post_confirm_delete.html', {'post': post})

CBV

class PostDeleteView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, 'post_confirm_delete.html', {'post': post})

    def post(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        post.delete()
        return redirect('post_list')

์ œ๋„ˆ๋ฆญ๋ทฐ

class PostDeleteView(DeleteView):
    model = Post
    success_url = '/posts/'
    # ํ™•์ธ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง โ†’ POST ์ˆ˜์‹  โ†’ ์‚ญ์ œ โ†’ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ž๋™

ํ๋ฆ„ ๊ตฌ์กฐ ๋น„๊ต ์š”์•ฝ

FBV
์š”์ฒญ โ†’ if method == 'POST' ๋ถ„๊ธฐ โ†’ ์ง์ ‘ ํผ/์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ โ†’ ์‘๋‹ต

CBV
์š”์ฒญ โ†’ dispatch() โ†’ get() / post() ์ž๋™ ๋ถ„๊ธฐ โ†’ ์ฒ˜๋ฆฌ โ†’ ์‘๋‹ต

์ œ๋„ˆ๋ฆญ๋ทฐ
์š”์ฒญ โ†’ dispatch() โ†’ get_object() / get_form() ์ž๋™ ์‹คํ–‰
     โ†’ form_valid() / form_invalid() ์ž๋™ ๋ถ„๊ธฐ โ†’ ์‘๋‹ต

ํ•ต์‹ฌ ์ฐจ์ด ํ•œ ์ค„ ์ •๋ฆฌ

ํ•ต์‹ฌ
FBV๋ชจ๋“  ํ๋ฆ„์„ ๋‚ด๊ฐ€ ์ง์ ‘ ์ž‘์„ฑ
CBVHTTP ๋ฉ”์„œ๋“œ ๋ถ„๊ธฐ๋ฅผ Django๊ฐ€ ์ฒ˜๋ฆฌ, ๋‚˜๋จธ์ง€๋Š” ์ง์ ‘
์ œ๋„ˆ๋ฆญ๋ทฐCRUD ํ๋ฆ„ ์ „์ฒด๋ฅผ Django๊ฐ€ ์ฒ˜๋ฆฌ, ๋‚˜๋Š” ์„ค์ •๋งŒ

ํ•ต์‹ฌ์„ ํ•œ ๋งˆ๋””๋กœ ์ •๋ฆฌํ•˜๋ฉด:

"์‚ฌ์šฉ์ž๊ฐ€ ์›น์—์„œ ๋ญ”๊ฐ€ ์ž…๋ ฅํ–ˆ์„ ๋•Œ, Django ๋‚ด๋ถ€์—์„œ ์–ด๋–ค ์ˆœ์„œ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š”๊ฐ€" ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๐Ÿงฑ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ฐจ๊ทผ์ฐจ๊ทผ

1๋‹จ๊ณ„ โ€” ์›น์ด ๋™์ž‘ํ•˜๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ ์›๋ฆฌ

๋ธŒ๋ผ์šฐ์ €(ํฌ๋กฌ ๋“ฑ)์™€ ์„œ๋ฒ„(Django)๋Š” ํŽธ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๋“ฏ ํ†ต์‹ ํ•ฉ๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € โ†’ (์š”์ฒญ, Request) โ†’ Django ์„œ๋ฒ„
๋ธŒ๋ผ์šฐ์ € โ† (์‘๋‹ต, Response) โ† Django ์„œ๋ฒ„

์š”์ฒญ์—๋Š” ๋‘ ์ข…๋ฅ˜๊ฐ€ ์žˆ์–ด์š”:

  • GET โ†’ "ํŽ˜์ด์ง€ ๋ณด์—ฌ์ค˜" (๋‹จ์ˆœ ์กฐํšŒ)
  • POST โ†’ "์ด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌํ•ด์ค˜" (ํผ ์ œ์ถœ, ์ €์žฅ ๋“ฑ)

2๋‹จ๊ณ„ โ€” ModelForm์ด ๋ญ”๊ฐ€์š”?

Django์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋ ค๋ฉด ๋ชจ๋ธ(Model) ์ด๋ผ๋Š” ์„ค๊ณ„๋„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

# ์˜ˆ์‹œ: ๊ฒŒ์‹œ๊ธ€ ๋ชจ๋ธ
class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

ModelForm์€ ์ด ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ HTML ์ž…๋ ฅ ํผ์„ ์ž๋™ ์ƒ์„ฑ + ๊ฒ€์ฆํ•ด์ฃผ๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

๋ชจ๋ธ(DB ์„ค๊ณ„๋„) โ†’ ModelForm โ†’ HTML ํผ ์ž๋™ ์ƒ์„ฑ
                            โ†’ ์ž…๋ ฅ๊ฐ’ ์ž๋™ ๊ฒ€์ฆ
                            โ†’ DB ์ €์žฅ๊นŒ์ง€ ํ•œ ๋ฒˆ์—

์ง์ ‘ HTML <input> ํƒœ๊ทธ๋ฅผ ํ•˜๋‚˜์”ฉ ๋งŒ๋“ค๊ณ , ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ผ์ผ์ด ์งœ์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ๊ฒŒ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.


3๋‹จ๊ณ„ โ€” ์ด๋ฏธ์ง€์˜ ํ•ต์‹ฌ ํ๋ฆ„ ํ•ด์„

์ด๋ฏธ์ง€์— ๋‚˜์˜จ ํ๋ฆ„์„ ์‹ค์ƒํ™œ๋กœ ๋น„์œ ํ•˜๋ฉด:

ํ๋ฆ„๋น„์œ 
์‚ฌ์šฉ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฐ’ ์ž…๋ ฅ์ข…์ด ์‹ ์ฒญ์„œ์— ๋‚ด์šฉ์„ ์”€
Django View๊ฐ€ POST ์š”์ฒญ ๋ฐ›์Œ์ ‘์ˆ˜ ์ฐฝ๊ตฌ๊ฐ€ ์‹ ์ฒญ์„œ๋ฅผ ๋ฐ›์Œ
ModelForm์ด ๊ฒ€์ฆ๋‹ด๋‹น์ž๊ฐ€ ๋น ์ง„ ํ•ญ๋ชฉ ์—†๋Š”์ง€ ํ™•์ธ
๋ชจ๋ธ์— ์ €์žฅ์„œ๋ฅ˜๋ฅผ DB ์บ๋น„๋‹›์— ๋ณด๊ด€
redirect๋กœ ํ™”๋ฉด ์ด๋™"์ ‘์ˆ˜ ์™„๋ฃŒ๋์Šต๋‹ˆ๋‹ค" ์•ˆ๋‚ด ํŽ˜์ด์ง€๋กœ ์ด๋™
๋ชฉ๋ก/์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ๊ฒฐ๊ณผ ํ™•์ธ์ ‘์ˆ˜๋œ ๋‚ด์šฉ์„ ํ™”๋ฉด์—์„œ ์กฐํšŒ

4๋‹จ๊ณ„ โ€” ์‹ค์ œ ์ฝ”๋“œ๋กœ ๋ณด๋ฉด

# views.py

def post_create(request):

    # GET ์š”์ฒญ โ†’ ๋นˆ ํผ์„ ๋ณด์—ฌ์คŒ
    if request.method == 'GET':
        form = PostForm()
        return render(request, 'create.html', {'form': form})

    # POST ์š”์ฒญ โ†’ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌ
    if request.method == 'POST':
        form = PostForm(request.POST)   # โ‘  ์ž…๋ ฅ๊ฐ’ ๋ฐ›๊ธฐ

        if form.is_valid():             # โ‘ก ๊ฒ€์ฆ
            form.save()                 # โ‘ข DB ์ €์žฅ
            return redirect('post_list') # โ‘ฃ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™

        # ๊ฒ€์ฆ ์‹คํŒจ ์‹œ โ†’ ์—๋Ÿฌ์™€ ํ•จ๊ป˜ ํผ ๋‹ค์‹œ ๋ณด์—ฌ์คŒ
        return render(request, 'create.html', {'form': form})

http://velog.io/@hy_1023/%ED%95%A8%EC%88%98-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%A0%9C%EB%84%88%EB%A6%AD

๐Ÿ’ก ์™œ ์ด๊ฑธ ๋จผ์ € ์ดํ•ดํ•ด์•ผ ํ•˜๋‚˜?

์ด๋ฏธ์ง€ ๋งจ ์•„๋ž˜ ๋ฌธ์žฅ์ด ํ•ต์‹ฌ์„ ๋งํ•ด์ค๋‹ˆ๋‹ค.

"์ด ํ๋ฆ„์ด ์ดํ•ด๋˜์–ด์•ผ โ†’ ํด๋ž˜์Šคํ˜• View โ†’ ์ œ๋„ˆ๋ฆญ View โ†’ DRF๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋œ๋‹ค"

์ฆ‰, Django๋ฅผ ๋ฐฐ์šฐ๋Š” ์ˆœ์„œ๊ฐ€:

ํ•จ์ˆ˜ํ˜• View๋กœ ํ๋ฆ„ ์ดํ•ด
    โ†“
ํด๋ž˜์Šคํ˜• View (์ฝ”๋“œ๋ฅผ ๋” ์งง๊ฒŒ)


    โ†“
์ œ๋„ˆ๋ฆญ View (CRUD๋ฅผ ์ž๋™ํ™”)
    โ†“
DRF (API ์„œ๋ฒ„ ๊ฐœ๋ฐœ)

์ง€๊ธˆ ๋ฐฐ์šฐ๋Š” ๊ฒŒ ๋ชจ๋“  ๊ฒƒ์˜ ๋ฟŒ๋ฆฌ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ฝ”๋“œ ํ•œ ์ค„์”ฉ ์™ธ์šฐ๊ธฐ๋ณด๋‹ค "์š”์ฒญ โ†’ ๊ฒ€์ฆ โ†’ ์ €์žฅ โ†’ ์ด๋™" ์ด 4๋‹จ๊ณ„ ํ๋ฆ„์„ ๋จธ๋ฆฟ์†์— ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ์ง„์งœ ๋ชฉํ‘œ์ž…๋‹ˆ๋‹ค.


Django View์˜ ํ™•์žฅ์„ฑ์ด๋ž€, ๊ฒฐ๊ตญ ๊ฐ™์€ "์š”์ฒญ โ†’ ์‘๋‹ต" ๊ตฌ์กฐ๋ฅผ ์ ์  ๋” ์ ์€ ์ฝ”๋“œ๋กœ, ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋ฐœ์ „์‹œํ‚ค๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฐ์ƒท์— ๋‚˜์˜จ ํ•™์Šต ์ˆœ์„œ๊ฐ€ ๋ฐ”๋กœ ๊ทธ ํ™•์žฅ์˜ ํ๋ฆ„์ด์—์š”.


1๋‹จ๊ณ„: ํ•จ์ˆ˜ํ˜• View (FBV) โ€” ๋ชจ๋“  ๊ฒƒ์„ ์ง์ ‘ ์“ด๋‹ค

def post_list(request):
    posts = Post.objects.all()
    return render(request, 'blog/post_list.html', {'posts': posts})

์š”์ฒญ์„ ๋ฐ›๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๊บผ๋‚ด๊ณ , ํ…œํ”Œ๋ฆฟ์— ๋„˜๊ธฐ๋Š” ๊ณผ์ •์„ ํ•œ ์ค„ ํ•œ ์ค„ ์ง์ ‘ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋ช…์‹œ์ ์ด๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์ง€๋งŒ, ๋น„์Šทํ•œ View๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด ๋ฐ˜๋ณต ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง‘๋‹ˆ๋‹ค.


2๋‹จ๊ณ„: ํด๋ž˜์Šคํ˜• View (CBV) โ€” ๋ฐ˜๋ณต์„ ๊ตฌ์กฐ๋กœ ์ค„์ธ๋‹ค

from django.views import View

class PostListView(View):
    def get(self, request):
        posts = Post.objects.all()
        return render(request, 'blog/post_list.html', {'posts': posts})

    def post(self, request):
        # POST ์ฒ˜๋ฆฌ
        ...

FBV์—์„œ if request.method == 'GET' ๊ฐ™์€ ๋ถ„๊ธฐ๋ฅผ ๋ฉ”์„œ๋“œ ์ด๋ฆ„(get, post)์œผ๋กœ ์ž๋™ ๋ถ„๋ฆฌํ•ด์ค๋‹ˆ๋‹ค. ํ•ต์‹ฌ์€ ์ƒ์†์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค๋Š” ์ ์ด์—์š”. ๊ณตํ†ต ๋กœ์ง์„ ๋ถ€๋ชจ ํด๋ž˜์Šค์— ๋‘๊ณ  ์ž์‹์ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


3๋‹จ๊ณ„: ์ œ๋„ˆ๋ฆญ View โ€” "๋ชฉ๋ก ๋ณด์—ฌ์ค˜", "ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์ค˜"๋ฅผ ํ•œ ์ค„๋กœ

from django.views.generic import ListView

class PostListView(ListView):
    model = Post
    template_name = 'blog/post_list.html'

Django๊ฐ€ "๋ชฉ๋ก ์กฐํšŒ"์— ํ•„์š”ํ•œ ๋กœ์ง(DB ์กฐํšŒ, ํŽ˜์ด์ง€๋„ค์ด์…˜, ํ…œํ”Œ๋ฆฟ ์ „๋‹ฌ)์„ ์ด๋ฏธ ๋‹ค ๋งŒ๋“ค์–ด๋’€๊ณ , ์—ฌ๋Ÿฌ๋ถ„์€ ๋ฌด์—‡์„(model), ์–ด๋””์—(template_name) ๋ณด์—ฌ์ค„์ง€๋งŒ ์•Œ๋ ค์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. CreateView, UpdateView, DeleteView ๋“ฑ CRUD ์ „์ฒด๊ฐ€ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.


4๋‹จ๊ณ„: DRF (Django REST Framework) โ€” HTML ๋Œ€์‹  JSON์„ ๋ฐ˜ํ™˜

from rest_framework.generics import ListAPIView

class PostListAPI(ListAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

๊ตฌ์กฐ๋Š” ์ œ๋„ˆ๋ฆญ View์™€ ๊ฑฐ์˜ ๊ฐ™์€๋ฐ, ํ…œํ”Œ๋ฆฟ ๋Œ€์‹  Serializer๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ(React, ๋ชจ๋ฐ”์ผ ์•ฑ ๋“ฑ)์™€ ํ†ต์‹ ํ•˜๋Š” API ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค ๋•Œ ์“ฐ์ž…๋‹ˆ๋‹ค.


์ •๋ฆฌํ•˜๋ฉด ์ด ๋„ค ๋‹จ๊ณ„๋Š” ๋ณ„๊ฐœ์˜ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ผ, ๊ฐ™์€ ํŒจํ„ด์„ ์ ์  ์ถ”์ƒํ™”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹จ๊ณ„์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒDjango๊ฐ€ ๋Œ€์‹  ํ•ด์ฃผ๋Š” ๊ฒƒ
FBV์ „๋ถ€์—†์Œ
CBV๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋ฉ”์„œ๋“œ ๋ถ„๊ธฐ
์ œ๋„ˆ๋ฆญ View์„ค์ •๊ฐ’๋งŒCRUD ๋กœ์ง ์ „์ฒด
DRF์„ค์ •๊ฐ’๋งŒCRUD + JSON ์ง๋ ฌํ™”

๊ทธ๋ž˜์„œ ๋ฌธ์„œ์—์„œ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ FBV์˜ "์š”์ฒญ โ†’ ๊ฒ€์ฆ โ†’ ์ €์žฅ โ†’ ์ด๋™" ํ๋ฆ„์„ ๋จผ์ € ์ฒด๊ฐํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€๋Š” ๊ทธ ํ๋ฆ„์„ ์ž๋™ํ™”ํ•œ ๊ฒƒ์— ๋ถˆ๊ณผํ•˜๋‹ˆ๊นŒ์š”.


Django์˜ ํ•จ์ˆ˜ํ˜• View(Function-Based View, FBV)์— ๋Œ€ํ•ด ์„ค๋ช…๋“œ๋ฆด๊ฒŒ์š”.

๊ธฐ์ดˆ ๊ฐœ๋…

ํ•จ์ˆ˜ํ˜• View๋Š” HTTP ์š”์ฒญ(request)์„ ๋ฐ›์•„์„œ HTTP ์‘๋‹ต(response)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋‹จ์ˆœํ•œ Python ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

# ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ
def post_list(request):
    posts = Post.objects.all()
    return render(request, 'blog/post_list.html', {'posts': posts})

urls.py์—์„œ ์ด๋ ‡๊ฒŒ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค:

path('posts/', views.post_list, name='post_list')

๊ธฐ์ดˆ๋ฅผ ๋„˜์–ด์„œ๋Š” ํ™œ์šฉ๋ฒ•๋“ค

1. HTTP ๋ฉ”์„œ๋“œ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ

ํ•˜๋‚˜์˜ ํ•จ์ˆ˜์—์„œ GET/POST๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ํŒจํ„ด์ด ์‹ค๋ฌด์—์„œ ๋งค์šฐ ํ”ํ•ฉ๋‹ˆ๋‹ค.

def post_create(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('post_list')
    else:  # GET
        form = PostForm()
    return render(request, 'blog/post_form.html', {'form': form})

2. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ™œ์šฉ

ํด๋ž˜์Šคํ˜• View์—์„œ๋Š” mixin์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์„ FBV์—์„œ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods, require_POST
from django.views.decorators.csrf import csrf_exempt

# ๋กœ๊ทธ์ธ ํ•„์ˆ˜
@login_required
def my_page(request):
    return render(request, 'my_page.html')

# ํ—ˆ์šฉํ•  HTTP ๋ฉ”์„œ๋“œ ์ œํ•œ
@require_http_methods(["GET", "POST"])
def post_edit(request, pk):
    ...

# POST๋งŒ ํ—ˆ์šฉ
@require_POST
def post_delete(request, pk):
    ...

# ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ค‘์ฒฉ๋„ ๊ฐ€๋Šฅ
@login_required
@require_POST
def comment_delete(request, pk):
    ...

3. JsonResponse๋กœ API ๋งŒ๋“ค๊ธฐ

ํ…œํ”Œ๋ฆฟ ๋ Œ๋”๋ง ์—†์ด JSON API ์—”๋“œํฌ์ธํŠธ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

from django.http import JsonResponse

def api_post_list(request):
    posts = Post.objects.values('id', 'title', 'created_at')
    return JsonResponse(list(posts), safe=False)

# AJAX ์š”์ฒญ ์ฒ˜๋ฆฌ
@require_POST
def api_like_toggle(request, pk):
    post = get_object_or_404(Post, pk=pk)
    post.likes += 1
    post.save()
    return JsonResponse({'likes': post.likes})

4. ์ปค์Šคํ…€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋งŒ๋“ค๊ธฐ

๋ฐ˜๋ณต๋˜๋Š” ๋กœ์ง์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์ถ”์ถœํ•˜๋Š” ๊ฒƒ์ด FBV์˜ ๊ฐ•๋ ฅํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

from functools import wraps
from django.http import HttpResponseForbidden

# ์ž‘์„ฑ์ž ๋ณธ์ธ๋งŒ ํ—ˆ์šฉํ•˜๋Š” ์ปค์Šคํ…€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ
def author_only(view_func):
    @wraps(view_func)
    def wrapper(request, pk, *args, **kwargs):
        post = get_object_or_404(Post, pk=pk)
        if post.author != request.user:
            return HttpResponseForbidden("๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.")
        return view_func(request, pk, *args, **kwargs)
    return wrapper

@login_required
@author_only
def post_edit(request, pk):
    # ์—ฌ๊ธฐ ๋„๋‹ฌํ•˜๋ฉด ์ด๋ฏธ ์ž‘์„ฑ์ž ๋ณธ์ธ์ด ๋ณด์žฅ๋จ
    ...

5. ์ปจํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๊ธฐ

def post_list(request):
    # ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•„ํ„ฐ๋ง/์ •๋ ฌ/ํŽ˜์ด์ง€๋„ค์ด์…˜
    search = request.GET.get('q', '')
    sort = request.GET.get('sort', '-created_at')
    page = request.GET.get('page', 1)

    posts = Post.objects.all()
    if search:
        posts = posts.filter(title__icontains=search)
    posts = posts.order_by(sort)

    paginator = Paginator(posts, 10)
    page_obj = paginator.get_page(page)

    return render(request, 'blog/post_list.html', {
        'page_obj': page_obj,
        'search': search,
        'sort': sort,
    })

FBV vs CBV ์„ ํƒ ๊ธฐ์ค€

์ƒํ™ฉ์ถ”์ฒœ
๋‹จ์ˆœํ•œ CRUDCBV (ListView, CreateView ๋“ฑ)
๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์งFBV โ€” ํ๋ฆ„์ด ๋ˆˆ์— ๋ณด์—ฌ์„œ ๋””๋ฒ„๊น…์ด ์‰ฌ์›€
์—ฌ๋Ÿฌ ๋ชจ๋ธ์„ ํ•œ View์—์„œ ์ฒ˜๋ฆฌFBV โ€” ์ž์œ ๋„๊ฐ€ ๋†’์Œ
API ์—”๋“œํฌ์ธํŠธFBV (๋˜๋Š” DRF)

ํ•ต์‹ฌ์€ FBV๊ฐ€ "๋‹จ์ˆœํ•œ ๊ฒƒ"์ด ์•„๋‹ˆ๋ผ, ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์กฐํ•ฉ๊ณผ ์ž์œ ๋กœ์šด ๋กœ์ง ๊ตฌ์„ฑ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์ ์—์„œ ์˜คํžˆ๋ ค ๋ณต์žกํ•œ ์š”๊ตฌ์‚ฌํ•ญ์— ๋” ์œ ์—ฐํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ถ๊ธˆํ•œ ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.


์งˆ๋ฌธ>์šฐ์„  4๋‹จ๊ณ„๊ฐ€ ์ดํ•ด๊ฐ€ ์•ˆ๊ฐ€๊ณ  ๊ทธ์ค‘์— redirect์˜ ์—ญํ• ๊ณผ ์˜๋ฏธ๋ฅผ ์•Œ๊ณ ์‹ถ์–ด. ๋˜ํ•œ 4๋‹จ๊ณ„์—์„œ ๋‚˜์˜จ ์ฝ”๋“œ๋ฅผ ๋ถ„์„๊ณผ ํฐ ํ๋ฆ„๋Œ€๋กœ ๋‚˜๋ˆ ์„œ ์–ด๋˜์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ๋ ค์ค˜ ๊ทธ๋ฆฌ๊ณ  3๋‹จ๊ณ„์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ํ๋ฆ„์—๋Œ€ํ•ด ๋”์‰ฝ๊ฒŒ ํ‘œํ˜„ํ•ด์ค˜

๋‹ต๋ณ€>

redirect๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

๐Ÿšช ํ•œ ๋งˆ๋””๋กœ: "๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ๊ฐ•์ œ ์ด๋™์‹œํ‚ค๋Š” ๋ช…๋ น"

์‹ค์ƒํ™œ ๋น„์œ ๋กœ ๋ณด๋ฉด:

์€ํ–‰ ์ฐฝ๊ตฌ์—์„œ ์„œ๋ฅ˜ ์ œ์ถœ ์™„๋ฃŒ ํ›„,
์ง์›์ด "์ ‘์ˆ˜ ์™„๋ฃŒ๋์Šต๋‹ˆ๋‹ค. ์ €์ชฝ ๋Œ€๊ธฐ์‹ค๋กœ ๊ฐ€์„ธ์š”" ๋ผ๊ณ  ์•ˆ๋‚ดํ•˜๋Š” ๊ฒƒ

๋งŒ์•ฝ redirect๊ฐ€ ์—†๋‹ค๋ฉด?

์‚ฌ์šฉ์ž๊ฐ€ ๊ธ€ ์ €์žฅ โ†’ ๊ทธ ์ž๋ฆฌ์— ๋ฉˆ์ถค
โ†’ ์ƒˆ๋กœ๊ณ ์นจ ๋ˆ„๋ฅด๋ฉด โ†’ ๊ธ€์ด ๋˜ ์ €์žฅ๋จ (์ค‘๋ณต ์ €์žฅ ๋ฐœ์ƒ!)

redirect๊ฐ€ ์žˆ์œผ๋ฉด?

์‚ฌ์šฉ์ž๊ฐ€ ๊ธ€ ์ €์žฅ โ†’ "๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ๊ฐ€์„ธ์š”" ๋ช…๋ น
โ†’ ์ƒˆ๋กœ๊ณ ์นจ ๋ˆŒ๋Ÿฌ๋„ โ†’ ๋ชฉ๋ก ํŽ˜์ด์ง€๋งŒ ์ƒˆ๋กœ๊ณ ์นจ (์ค‘๋ณต ์ €์žฅ ์—†์Œ)

์ฆ‰ redirect์˜ ์—ญํ• ์€ ๋‘ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

  • โœ… ์ €์žฅ ํ›„ ์ ์ ˆํ•œ ํŽ˜์ด์ง€๋กœ ์•ˆ๋‚ด
  • โœ… ์ƒˆ๋กœ๊ณ ์นจ์œผ๋กœ ์ธํ•œ ์ค‘๋ณต ์ €์žฅ ๋ฐฉ์ง€

4๋‹จ๊ณ„ ์ฝ”๋“œ ์™„์ „ ๋ถ„์„

์ฝ”๋“œ๋ฅผ ํฐ ๋ฉ์–ด๋ฆฌ 3๊ฐœ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

def post_create(request):
#  โ†‘ ์ด ํ•จ์ˆ˜ ์ „์ฒด๊ฐ€ ํ•˜๋‚˜์˜ "์ ‘์ˆ˜ ์ฐฝ๊ตฌ" ์—ญํ• 

๐ŸŸฆ ๋ฉ์–ด๋ฆฌ 1 โ€” "๋นˆ ์‹ ์ฒญ์„œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ตฌ๊ฐ„"

    if request.method == 'GET':
    #   โ†‘ ์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ๋ƒฅ ํŽ˜์ด์ง€๋ฅผ ์—ด์—ˆ์„ ๋•Œ (์กฐํšŒ ์š”์ฒญ)

        form = PostForm()
        #      โ†‘ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์ฑ„์›Œ์ง„ ๋นˆ ํผ์„ ๋งŒ๋“ ๋‹ค

        return render(request, 'create.html', {'form': form})
        #      โ†‘ ๊ทธ ๋นˆ ํผ์„ HTML๋กœ ๊ทธ๋ ค์„œ ๋ธŒ๋ผ์šฐ์ €์— ๋ณด๋‚ด์คŒ

๐Ÿ’ก ์‚ฌ์šฉ์ž ์ž…์žฅ: ์ฃผ์†Œ์ฐฝ์— URL ์ž…๋ ฅ โ†’ ๋นˆ ์ž…๋ ฅ ํผ ํ™”๋ฉด์ด ์—ด๋ฆผ


๐ŸŸจ ๋ฉ์–ด๋ฆฌ 2 โ€” "์‹ ์ฒญ์„œ๋ฅผ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ตฌ๊ฐ„"

    if request.method == 'POST':
    #   โ†‘ ์‚ฌ์šฉ์ž๊ฐ€ ํผ์— ๋‚ด์šฉ์„ ์“ฐ๊ณ  "์ œ์ถœ" ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ

        form = PostForm(request.POST)
        #               โ†‘ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํผ์— ๋‹ด๋Š”๋‹ค
        #      (์•„์ง ์ €์žฅ์€ ์•ˆ ํ•จ. ๊ฒ€์‚ฌํ•  ์ค€๋น„๋งŒ ํ•œ ์ƒํƒœ)

        if form.is_valid():
        #         โ†‘ "์ด ๋ฐ์ดํ„ฐ ๊ดœ์ฐฎ์•„?" ๊ฒ€์‚ฌ
        #           ์˜ˆ) ์ œ๋ชฉ์ด ๋น„์–ด์žˆ์ง€ ์•Š์€์ง€, ๊ธ€์ž์ˆ˜ ์ดˆ๊ณผ๋Š” ์•„๋‹Œ์ง€

            form.save()
            #    โ†‘ ๊ฒ€์‚ฌ ํ†ต๊ณผ โ†’ DB์— ์ €์žฅ

            return redirect('post_list')
            #       โ†‘ ์ €์žฅ ์™„๋ฃŒ โ†’ ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ๊ฐ•์ œ ์ด๋™

๐Ÿ’ก ์‚ฌ์šฉ์ž ์ž…์žฅ: ๋‚ด์šฉ ์ž…๋ ฅ ํ›„ ์ œ์ถœ โ†’ ์ €์žฅ ์™„๋ฃŒ โ†’ ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™๋จ


๐ŸŸฅ ๋ฉ์–ด๋ฆฌ 3 โ€” "๊ฒ€์‚ฌ ์‹คํŒจ ์‹œ ๋‹ค์‹œ ๋Œ๋ ค๋ณด๋‚ด๋Š” ๊ตฌ๊ฐ„"

        return render(request, 'create.html', {'form': form})
        #   โ†‘ is_valid() ์‹คํŒจํ–ˆ์„ ๋•Œ ์—ฌ๊ธฐ๋กœ ์˜ด
        #     ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‹ด๊ธด ํผ์„ ๋‹ค์‹œ ํ™”๋ฉด์— ๋ณด์—ฌ์คŒ

๐Ÿ’ก ์‚ฌ์šฉ์ž ์ž…์žฅ: ์ œ๋ชฉ์„ ์•ˆ ์“ฐ๊ณ  ์ œ์ถœ โ†’ "์ œ๋ชฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”" ์—๋Ÿฌ ํ‘œ์‹œ์™€ ํ•จ๊ป˜ ํผ์œผ๋กœ ๋Œ์•„์˜ด


์ „์ฒด ํ๋ฆ„ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

์‚ฌ์šฉ์ž๊ฐ€ URL ์ ‘์†
      โ†“
  GET ์š”์ฒญ?  โ”€โ”€โ”€โ”€โ”€โ”€โ†’ ๋นˆ ํผ ํ™”๋ฉด ๋ณด์—ฌ์คŒ
                           โ†“
               ์‚ฌ์šฉ์ž๊ฐ€ ๋‚ด์šฉ ์ž…๋ ฅ ํ›„ ์ œ์ถœ
                           โ†“
  POST ์š”์ฒญ? โ”€โ”€โ”€โ”€โ”€โ”€โ†’ ๋ฐ์ดํ„ฐ ๋ฐ›์Œ
                           โ†“
               is_valid() ๊ฒ€์‚ฌ
              โ†™               โ†˜
          ์‹คํŒจ                 ์„ฑ๊ณต
           โ†“                    โ†“
   ์—๋Ÿฌ ํผ ๋‹ค์‹œ ๋ณด์—ฌ์คŒ         DB์— ์ €์žฅ
                                โ†“
                         redirect โ†’ ๋ชฉ๋ก ํŽ˜์ด์ง€

3๋‹จ๊ณ„ ํ๋ฆ„์„ ๋” ์‰ฝ๊ฒŒ โ€” ํŽธ์˜์  ์•Œ๋ฐ” ๋น„์œ 

Django ํ๋ฆ„ํŽธ์˜์  ๋น„์œ 
์‚ฌ์šฉ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ฐ’ ์ž…๋ ฅ์†๋‹˜์ด ์ฃผ๋ฌธ์„œ์— ๋ฉ”๋‰ด๋ฅผ ์”€
POST ์š”์ฒญ ๋ฐ›์Œ์•Œ๋ฐ”์ƒ์ด ์ฃผ๋ฌธ์„œ๋ฅผ ๋ฐ›์•„๋“ค์Œ
ModelForm์ด ๊ฒ€์ฆ"ํ’ˆ์ ˆ ๋ฉ”๋‰ด ์—†๋Š”์ง€, ๋น ์ง„ ํ•ญ๋ชฉ ์—†๋Š”์ง€" ํ™•์ธ
โœ… ํ†ต๊ณผ โ†’ ๋ชจ๋ธ์— ์ €์žฅ์ด์ƒ ์—†์œผ๋ฉด ์ฃผ๋ฐฉ์— ์ฃผ๋ฌธ ์ „๋‹ฌ + ์˜์ˆ˜์ฆ ์ถœ๋ ฅ
โŒ ์‹คํŒจ โ†’ ํผ ๋‹ค์‹œ ๋ณด์—ฌ์คŒ"์ด ๋ฉ”๋‰ด๋Š” ์—†์–ด์š”, ๋‹ค์‹œ ๊ณจ๋ผ์ฃผ์„ธ์š”"
redirect"์ฃผ๋ฌธ ์™„๋ฃŒ! ์ €์ชฝ ํ”ฝ์—… ๋Œ€๊ธฐ์ค„๋กœ ๊ฐ€์„ธ์š”"
๋ชฉ๋ก/์ƒ์„ธ ํŽ˜์ด์ง€ํ”ฝ์—… ํ™”๋ฉด์—์„œ ๋‚ด ์ฃผ๋ฌธ ํ™•์ธ

ํ•ต์‹ฌ๋งŒ ๊ธฐ์–ตํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค:

GET = ๋ณด์—ฌ์ฃผ๊ธฐ / POST = ์ฒ˜๋ฆฌํ•˜๊ธฐ / redirect = ๋‹ค์Œ ์žฅ์†Œ๋กœ ๋ณด๋‚ด๊ธฐ

์ด ์„ธ ๊ฐ€์ง€๊ฐ€ ์›น์˜ ๋ชจ๋“  ๋™์ž‘์˜ ๊ธฐ๋ณธ์ž…๋‹ˆ๋‹ค. ๋” ๊ถ๊ธˆํ•œ ๋ถ€๋ถ„ ์žˆ์œผ๋ฉด ๋ง์”€ํ•ด ์ฃผ์„ธ์š”!


GET vs POST ์ฐจ์ด

https://velog.io/@hy_1023/GET-vs-POST-%EC%B0%A8%EC%9D%B4


์งˆ๋ฌธ

ํ•„๋“œ๋ž€ ๋ฌด์—‡์ด๊ณ  ๋ชจ๋ธ์ด๋ž€ ๊ทธ๋ฆ‡ ๊ทธ๋ฆฌ๊ณ  ๊ทธ์•ˆ์— ๋ฐ์ดํ„ฐ.. ๊ฐœ๋…์—์„œ ๋” ํ™•์žฅํ•˜์—ฌ ํฐํ๋ฆ„๊ตฌ์กฐ์ ์œผ๋กœ ์ดํ•ด์‹œ์ผœ์ค˜


Django์˜ ํฐ ํ๋ฆ„์„ ๊ฑด๋ฌผ ์ง“๊ธฐ์— ๋น„์œ ํ•ด์„œ ์„ค๋ช…ํ•ด ๋ณผ๊ฒŒ์š”.

์„ค๊ณ„๋„ โ†’ ๊ฑด๋ฌผ โ†’ ์ž…์ฃผ์‹ ์ฒญ์„œ โ†’ ์‹ค์ œ ์ž…์ฃผ

Model์€ "์„ค๊ณ„๋„"์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํ…Œ์ด๋ธ”์ด ์–ด๋–ค ๊ตฌ์กฐ๋กœ ์ƒ๊ฒจ์•ผ ํ•˜๋Š”์ง€๋ฅผ Python ์ฝ”๋“œ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

class Study(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

์ด ์ฝ”๋“œ๋ฅผ ์“ฐ๋Š” ์ˆœ๊ฐ„, Django๋Š” ์ด๋ ‡๊ฒŒ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค:

"์•„, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— study๋ผ๋Š” ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๊ตฌ๋‚˜. ์นธ(column)์€ title, content, created_at ์„ธ ๊ฐœ๊ณ , ๊ฐ๊ฐ ์งง์€ ๋ฌธ์ž์—ด, ๊ธด ๋ฌธ์ž์—ด, ๋‚ ์งœ ํ˜•์‹์ด๊ตฌ๋‚˜."

Field๋Š” ๊ทธ ์„ค๊ณ„๋„ ์•ˆ์˜ "์นธ ํ•˜๋‚˜ํ•˜๋‚˜"์ž…๋‹ˆ๋‹ค. title, content, created_at ๊ฐ๊ฐ์ด ํ•„๋“œ์˜ˆ์š”. ํ•„๋“œ๋Š” ๋‹จ์ˆœํ•œ ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ "์ด ์นธ์—๋Š” ์–ด๋–ค ์ข…๋ฅ˜์˜ ๋ฐ์ดํ„ฐ๊ฐ€, ์–ด๋–ค ์ œ์•ฝ ์กฐ๊ฑด์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š”๊ฐ€"๊นŒ์ง€ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. CharField(max_length=200)์ด๋ผ๊ณ  ์“ฐ๋ฉด "๋ฌธ์ž์—ด์ธ๋ฐ 200์ž๊นŒ์ง€๋งŒ ํ—ˆ์šฉํ•ด"๋ผ๋Š” ๊ทœ์น™๊นŒ์ง€ ํฌํ•จ๋œ ๊ฑฐ์ฃ .

๊ทธ๋ž˜์„œ makemigrations โ†’ migrate๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ์ด ์„ค๊ณ„๋„๋Œ€๋กœ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.


์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ "๋ฐฑ์—”๋“œ(์ €์žฅ์†Œ) ์ชฝ" ์ด์•ผ๊ธฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ฌธ์ œ๊ฐ€ ํ•˜๋‚˜ ์žˆ์–ด์š”.

์‚ฌ์šฉ์ž๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ง์ ‘ ๋ชป ๊ฑด๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•˜๋ ค๋ฉด, ์ค‘๊ฐ„ ๋‹ค๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๋ฐ”๋กœ Form์ด์—์š”.


Form์€ "์ž…์ฃผ์‹ ์ฒญ์„œ"์ž…๋‹ˆ๋‹ค. ์„ค๊ณ„๋„(Model)์—๋Š” ์นธ์ด 10๊ฐœ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ž…์ฃผ์‹ ์ฒญ์„œ(Form)์—๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์“ธ ์นธ๋งŒ ๊ณจ๋ผ์„œ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

class StudyForm(forms.ModelForm):
    class Meta:
        model = Study          # ์–ด๋–ค ์„ค๊ณ„๋„(๋ชจ๋ธ)์— ์—ฐ๊ฒฐํ• ์ง€
        fields = ['title', 'content']  # ๊ทธ ์ค‘ ์–ด๋–ค ์นธ๋งŒ ๋ณด์—ฌ์ค„์ง€

created_at์€ auto_now_add=True๋ผ์„œ ์ž๋™ ์ž…๋ ฅ๋˜๋‹ˆ๊นŒ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ˆ ๋ณด์—ฌ์ฃผ๋Š” ๊ฑฐ์ฃ . ์ด๊ฒŒ fields์—์„œ ๊ณจ๋ผ๋‚ด๋Š” ํ–‰์œ„์ž…๋‹ˆ๋‹ค.


์ „์ฒด ํ๋ฆ„์„ ํ•˜๋‚˜๋กœ ์—ฐ๊ฒฐํ•˜๋ฉด

์‚ฌ์šฉ์ž(๋ธŒ๋ผ์šฐ์ €)          Django ์„œ๋ฒ„               ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
    โ”‚                        โ”‚                        โ”‚
    โ”‚  โ‘  ํŽ˜์ด์ง€ ์š”์ฒญ         โ”‚                        โ”‚
    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ   โ”‚                        โ”‚
    โ”‚                   View๊ฐ€ Form์„ ๋งŒ๋“ค์–ด์„œ        โ”‚
    โ”‚  โ‘ก ๋นˆ ํผ ๋ณด์—ฌ์คŒ        โ”‚                        โ”‚
    โ”‚ โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€   โ”‚                        โ”‚
    โ”‚                        โ”‚                        โ”‚
    โ”‚  โ‘ข ํผ ์ž‘์„ฑ ํ›„ ์ œ์ถœ     โ”‚                        โ”‚
    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ   โ”‚                        โ”‚
    โ”‚                   View๊ฐ€ Form์œผ๋กœ               โ”‚
    โ”‚                   ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ(validation)        โ”‚
    โ”‚                        โ”‚                        โ”‚
    โ”‚                   โ‘ฃ ๊ฒ€์ฆ ํ†ต๊ณผํ•˜๋ฉด                โ”‚
    โ”‚                   form.save() ํ˜ธ์ถœ              โ”‚
    โ”‚                        โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ   โ”‚
    โ”‚                        โ”‚   Model ๊ตฌ์กฐ๋Œ€๋กœ       โ”‚
    โ”‚                        โ”‚   DB์— ์ €์žฅ            โ”‚
    โ”‚  โ‘ค ์™„๋ฃŒ ์‘๋‹ต           โ”‚                        โ”‚
    โ”‚ โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€   โ”‚                        โ”‚

๊ฐ ๋‹จ๊ณ„์—์„œ ๋ˆ„๊ฐ€ ๋ฌด์Šจ ์—ญํ• ์ธ์ง€ ์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡์Šต๋‹ˆ๋‹ค:

Model โ†’ ๋ฐ์ดํ„ฐ์˜ ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜๊ณ , DB์™€ ์ง์ ‘ ๋Œ€ํ™”ํ•˜๋Š” ๊ณ„์ธต
Field โ†’ ๊ทธ ๊ตฌ์กฐ ์•ˆ์˜ ์นธ ํ•˜๋‚˜. ํƒ€์ž…๊ณผ ๊ทœ์น™์„ ๊ฐ€์ง
Form โ†’ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋ฐ›๊ณ , ๊ทธ ์ž…๋ ฅ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ๊ฒ€์ฆํ•˜๋Š” ๊ณ„์ธต
Form์˜ fields โ†’ Model์˜ ํ•„๋“œ ์ค‘ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœํ•  ๊ฒƒ๋งŒ ๊ณ ๋ฅธ ๊ฒƒ
View โ†’ ์ด ๋ชจ๋“  ๊ฑธ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตํ†ต์ •๋ฆฌ ๋‹ด๋‹น (์š”์ฒญ ๋ฐ›๊ณ  โ†’ ํผ ์ฃผ๊ณ  โ†’ ๊ฒ€์ฆํ•˜๊ณ  โ†’ ์ €์žฅํ•˜๊ณ  โ†’ ์‘๋‹ต)


ํ•ต์‹ฌ์€ ์ด๊ฒ๋‹ˆ๋‹ค: Model์€ "๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”๊ฐ€"๋ฅผ ์ •์˜ํ•˜๊ณ , Form์€ "์‚ฌ์šฉ์ž๊ฐ€ ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋„ฃ๋Š”๊ฐ€"๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‘˜์€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ณ„์ธต์ธ๋ฐ, ModelForm์ด ์ด ๋‘˜์„ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ํŽธ์˜ ์žฅ์น˜์ธ ๊ฑฐ์˜ˆ์š”. ModelForm ์—†์ด๋„ Django๋Š” ๋™์ž‘ํ•˜์ง€๋งŒ, ์žˆ์œผ๋ฉด Model์˜ ๊ตฌ์กฐ๋ฅผ Form์ด ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ์–ด์„œ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ์งง์•„์ง‘๋‹ˆ๋‹ค.


๋‹ค์‹œ์ •๋ฆฌ


ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋‹จ์–ด ์ฒดํฌ

  • 1ํŽธ์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ admin์—์„œ๋งŒ ๋„ฃ๊ณ  ํ…Œ์ŠคํŠธ ? ์‹ค์ œ ์›นํŽ˜์ด์ง€์—์„œ ์ง์ ‘๋ฐ์ดํ„ฐ ๋„ฃ๊ณ  ํ…Œ์ŠคํŠธ?
  • 2๋ฒˆ์งธ ๊ต์•ˆ์˜ ๋ชฉํ‘œ
    - ๋ชจ๋ธํผ? ModModel form?
    • ํ•จ์ˆ˜ํ˜• view ๊ธฐ์ค€์˜ CRUD?

    • CRUD ? ์ƒ์„ฑ, ์ƒ์„ธ , ์ˆ˜์ • , ์‚ญ์ œ ๊ฐ๊ฐ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜๋Š”์ง€ ์ฒด๋“?

    • ํ•จ์ˆ˜ํ˜•? ํด๋ž˜์‹? ์ œ๋„ˆ๋ฆญ?

    • ๋ธŒ๋ผ์šฐ์ € ์ค‘์‹ฌ ํ…Œ์ดํ„ฐํ๋ฆ„์ดํ•ด.. ๋ธŒ๋ผ์šฐ์ €?

    • HTML ํผ ์ž…๋ ฅ

    • POST ๋ž€? ๊ทธ ๋ฐ˜๋Œ€๋ง? ๊ทธ์™ธ ์ข…๋ฅ˜๋Š” ๋ฌด์—‡์ด ์žˆ๋Š”์ง€

    • ๊ฒ€์ฆ?

    • ์ €์žฅ

    • redirect ํ๋ฆ„ ์ดํ•ด? ๋œป? ๊ทธ๋ฐ˜๋Œ€์˜๋ฏธ๋˜๋Š” ๊ทธ์™ธ ์ข…๋ฅ˜ ?

      -์ด ํ๋ฆ„์ด ์ดํ•ด๋˜์–ด์•ผ ๋‹ค์Œ ๊ต์•ˆ์—์„œ ํด๋ž˜์Šคํ˜• View, ์ œ๋„ˆ๋ฆญ View, DRF๊นŒ์ง€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. --> ์™œ??/
      -DRF ๋Š” ๋ฌด์—‡์ธ๊ฐ€.

    • ํ•จ์ˆ˜ ํด๋ž˜์Šค ์ œ๋„ˆ๋ฆญ ์ข…๋ฅ˜๋Š” VIEW ๋ฐ–์— ์—†๋‚˜ ?


27๋ฒˆ. ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„ 2์ฐจ ๊ต์•ˆ์—์„œ ํ•ต์‹ฌ ํ๋ฆ„

-๋ชจ๋ธํผ์ž‘์„ฑ
-๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ CRUD?
-C์ƒ์„ฑ D์ƒ์„ธ U์ˆ˜์ • D์‚ญ์ œ PํŽ˜์ด์ง€๋„ค์ด์…˜ --> ์ด๋ถ€๋ถ„์ด ? CRUD ๋ผ๋Š”๊ฑด๊ฐ€?
-๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑ / ์ˆ˜์ • ํ๋ฆ„์€ ํŠนํžˆ ์•„๋ž˜ ํŒจํ„ด์„ ๊ผญ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
-GET ์š”์ฒญ์ด๋ž€? ์˜๋ฏธ์™€ ์—ญํ•  ๊ทธ์™ธ ์ข…๋ฅ˜
- ๋นˆ ํผ ๋˜๋Š” ๊ธฐ์กด ๊ฐ’์ด ์ฑ„์›Œ์ง„ ํผ ๋ณด์—ฌ์ฃผ๊ธฐ
-POST ์š”์ฒญ์ด๋ž€? ์˜๋ฏธ์™€ ์—ญํ•  ๊ทธ์™ธ ์ข…๋ฅ˜
-์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœํ•œ ๊ฐ’ ๋ฐ›๊ธฐ ๋ญ˜๋กœ ๋ฐ›๋Š”์ง€
-form.is_valid() ๊ฒ€์ฆ ์–ธ์ œ ์“ฐ์ด๋Š”์ง€
-form.save() ์ €์žฅ ์˜๋ฏธ? ์–ธ์ œ ์“ฐ์ด๋Š”์ง€
-redirect() ์ด๋™ ์—ญํ• ๊ณผ ์˜๋ฏธ ๊ทธ์™ธ์ข…๋ฅ˜

-์ด ํŒจํ„ด์€ Django์—์„œ ์ •๋ง ์ž์ฃผ ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค. -- > ํ•ต์‹ฌ?

-28. ํ•จ์ˆ˜ํ˜• View ๊ธฐ์ค€ CRUD ์ •๋ฆฌ?

-ํ•จ์ˆ˜ํ˜• View๋ž€?
-ํ•จ์ˆ˜ํ˜• View ๊ธฐ์ค€์œผ๋กœ CRUD ์ „์ฒด ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ด
-๋‹ค์Œ์— ํด๋ž˜์Šค view ์™€ ์ œ๋„ˆ๋ฆญ view ๋„˜์–ด๊ฐˆ๋•Œ. ๋ฌด์—‡์ด ๋‹ค๋ฅธ๊ฐ€?
-ํ˜„์žฌ 2ํŽธ์—์„œ ๋งŒ๋“  ํ•จ์ˆ˜ํ˜• view ์ข…๋ฅ˜? ์ด 5๊ฐœ
-์ฆ‰ Django CRUD์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ ํ˜•ํƒœ๋ฅผ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ๋จผ์ € ์ฒด๋“ํ•œ ๊ฒƒ--> ์žฅ๊ณ crud ๊ธฐ๋ณธํ˜•ํƒœ๋ฅผ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ๋จผ์ € ์ฒด๋“ --> ๋ฌด์Šจ์˜๋ฏธ

  • 30.์ฒดํฌ๋ฆฌ์ŠคํŠธ์—์„œ
    - ๋ชจ๋ธํผ ํ˜•์„ฑ
    -C์ƒ์„ฑ D์ƒ์„ธ U์ˆ˜์ • D์‚ญ์ œ PํŽ˜์ด์ง€๋„ค์ด์…˜
    - url -> view -> templete ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰์ด ๋˜๋Š”๊ฑฐ ๊ฐ™์€๋ฐ ์ƒ์„ธํ…œํ”Œ๋ฆฟ์„ ๋งŒ๋“  ๋‹ค์Œ ๋ชฉ๋ก์—์„œ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ ํ• ์ˆ˜์žˆ๋‹ค..? ๊ฐ‘์ž๊ธฐ์™œ?
    • ์ˆ˜์ •์—์„œ url view ๊ทธ ๋‹ค์Œ ์ƒˆ๋กœ์šด ํ…œํ”Œ๋ฆฟ์ด ์•„๋‹Œ ๊ธฐ์กด๊ฐ’์ด ์ฑ„์›Œ์ง„ ์ˆ˜์ • ํผ์ด ์—ด๋ฆฌ๋Š” ๋ถ€๋ถ„
    • ์ˆ˜์ • ํ›„ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ๋ฐ˜์˜๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. --> ์ฝ”๋“œ๊ฐ€ ๋ถ„์„ํ•ด์•ผํ•œ๋‹ค.
    • ์‚ญ์ œ์—์„œ url -> view -> templete ๋ฐฉ์‹ ๊นŒ์ง€๋Š” ์ดํ•ด๋˜์ง€๋งŒ, ๊ทธ ๋‹ค์Œ์ด ์ดํ•ด๊ฐ€ ์–ด๋ ค์›€
    • ์‚ญ์ œ ์ „ ํ™•์ธ ํŽ˜์ด์ง€๊ฐ€ ๋‚˜์˜จ๋‹ค.
      -์‚ญ์ œ ํ›„ ๋ชฉ๋ก์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.
      -ํŽ˜์ด์ง€ ๋„ค์ด์…˜ ์ด๋ž€?
    • ๋ฐ์ดํ„ฐ 6๊ฐœ ์ด์ƒ์œผ๋กœ ํŽ˜์ด์ง€ ์ด๋™์„ ํ™•์ธํ–ˆ๋‹ค.
  1. ๊ฒฐ๋ก 

-1์ฐจ์™€ 2์ฐจ์˜ ๋‹ค๋ฅธ์  ์ฆ‰ ํ”„๋กœ์ ฏํŠธํŒŒ์ผ ์žฅ๊ณ  ํŒŒ์ผ ์–ด๋“œ๋ฏผ์„ค์น˜ ๊ทธ์•ˆ์— ์•ฑํ˜•์„ฑ ์ž„์‹œํ…Œ์ŠคํŠธํ•˜๊ธฐ์œ„ํ•ด ์–ด๋“œ๋ฏผ์œผ๋กœ ๋จผ์ € ์ž„์‹œ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์ž„์‹œํ…Œ์ŠคํŠธ ์„ฑ๊ณตํ•˜๋ฉด 1์ฐจ์—์„œ ํ๋ฆ„ ์ดํ•ด๋„๋ฅผ ์œ„ํ•ด ์•ฑ ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์•„๋‹Œ ์•ฑ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ๊ทธ์•ˆ์— study models.py ์— ํ•จ์ˆ˜๋ทฐ๋กœ ๋งŒ๋“ค๊ธฐ?

-2์ฐจ์—์„œ๋Š” ๋ชจ๋ธํŒŒ์ผ์„ ํ•จ์ˆ˜๋ทฐ๋กœ ํ•˜๋Š”๊ฒŒ ์•„๋‹Œ ์žฅ๊ณ ๋‚ด์žฅํ•จ์ˆ˜์˜ ๋ชจ๋ธํผ์„ ์ด์šฉํ•˜์—ฌ
-C์ƒ์„ฑ D์ƒ์„ธ U์ˆ˜์ • D์‚ญ์ œ PํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ธŒ๋ผ์šฐ์ € ์ค‘์‹ฌ CRUD ํ…Œ์ŠคํŠธ
-๋ธŒ๋ผ์šฐ์ € ์ค‘์‹ฌ CRUD ํ…Œ์ŠคํŠธ์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€ ?

-์ฆ‰ ์žฅ๊ณ ๋กœ ๋ฐ์ดํ† ๋ฅผ ๋ณด์—ฌ์ค„์ˆ˜๋„ ๋งŒ๋“ค์ˆ˜๋„ ์ˆ˜์ •ํ• ์ˆ˜๋„ ์‚ญ์ œํ• ์ˆ˜๋„์žˆ๋Š” ๊ธฐ๋ณธ์ ์ธ์›น์„œ๋น„์Šค๋ฅผ ์™„์„ฑ ์‹œํ‚จ๊ฒƒ.

-์—ฌ๊ธฐ์—์„œ ์ค‘์š”ํ•œ๊ฒƒ์€
-GET ํผ ๋ณด์—ฌ์ฃผ๊ธฐ
-POST ๊ฒ€์ฆ ์ €์žฅ redirect

--> ์ดํŒจํ„ด์ด Django Form ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ! ๋ชจ๋ฅด๊ฒ ์Œ...

  • 3์ฐจ ๊ต์•ˆ์—์„œ๋Š” โ€œ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ CRUDโ€๋ฅผ ๋„˜์–ด์„œ, Django๋ฅผ ๋” Django๋‹ต๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์กฐ์™€ API ํ™•์žฅ ํ๋ฆ„๊นŒ์ง€ ๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. -ํ•จ์ˆ˜ํ˜• View ๋ณต์Šต
    • ํด๋ž˜์Šคํ˜• View
      -โ†’ ์ œ๋„ˆ๋ฆญ View
      -โ†’ DRF Serializer
      -โ†’ ViewSet
      -โ†’ Router
      -โ†’ API ํ…Œ์ŠคํŠธ


  
profile
๊ฐœ๋ฐœ์–ธ์–ด๋ฅผ ๋ฐฐ์šฐ๋Š” ๊ณผ์ • ๊ธฐ๋ก

0๊ฐœ์˜ ๋Œ“๊ธ€