무대가 열렸다, 막이 올랐다 위로 올라가 니 세상을 보여 줘(기대해도 좋아)
[- 클로버, La Vida Loca 중에서 -]
드디어 총 4주, 2번의 프로젝트가 끝나고 기대와 긴장 속에 기업협업이 시작되었다.
우리 27기는 따로 플랜이 있었던 1명을 제외하고 40명 전원이 기업협업에 참여했는데, 나는 프1, 백2 로 이뤄진 3인 팀에 합류하게 되었다.
회사는 퀀텀AI라는 이름의 안면인식 인공지능 기반으로 얻은 데이터의 통계를 가지고 서비스를 하는 곳이었고 위치는 출, 퇴근의 메카 가산디지털단지였다.
퀀텀AI
대표님의 첫 인상은 후리함(free). 그리고 우리에게 하신 첫 마디도 '복장은 자율입니다' 였는데, 입가에 그려지는 미소를 감출수가 없었다. 사실 내게 취직을 할 때 가장 큰 불안요소는 다름 아닌 셔츠, 정장 통일 이었으니까. 그리고 이어서 회사의 현재 프로젝트, 목표, 최근 성과 등등 소소한 것까지 자세하게 알려주셨고, 또 하나 마음에 들었던, '아, 점심은 사드립니다. 옆 건물에 있는 한식뷔페가 있어요.' 이 한마디. 자율 복장에 밥 주고 10시 출근? 나한텐 이미 허들이 없는거나 마찬가지. 그저 대략 너무나 좋았다.
알면 알수록 신기한 백엔드의 세계였지만, 사수가 되신 백엔드 개발자님의 설명을 듣는데, 이건 뭐 신세계가 따로 없었다. 아, 먼저 우리에게 하달 된 것들에 대해 먼저 설명해야 하겠다. 프론트는 잘 모르니 패스, 백엔드는 DRF, djangoframework 를 사용하게 되었는데, 공식문서를 보면서 튜토리얼을 따라 하는 것이 첫 날의 임무였다. 물론 점심 먹기 전에 CRUD 를 모두 포함한 간단한 프로젝트를 만드는 것이 먼저긴 했지만, 모델도 간단했고 1, 2차로 다듬어진 model, view 작성법이 남아있어서 그리 어렵지 않게 만들어 낼 수 있었다. 이어서 오후에 DRF를 이용해 오전에 만들어 둔 프로젝트를 리팩토링 했는데, 비슷해 보이면서도 완전히 다른 세상이었다. 그리고 혹시나 이 글을 보게 될 예비 백엔드분들, 꼭 반드시 class
에 대한 개념은 꼭꼭꼭꼭꼭꼭 숙지하길 바란다. 나중에 열어보면 알겠지만, 온통 class
의 쓰나미다. 추상화 된 모델에 클래스에 함수에.. model
만들면서 추상화 모델을 한 번 만들어 봤으니 망정이지, 멍 때리다 울면서 돌아올뻔 했다. 암튼, 우리 자비로우신 사수님은 위코드 분이 셨는데, 마치 1타 강사처럼 세세하게 조목조목 알려주시면서 집중공부해야 할 부분, 나중에 해도 될 부분 등을 나눠서 알려주셨다. 진짜 사수님 짱!
프론트쪽 사수님도 굉장히 친절하시고 마치 동기에게 알려주듯이 연신 괜찮다면서 자세하게 설명해주려고 애를 쓰시는게 보였다. 본인들의 업무만으로도 야근을 해야 할 판인데, 한 달 후에 떠나게 될 우리에게 시간을 소비하시면서도 티도 내지 않으시고 질문은 언제든 하라시는 모습이 너무나 감사했다. To do list 가 쌓여 있는 와중에 나는 과연 저렇게 할 수 있을까 하고 다시 생각해보게 만드는 첫 날 이었다. 그래서, 첫 날의 만족도? 당연한 것 아닌가, 무조건 100점 만점.
우선 선생님, 학생으로 이뤄진 모델로 간단한 CRUD를 구현했다.
views.py
class TeacherView(View):
def get(self, request):
teachers = Teacher.objects.all()
result = [{'name' : [teacher_data.name]}for teacher_data in teachers]
return JsonResponse({'result':result}, status=200)
def post(self, request):
data = json.loads(request.body)
Teacher.objects.create(
name = data['name']
)
return JsonResponse({'message' : 'Created'}, status=201)
def patch(self, request):
data = json.loads(request.body)
teacher = Teacher.objects.get(id=data['id'])
teacher.name = data['new_name']
teacher.save()
return JsonResponse({'message' : 'Success'}, status=200)
def delete(self, request):
teacher_id = request.GET.get('id')
Teacher.objects.filter(id=teacher_id).delete()
return JsonResponse({'message' : 'Delete Success'}, status=200)
class StudentView(View):
def get(self, request):
students = Student.objects.all()
result = [
{
'teacher' : student_data.teacher.name,
'name' : student_data.name,
'email' : student_data.email
} for student_data in students
]
return JsonResponse({'result':result}, status=200)
def post(self, request):
data = json.loads(request.body)
teacher_data = data['teacher_data']
teacher_id = Teacher.objects.get(id=teacher_data)
Student.objects.create(
name = data['name'],
email = data['email'],
teacher_id = teacher_id.id
)
return JsonResponse({'message' : 'Created'}, status=201)
def patch(self, request):
data = json.loads(request.body)
student = Student.objects.get(id=data['id'])
student.name = data['new_name']
student.email = data['new_email']
student.save()
return JsonResponse({'message' : 'Success'}, status=200)
def delete(self, request):
student_id = request.GET.get('id')
Student.objects.filter(id=student_id).delete()
return JsonResponse({'message' : 'Delete Success'}, status=200)
patch
부분에 기능상 문제가 있지만, 일단 넘어가도록 하자.
아래는 Djangoframework 의 serializer
를 이용한 리팩토링 코드이다.
views.py
class TeacherModelViewSet(viewsets.ModelViewSet): # 클래스명은 룰임
permission_classes = [AllowAny] # 누구나 접근 가능(디폴트)
serializer_class = TeacherSerializer
queryset = Teacher.objects.all()
class StudentModelViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
serializer_class = StudentSerializer
queryset = Student.objects.all()
class ScoreModelViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
serializer_class = ScoreSerializer
queryset = Score.objects.all()
이것만 보면 도저히 알 수가 없다. 그래서 아래와 같은 것들이 선행되어야 한다.
serializers.py
from .models import Score, Teacher, Student
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
class TeacherSerializer(ModelSerializer):
student_name = serializers.SerializerMethodField()
class Meta:
model = Teacher
fields = '__all__'
def get_student_name(self, data):
student = data.student_set.all()
return student.values()
class StudentSerializer(ModelSerializer):
teacher_name = serializers.SerializerMethodField()
score_total = serializers.SerializerMethodField()
class Meta:
model = Student
fields = '__all__'
def get_teacher_name(self, data):
return data.teacher.name
def get_score_total(self, data):
score = data.score_set.get()
total = score.korean + score.english + score.math
result = {
'total' : total,
'avg' : total/3
}
return result
class ScoreSerializer(ModelSerializer):
class Meta:
model = Score
fields = '__all__'
urls.py
from django.urls import path
from user.views import StudentModelViewSet, TeacherModelViewSet, ScoreModelViewSet
teacher_list = TeacherModelViewSet.as_view({
'get' : 'list',
'post' : 'create'
})
teacher_detail = TeacherModelViewSet.as_view({
'get' : 'retrieve',
'put' : 'update',
'patch' : 'partial_update',
'delete' : 'destroy'
})
student_list = StudentModelViewSet.as_view({
'get' : 'list',
'post' : 'create'
})
student_detail = StudentModelViewSet.as_view({
'get' : 'retrieve',
'put' : 'update',
'patch' : 'partial_update',
'delete' : 'destroy'
})
score_list = ScoreModelViewSet.as_view({
'get' : 'list',
'post' : 'create'
})
score_detail = ScoreModelViewSet.as_view({
'get' : 'retrieve',
'put' : 'update',
'patch' : 'partial_update',
'delete' : 'destroy'
})
urlpatterns = [
path('teacher/', teacher_list),
path('teacher/<int:pk>/', teacher_detail),
path('students/', student_list),
path('student/<int:pk>/', student_detail),
path('score/', score_list),
path('score/<int:pk>/', score_detail),
]
serializers.py
에 잔뜩 들어있는 serialize
가 오늘 학습의 핵심이다. 사수님의 설명에 의하면, Model
과 View
사이에 있는 추상 클래스와 그보다 더 추상화 된 함수로 이루어진 코드다. 그래, 사실 아직은 잘 모르겠다. 공식문서에서 튜토리얼부터 정독해봐야 할 듯하다.
이제 시작이다 싶었더니, 아직도 신발끈을 묶고 있는 중이었다.
인생은 나의 무대, Attention Everybody.
[ - 클로버, La Vida Loca 중에서 - ]