MTV패턴 Q&A


[질문]


설명드리지 못한 부분을 다시 공부해서 올립니다 :)
좋은 질문 많이 해주셔서 감사합니다. (–)(__)




[질문 3가지]

  • HTTP메서드, 중립적, 뭔소리
  • 서드 파티 라이브러리와 충돌하지 않게 하기
  • git branch는 뭔가요?


Q. HTTP 메서드에 중립적이라는 얘기는 무엇인가요?

장고의 함수 기반 뷰는 HTTP 메서드에 중립적이지만, 클래스 기반 뷰의 경우 HTTP 메서드의 선언이 필요하다는 것을 설명해준다. (Two Scoop of Django, p.98)



# 함수 기반 뷰
def function_based_view(request):
    # 로직
    return HttpResponse("FBV")

# 클래스 기반 뷰
class ClassBasedView(View):
    def get(self, request, *args, **kwargs):
	# 로직
        return HttpResponse("CBV")



A. ‘Django의 함수 기반 뷰는 중립적이다’ : if문에 따라 이럴 수도, 저럴 수도 있다.

니편이냐, 내편이냐 할 때 그 어느 편에도 서지 않는 사람을 보고 ‘중립적’이라고 하는데요. 함수형 뷰는 if request.method == 'POST' else ~ 처럼 request 종류에 따라서 응답이 달라집니다. 그래서 같은 함수이지만 request에 따라 어쩔 때는 get을 처리하는 함수, 또 다른 때는 post를 처리하는 함수가 되니 ‘중립적’이라고 표현한 것 같습니다.


from django.http import HttPResponse

def my_view(request):
    if request.method == 'GET':
    # 로직
    return HttPResponse('result')



반대로, class 뷰는 위의 def get 처럼 get이면 get, post면 post와 같은 request 메서드를 처리하는 함수를 선언해줘야 합니다.


class CustomerViewSet(viewsets.ModelViewSet) :
    queryset = Customer.objects.all()

    def get_queryset(self) :
        # 로직
        return queryset


그럼 class 뷰가 더 귀찮은 거 아닌가?라고 생각할 수 있겠으나… class 뷰의 장점 2가지가 있습니다.

  • if 함수가 아닌 메서드 명으로 구분할 수 있어 깔끔한 구조를 갖게 됩니다.
  • class는 다중 상속이 가능하므로 클래스형 제네릭 뷰, 믹스인 클래스를 상속 받아 생산성이 높아집니다.

추가 : 다른 클래스 뷰, 믹스인 클래스에서 필요한 메서드만 다시 골라서 나만의 믹스인 클래스를 만들 수도 있습니다.

class뷰와 함수형 뷰 중 뭐가 더 좋다고 할 수 없고, 상황에 따라 어떤 뷰를 만들지 선택해야합니다. 아래 요약본에서 순서도를 참고해보세요. Two Scooop Django 요약본 참고


Q.(예상 질문) 제네릭 뷰와 믹스인 클래스는 뭔가요?

A. 제네릭 뷰 : 한 마디로 삽질하지 말라고 Django에서 미리 만들어 놓은 뷰입니다. (저는 몰라서 삽질했습니다.) 개발 과정에서 공통적으로 사용하는 기능들을 기본적으로 제공합니다.

아래 코드는 제네릭 뷰 중에 FromView를 상속받아 만든 ContactView 클래스입니다. django에 내장되어 있는 FormView를 사용하여 아래 예제 코드와 같은 양식으로 작성하면 form view를 따로 만들지 않아도 됩니다.


from myapp.forms import ContactForm
from django.views.generic.edit import FormView

class ContactView(FormView):
    template_name = 'contact.html' #contact form을 편집할 때 보여줄 템플릿 
    form_class = ContactForm #forms 에 정의한 클래스 명
    success_url = '/thanks/' #성공적으로 form을 POST했을 때 리다이렉팅할 url path

    def form_valid(self, form):
        # form data가 POST되었을 때 호출
        form.send_email()
        return super(ContactView, self).form_valid(form)


A. 믹스인 클래스 : 여러 클래스를 다중 상속 받아서 내가 필요한 속성, 메서드만 골라서 한 군데 모아놓은 연장통입니다. django에서만이 아니라 Python 공통적으로 쓰는 개념이에요.

장고 공식 문서

form 을 편집할 때 아래 믹스인 클래스를 상속 받아 필요한 속성, 메서드를 사용하면 됩니다. 아래 경로에서 직접 어떻게 구성되어 있는지 확인해볼 수 있어요.

경로 : 가상환경 폴더(ex.'myvenv') -> Lib -> site-packages -> django-> views -> generic -> edit


class FormMixin(ContextMixin):
    form_class = None
    success_url = None
    prefix = None

    def get_initial(self):
        return self.initial.copy()

    ...(생략)


추가 :

Django의 최대 장점은 개발자가 삽질하지 않도록 이것저것 다 만들어두었다 건데요. tutorial을 따라하는 데에만 그치다보니 아주 기본적인 클래스만 알고, 다른 뷰에 대해서는 잘 몰랐네요. view - generic 폴더에 들어가시면 dates, detail, edit, list 등 기능 별로 view가 따로 만들어져 있어요.




Q. 한국어 맞나요?

아래 내용이 이해가 안됩니다.

8.4.2 서드 파티 라이브러리와 상호 운영성을 높이기

URL 이름을 myapp_detail 등의 방법으로 부를 때 생기는 또 다른 문제는 이 myapp 부분이 서로 겹칠 때 벌어진다. 이런 경우 URL 이름 공간을 통해 이를 간단히 해결할 수 있다.

예제 코드


urlpatterns += [
    path('contact/', include('contactmonger.urls', namespace='contactmonger')),
    path('report-problem/', include('contactapp.urls', namespace='contactapp')),
]


그리고 템플릿에서는 아래처럼 이용이 가능하다.


< a href="{% url "contactmonger:create"%}"> Contact Us < /a>
< a href="{% url "contactapp:report"%}"> Report a Problem < /a>



A. 이름이 충돌하는 것을 피하는 방법

‘_detail’는 상세 내용을 보여주는 페이지겠네요. 위의 예시에서는 contact라는 기능을 수행하는 ‘contactapp’이 있고요.

서드 파티 라이브러리나 서드 파티 패키지는 ‘남이 만든 라이브러리, 패키지’를 말해요. 여기서는 ‘contactmonger’라는 앱을 추가 했는데 앞에 핵심 키워드인 ‘contact’만 따서 detail 페이지를 만들려다보니까 contactapp의 url도 contact_detail이 되고, contactmonger의 url도 contact_detail이 되서 이름이 충돌하네요. 그래서 프로젝트 루트 urls.py에서 namespace라는 키워드 인수에 각 앱을 구별할 수 있는 이름을 넣어주고 있고요.

원래대로라면 아래처럼 url을 쓰겠지만..


# contactapp 만 있다면 이와 같은 코드겠지만.. 

< a href="{% url 'contact_detail' %}}">
    < button type="button" > Report a Problem < /button>
< /a>

새로운 앱때문에 contact_detail이라는 이름을 쓰기 어려우니 이름 공간을 사용했네요.

그럼 저기 있는 create, report는 왜 나오는 걸까요? 각 앱의 urls.py에서 create, report라는 name을 참조하여 그 앱의 url들 중 어떤 url인지 식별할 수 있습니다.


#contactapp의 urls
urlpatterns = [
    path('', views.get_problem, name='report'),
]

#contactmonger의 urls
urlpatterns = [
    path('', views.get_contact, name='create'),
]




Q. git branch는 뭔가요?

A. master라는 큰 줄기에서 뻗어나온 가지

우리 git remote add origin 깃저장소 주소 명령어로 로컬 저장소랑 원격 저장소를 연결했어요. 여기서 origin은 원격 저장소의 이름일 뿐이고, 원하는 이름으로 지어줄 수 있어요.

git remote -v를 하면 로컬 저장소와 연결된 원격 저장소를 확인할 수 있고요. 이때, 원격 저장소와 로컬 저장소를 연결하면 master라는 큰 줄기(branch)로 연결됩니다. 근데 우리가 코드를 수백 줄 수정하다가 에러가 났는데 다시 되돌리지 못하는 상황, 또는 테스트가 필요한 경우를 대비해 독립적인 공간을 하나 더 만들게 됩니다. 그때 필요한 게 branch에요. master에서 branch를 하나 더 만들어서 테스트해본 다음 문제가 없으면 master 브랜치에 적용합니다.

아래는 브랜치를 만드는 법입니다.


#test라는 branch 만들기
git branch test

#test 브랜치로 이동 
git checkout test

#branch 목록과 현재 내가 있는 branch 확인
git branch

#test 브랜치에 push하기 
git add .
git commit -m "test" 
git push origin test

#test 브랜치 내용을 master 브랜치에 반영하기
git checkout master #master 브랜치로 이동
git pull origin test #test 브랜치의 내용을 내 local 저장소에 가져옴 
git push origin master #master 브랜치에 적용하기