Project: westagram -3 (21.06.02)

16631 단어 WeCodeprojectWeCode

👍 오늘 한일

  1. Mission2 과제 진행 - 회원가입 엔드포인트 만들기
    • hash화된 비밀번호 db 저장시 문자열로 변경하여 저장하도록 관련내용 수정
  2. Mission3 과제 수정 - 로그인 엔드포인트 만들기
    • 불필요한 암호화 하는 함수 제거
  3. Mission4 과제 진행 - 포스팅 만들기 (PR상태)
    • 포스팅 등록
    • 포스팅 전체 조회, 1개만 조회

회원가입 model만들기 (수정완료)
회원가입 view만들기 (완료)
회원가입 시 db에 저장되는 비밀번호 hash화 해서 저장하도록 변경(완료)
Mission3 과제 진행 - 로그인 엔드포인트 만들기 (PR상태)

🔥 변경 사항

  1. 암호화 하는로직을 함수로 분리하였는데, 불필요하여 함수 제거
  2. hash화된 비밀번호를 db 저장시 문자열로 변경하여 저장하도록 관련내용 수정

❗️ Mission4 - 게시물 기능 구현

📝 Model

1.게시물을 등록하기 위해서는 사용자, 생성 시간, 이미지 url이 필요합니다.
2. 해당 게시물의 유저는 Foreign Key를 이용하여 이미 서비스에 가입된 사람으로 연결시켜 주세요.

  • 우선 포스팅을 저장할 수 있는 Posting model를 만들었고, 한명의 user가 여러개의 글을 쓸 수 있으므로, User model과 1:N 관계를 맺었다.
  • 하나의 포스팅에는 여러개의 Image가 들어 갈 수 있으므로 이미지를 저장 할 수 있는PostingImage model를 만들어서 Posting과 1:N 관계를 맺었다.

class Posting(models.Model):
    user       = ForeignKey('users.user', on_delete=models.CASCADE)
    main_text  = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'postings'

class PostingImage(models.Model):
    posting = ForeignKey(Posting, on_delete=models.CASCADE)
    url     = models.CharField(max_length=200)

    class Meta:
        db_table = 'posting_images'

📝 View

  1. 게시물을 등록할 때에는 post메소드를 사용합니다.
  2. 게시물 생성 시간은 등록하는 현재 시간이어야 합니다.
  3. 게시물을 나타낼 때에는 get메소드를 사용합니다.
  4. 게시물을 나타낼 때에는 등록한 사람, 게시물, 게시된 내용, 게시된 시각이 포함되어야 합니다.

✍️ 포스팅 등록

  • user정보는 header의 token 형태로 받았다.
  • 나머지 정보는 body에 json 형태로 받았다.
  • 우선 image_url 정보가 list형태가 아니인지 체크하였다. 문자열로 들어오면 for문을 돌때, 한 문자씩 받아오기 때문에 문제가 발생할 수 있다고 생각했다.
  • 그리고 2개의 테이블에 insert해야 되므로(postings, posting_images) 이 두가가지 테이블에 insert하는 구문을 transaction으로 묶었다.
def post(self, request):
        try:
            data       = json.loads(request.body)
            token      = request.headers['token']
            image_urls = data['image_urls']
            user_id    = jwt.decode(token, SECRET_KEY, 
                                    algorithms=HASH_ALGORITHM)['user_id']
            if type(image_urls) is not list:
                return JsonResponse({'message': 'INVALIED_DATA'}, status=400)
                
            with transaction.atomic():
                new_posting = Posting.objects.create(
                    user      = User.objects.get(id=user_id),
                    main_text = data['main_text']
                    )
                    
                for image_url in image_urls:
                    PostingImage.objects.create(
                        posting = new_posting,
                        url     = image_url
                        )

🔎 포스팅 조회

포스팅 조회는 2가지 상황(전체, 1개)을 생각하여, 각각 url를 설정하였다.
하지만 이렇게 설정하자 기존에 잘 되었던 모든 포스트를 조회하는 url이 안 되었다.

urlpatterns = [
    path('', PostingView.as_view()), # 모든 게시물 조회
    path('/<int:id>', PostingView.as_view()), # 단일 게시물 조회
    ]

그래서 다음과 같이 순서를 바꾸니 되었다.

urlpatterns = [
    path('/<int:id>', PostingView.as_view()), # 단일 게시물 조회
    path('', PostingView.as_view()), # 모든 게시물 조회
    ]

url 작성시 순서를 유의하면서 작성을 해야겠다.

그래서 모든 posting을 조회하는 기능은 all()를 사용해서 불러드린 후, 각 posting의 정보를 가공해서 list형태로 묶어서 만들었다.

    def get(self, request):
        result   = [self.make_posting_response_data(posting) 
                    for posting in Posting.objects.all()]

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

하나의 조회하는 기능은 포스팅 id에 해당하는 정보가 있는지 검색 후 반환하도록 하였다.

    def get(self, request, id):
        try:
            posting = Posting.objects.get(id=id)
            result = self.make_posting_response_data(posting)

그런데 2가지 조회 기능의 데이터를 만드는 로직이 중복되어 중복되는 부분을 메쏘드로 만들었다.

def make_posting_response_data(self, posting):
        return {
                'user'       : posting.user.email,
                'main_text'  : posting.main_text,
                'created_at' : posting.created_at
                                .strftime('%Y-%m-%d %H:%M:%S %z %Z'),
                'image_urls' : list(
                    posting.postingimage_set.all()
                    .values_list('url', flat=True))
                }

🤔 궁금증

현재 게시물 생성시간을 auto_now_add 옵션을 사용해서 저장하고 있습니다.

DateTimeField(auto_now_add=True)

이러한 형태로 저장되면 UTC 0 기준으로 저장이됩니다. 즉 보이는 시간 자체는 한국시간과 다릅니다.
그래서 아래 옵션을 다음과 같이 바꿔서 한국 시간 기준으로 저장을 하였었습니다.

TIME_ZONE = 'Asia/Seoul'
USE_TZ = False

하지만 더 찾아보니 USE_TZ = False를 적용하면 naive datetime으로 저장된다고 합니다.
즉 UTC정보가 없는 시간정보만 저장이 되는 것이죠.
그래서 이 방법은 좋지 않다 하여 다시 UTC0 으로 저장되도록 롤백하였습니다.
이러면 UTC 정보만 알면 지역에 맞는 시간을 구할 수 있겠지만, 저는 사용자의 UTC에 맞춰서 저장 할 수 있는 방법이 있을까 궁금했습니다.

그래서 제가 떠오르는 생각은 아래 3가지 시나리오 정도입니다.

  1. 요청받을 시, Time-Zone 정보도 같이 받는다. 그 정보를 기반으로 UTC를 알아내서 시간을 저장한다.
  2. 무조건 UTC0 기준으로 저장하고, 프론트에서 사용자의 Time-Zone에 맞춰서 변환한다.
  3. 사용자의 Time-Zone을 알아낼 수 있는 라이브러리를 사용해서 UTC를 알아내서 시간을 저장한다 ( 🔗 django-tz-detect)

그래서 현업에서는 어떠한 방식으로 시간 data를 관리 및 저장하는지 궁금하네요

🔗 파이썬의 시간대에 대해 알아보기
🔗 [Django] TIME_ZONE, USE_TZ 설정

좋은 웹페이지 즐겨찾기