1차 프로젝트 후기

Yerin·2020년 1월 4일
1

프로젝트 소개

사용한 언어/framework

  • Python, Django, MySQL

내가 맡은 부분

  • 로그인, 회원가입 API
  • 메인페이지 API

느낀점

  • 데이터 모델링 - 가장 중요하고 어려웠다. 어떤 데이터의 테이블이 필요할지 생각해보고 서로 관계가 어떻게 되는지, 1-N인지 N-N인지 고민하는 과정 등 관계형 데이터베이스에 대한 개념을 알고 있다 해도 막상 실데이터에 적용해보려하니 쉽지 않았다. 처음에 Account app 안에 사용자와 호스트를 같이 넣지 않고 따로 model을 짰는데 나중가서 호스트 로그인을 따로 만들어야했던 귀찮음이 발생했다.. 처음부터 모델링을 할때 신중하게 해야한다.
  • 크롤링 - 세션에서는 beautiful soup으로 실습했었고 실제 데이터는 많은 것 같아서 selenium으로 시도를 해봤는데 어려워서 웹사이트에 접근하는것까지만 해보았다. 결론적으로는 둘다 안쓰고 csv를 만들고 그것을 데이터베이스에 넣어지게끔 하는 파이썬 파일을 만들어서 받아왔다. 예를 들어 tags 데이터를 가져온다고 하면 csv를 만들고 로직을 구현한 파이썬 파일 만들었다.
import requests as rq
import os
import csv
os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'wespace.settings')
CSV_PATH = './tag.csv'
import django
django.setup()
from space.models import Tags
with open(CSV_PATH, newline='') as csvfile:
    spamreader = csv.DictReader(csvfile)
    for row in spamreader:
        print(row)
        Tags.objects.create(
            tag = row['tag'],
            space_id = int(row['space_id']),
            )

python shell에서 실행하고 Mysql로 확인하면 데이터가 들어가있다.
로직에 대해 아직 정확히 이해한 것은 아니어서 더 자세히 알아볼 예정이다..

  • 로그인/회원가입 API - try/except 로 여러 exceptions에 대해 생각해야돼서 어려웠지만 구글링을 더 해봤다면 다른 예외처리들도 더 알게 되지 않았을까 싶다. 비밀번호 해싱하는 것에 대한 개념도 처음에는 이해가 어려웠는제 조금은 알 것 같다.다른 얘기지만 gitignore, my_settings 등의 파일도 잊지말것. 소셜로그인 api를 구현하지 못해 아쉬웠지만 어렵다고 하니까 그부분도 공부해서 언젠간 구현해보고싶다. 데코레이터에 대한 이해가 부족했는데 로그인 데코레이터를 구현해보면서 어떤식으로 데코레이터가 활용되는지에 대해 더 알 수 있었다.

  • 메인페이지 API - 로그인 구현하는것과는 다른 느낌. 프론트에서 어떻게 데이터를 받아야 매핑을 잘 할 수 있을지에 대해 무지했는데 이번에 하면서 조금 알게 되었다. 로직 구현할때 python list comprehension을 쓰는 것과 flat=True 쓰기. 예를 들면, 하나씩 튜플로 나오지 않고 객체로 나와서 프론트에서 매핑하기에 더 편리하다.

>>> Entry.objects.values_list('id').order_by('id')
<QuerySet[(1,), (2,), (3,), ...]>

>>> Entry.objects.values_list('id', flat=True).order_by('id')
<QuerySet [1, 2, 3, ...]>

ref:https://docs.djangoproject.com/en/3.0/ref/models/querysets/

  • MySQL 사용하기 - 여러번 드랍하고 새로 만들어보면서 데이터베이스와 테이블을 확인하고 값을 불러오고, 입력하고 등의 활용법을 익힐 수 있었고 여러 터미널 창을 띄워놓고 작업하는 것에 조금은 익숙해졌다..

기록하고 싶은 코드

  • 로그인/회원가입
import json
import bcrypt
import jwt

from wespace.settings import SECRET_KEY
from django.views import View
from django.http import JsonResponse, HttpResponse
from django.db import IntegrityError
from django.core.validators import validate_email
from django.core.exceptions import ValidationError

from .models import Accounts, Hosts
from account.utils import login_decorator


class AccountsView(View):
    def post(self, request):
        data = json.loads(request.body)

        try:
            if len(data['password']) < 6:
                return JsonResponse({'message': 'SHORT_PASSWORD'}, status=400)

            validate_email(data['email'])
            hashed_password = bcrypt.hashpw(
                data['password'].encode('utf-8'), bcrypt.gensalt())

            Accounts(
                nick_name=data['nick_name'],
                email=data['email'],
                password=hashed_password.decode('utf-8')
            ).save()

            return JsonResponse({'message': 'SUCCESS'}, status=200)

        except KeyError:
            return JsonResponse({'message': 'INVALID_KEYS'}, status=400)

        except IntegrityError:
            return JsonResponse({'message': 'EMAIL_ALREADY_EXIST'}, status=400)

        except TypeError:
            return JsonResponse({'message': 'WRONG_INPUT_VALUE'}, status=400)

        except ValidationError:
            return JsonResponse({'message': 'NOT_AN_EMAIL'}, status=400)


class AuthView(View):
    def post(self, request):
        data = json.loads(request.body)

        try:
            if len(data['password']) < 6:
                return JsonResponse({'message': 'SHORT_PASSWORD'}, status=400)

            user = Accounts.objects.get(email=data['email'])
            if bcrypt.checkpw(data['password'].encode('utf-8'), user.password.encode('utf-8')):
                access_token = jwt.encode(
                    {'id': user.id}, SECRET_KEY, algorithm='HS256')
                return JsonResponse({'access_token': access_token.decode('utf-8')}, status=200)
            else:
                return JsonResponse({'message': 'INVALID_PASSWORD'}, status=401)

        except KeyError:
            return JsonResponse({'message': 'INVALID_KEYS'}, status=400)

        except Accounts.DoesNotExist:
            return JsonResponse({'message': 'INVALID_ACCOUNT'}, status=400)

        except TypeError:
            return JsonResponse({'message': 'WRONG_INPUT_VALUE'}, status=400)

        except ValidationError:
            return JsonResponse({'message': 'NOT_AN_EMAIL'}, status=400)
  • 로그인 데코레이터
import jwt
import json
from django.http import JsonResponse
from .models import Accounts, Hosts
from wespace.settings import SECRET_KEY


def login_decorator(func):
    def wrapper(self, request, *args, **kwargs):
        if "Authorization" not in request.headers:
            return JsonResponse({"error_code": "INVALID_LOGIN"}, status=401)

        encode_token = request.headers["Authorization"]

        try:
            data = jwt.decode(encode_token, SECRET_KEY, algorithm='HS256')
            account = Accounts.objects.get(id=data['id'])
            request.account = account

        except jwt.DecodeError:
            return JsonResponse({"error_code": "INVALID_TOKEN"}, status=401)

        except Accounts.DoesNotExist:
            return JsonResponse({"error_code": "UNKNOWN_USER"}, status=401)

        return func(self, request, *args, **kwargs)
    return wrapper
  • python list comprehension 이용한 views 로직
from django.views import View
from django.http import JsonResponse

from .models        import Spaces, Space_Categories, Images
from account.models import Hosts


class CategoryView(View):
    def get(self, request):
        try:
            categories = list(Space_Categories.objects.values('id','category'))
            return JsonResponse({'Categority':categories}, status=200)
        except:
            return JsonResponse({'result':'ERROR'}, status =400)

class RecommendView(View):
    def get(self, request):
        spaces = list(Spaces.objects.all())[:6]
        recommend = [{
            'title'    : space.title,
            'price'    : space.price,
            'location' : space.location,
            'image'    : list(space.images_set.filter(space_id = space.id).values('space_image'))
        } for space in spaces]

        return JsonResponse({'data':recommend}, status =200)

class EditorView(View):
    def get(self, request):
        spaces = list(Spaces.objects.all())
        editor = [{
           'image'       : list(space.images_set.filter(space_id = space.id).values_list('space_image', flat=True)),
            'tag'        : list(space.tags_set.filter(space_id = space.id).values('tag')),
            'title'      : space.title,
            'price'      : space.price,
            'long_intro' : space.long_intro
            } for space in spaces]

        return JsonResponse({'data':editor}, status = 200)
        
class DetailSpaceView(View):
    def get(self, request, space_id):
        space = [
            {
                'id': space.id,
                'title': space.title,
                'short_intro': space.short_intro,
                'long_intro': space.long_intro,
                'price': space.price,
                'location': space.location,
                'open_time': space.open_time,
                'close_time': space.close_time,
                'min_guest': space.min_guest,
                'min_time': space.min_time,
                'space_images': list(space.images_set.values_list('space_image', flat=True)),
                'host': list(Hosts.objects.filter(id=space.host_id).values('id', 'nick_name', 'email', 'phonenumber')),
                'tag': list(space.tags_set.values_list('tag', flat=True)),
                'notice': list(space.notices_set.values_list('notice', flat=True))
            }
            for space in Spaces.objects.filter(id=space_id)]
        return JsonResponse({'result': space}, status=200)
                                                                                                                                                     
                                                                                                                                                    
profile
졸꾸 !!!

0개의 댓글