Intro
Django์ CBV(Class Based View)๋ฅผ ์ฌ์ฉํ ๋, Mixin์ ํ์ฉํ๋ฉด ํ์ํ ๊ธฐ๋ฅ์ ์์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด RetrieveAPIView๋ฅผ ์ฌ์ฉํ๊ณ ์๋๋ฐ Create ๊ธฐ๋ฅ์ด ํ์ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด CreateModelMixin์ ์์๋ฐ์ Create ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
# ์๋ชป๋ ์ฌ์ฉ
class ProductRetrieveCreateView(RetrieveAPIView, CreateModelMixin):
pass
Python
๋ณต์ฌ
๋ค๋ง Mixin์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋ช ๊ฐ์ง ๊ณ ๋ คํด์ผ ํ๋ ์ฌํญ์ด ์์ต๋๋ค.
Django CBV์ Mixin์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ฐ๋จํ๊ฒ ์์๋ณด๊ฒ ์ต๋๋ค.
Rule of Thumb
Mixin์ ์ฌ์ฉํ ๋ <Two Scoops of Django 3.x>์์ ์ถ์ฒํ๋ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1.
Django๊ฐ ์ ๊ณตํ๋ Base View Class๋ ๊ฐ์ฅ ์ค๋ฅธ์ชฝ์ ๋๋ค.
2.
Mixin์ Base View์ ์ผ์ชฝ์ ๋๋ค.
3.
๋ํ Mixin์ ์ด๋ค Class๋ก๋ถํฐ๋ผ๋ ์์์ ๋ฐ์์ ์ ๋๋ค.
์์ ๋ฐฉ๋ฒ์ ์ ์ฉํ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
from django.views.generic import TemplateView
class FreshFruitMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["has_fresh_fruit"] = True
return context
class FruityFlavorView(FreshFruitMixin, TemplateView):
template_name = "fruity_flavor.html"
Python
๋ณต์ฌ
์์ ์์์์ ์ฃผ์ ๊น๊ฒ ๋ณด์์ผ ํ๋ ์ ์
1.
FruitFlavorView์ ์์ ์์์์ FreshFruitMixin์ด TemplateView ๋ณด๋ค ์ผ์ชฝ์ ์๊ณ
2.
FreshFruitMixin์ด ๋ค๋ฅธ ํด๋์ค๋ก๋ถํฐ ์์ ๋ฐ์ง ์๋ ํด๋์ค๋ผ๋ ๊ฒ์
๋๋ค.
Why?
์ ์์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ถ์ฒํ๋ ๊ฑธ๊น์?
์ ๋ต์ Python์ MRO(Method Resolution Order)์ ๊ด๋ จ ์์ต๋๋ค.
Python์ ๋ค์ค ์์์ ๋ฐ์ ํด๋์ค์์ attribute๋ method๋ฅผ ํ์ํ ๋, C3 Linearization ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํฉ๋๋ค.
C3 Linearization ์๊ณ ๋ฆฌ์ฆ ํ ๋ฌธ์ฅ์ผ๋ก ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
depth-first until classes are encountered that will share a parent, and then breadth-first over those ...
attribute๋ method ํ์ ์์
1.
๋จผ์ ํ์ฌ ํด๋์ค์์ ์ฐพ์ต๋๋ค.
2.
ํ์ฌ ํด๋์ค์์ ์ฐพ์ง ๋ชปํ๋ฉด ๋ถ๋ชจ ํด๋์ค๋ก ์ด๋ํ์ฌ depth-first ํ์์ ํฉ๋๋ค.
3.
ํ์ ์ค ๊ณต์ ๋๋ parent class๋ฅผ ๋ง๋๋ฉด ๋์๊ฐ์ breadth-first ํ์์ ํฉ๋๋ค.
์์๋ฅผ ํตํด์ ๋ ์์ธํ๊ฒ ์์๋ด
์๋ค.
๋ค์๊ณผ ๊ฐ์ ์์ ๊ด๊ณ๋ฅผ ๊ฐ์ง ํด๋์ค๋ค์ ์ ์ํด์ค๋๋ค:
class A(): pass
class B(A): pass
class C(A): pass
class D_0(B, C): pass
class D_1(B, C): pass
class E_0(D_0): pass
class E_1(D_1): pass
class F(E_0, E_1): pass
Python
๋ณต์ฌ
์์ ์์๊ด๊ณ๋ฅผ ๋์ํ ํ์ฌ ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
F ํด๋์ค์ MRO๋ฅผ ์์ฐจ์ ์ผ๋ก ์ถ๋ ฅํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
print([x.__name__ for x in F.mro()])
Python
๋ณต์ฌ
['F', 'E_0', 'D_0', 'E_1', 'D_1', 'B', 'C', 'A', 'object']
Python
๋ณต์ฌ
์์์ ์ค๋ช
ํ ๋ฃฐ์ ๋ฐ๋ผ F ์ธ์คํด์ค์์ ์ด๋ค attribute๋ method๋ฅผ ํธ์ถํ๋ฉด,
๋ณธ์ธ ํด๋์ค(F)๋ฅผ ๋จผ์ ํ์ํ ๋ค, ์ฒซ ๋ฒ์งธ ๋ถ๋ชจ ํด๋์ค๋ถํฐ ์์ฐจ์ ์ผ๋ก ๊น์ด ์ฐ์ ํ์์ ์งํํฉ๋๋ค:
['F', 'E_0', 'D_0', 'E_1', 'D_1', 'B', 'C', 'A', 'object']
Python
๋ณต์ฌ
D_0์ D_1์์ ๊ณตํต์ผ๋ก ์์ ๋ฐ์ ๋ถ๋ชจ ํด๋์ค(B)๋ฅผ ๋ง๋๋ฉด, F์ ๋ ๋ฒ์งธ ๋ถ๋ชจ ํด๋์ค์ธ E_1๋ถํฐ ๋ค์ ํ์์ ์์ํฉ๋๋ค:
['F', 'E_0', 'D_0', 'E_1', 'D_1', 'B', 'C', 'A', 'object']
Python
๋ณต์ฌ
๋ง์ง๋ง์ผ๋ก ๊ณตํต ๋ถ๋ชจ์ธ B๋ถํฐ ํ์ํ๋๋ฐ ์ด ๋๋ A๊ฐ ๊ณตํต ๋ถ๋ชจ์ด๊ธฐ ๋๋ฌธ์ ํ์ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
['F', 'E_0', 'D_0', 'E_1', 'D_1', 'B', 'C', 'A', 'object']
Python
๋ณต์ฌ
๋ฐ๋ผ์ ํ์ฌ ํด๋์ค์ ์๋ attribute๋ method๊ฐ ์๋๋ฉด ์์ ๋ฐ์ ํด๋์ค๋ฅผ ํ์ํ ๋ ์ผ์ชฝ์ ์๋ Mixin๋ถํฐ ํ์ํ๊ณ ๋ง์ง๋ง์ผ๋ก Base View๋ฅผ ํ์ธํ ๊ฒ์
๋๋ค.
์ฐ๋ฆฌ๊ฐ Mixin์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์ผ๋ฐ์ ์ผ๋ก ๊ธฐ์กด View์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ ์ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ํ์์ ํ ๋๋ BaseView ๋ณด๋ค๋ Mixin๋ฅผ ๋จผ์ ํ์ํ๋ ๊ฒ์ด ํฉ๋ฆฌ์ ์
๋๋ค.
๋ ๊ฐ๊ธ์ Mixin์ ๋ค๋ฅธ Class๋ก๋ถํฐ ์์์ ๋ฐ์ง ์์์ inheritance chain์ ๋จ์ํ๊ฒ ์ ์งํจ์ผ๋ก์ ์์ํ์ง ๋ชปํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.