루나의 TIL 기술 블로그

위스타그램 4 업로드 (로그인 데코레이터)

|

[Mission 7] 게시물 등록 기능 구현

1. Postings app 생성

  • Django에서는 주로 다루는 데이터의 종류가 달라지는 시점에서 앱을 분리합니다. 인스타그램의 게시물은 이용자 데이터와는 그 성질이 달라 데이터베이스에서 테이블을 따로 관리합니다. 따라서, 주로 다루는 테이블이 달라지므로 앱을 분리하는 것이 좋습니다.

2. Posting Model 생성

  • 인스타그램에 게시물을 등록하기 위해서는 사용자, 생성 시간, 이미지 url이 필요합니다.
  • 해당 게시물의 유저는 Foreign Key를 이용하여 이미 서비스에 가입된 사람으로 연결시켜 주세요.
from django.db import models
from users.models import User

class Upload(models.Model): #나는 포스팅대신 업로드라는 이름을 사용했다
    user_id = models.ForeignKey(User, on_delete=models.CASCADE, db_column='user_id')
    #User테이블의 id를 참조하는 'user_id'이름의 컬럼을 만든다.
    created_at = models.DateTimeField(auto_now_add=True)
    text = models.CharField(max_length=300)
    img = models.CharField(max_length=400)
    
    class Meta:
        db_table = 'uploads'

데이터베이스 상의 필드 이름(db_column)은 테이블에 정의될 이름을 의미한다. db_column 매개변수를 사용하지 않는다면, 데이터베이스 필드에 작성될 필드명은 user_id_id가 되는데 이는 의도한 필드명이 아니므로, db_column 매개변수의 인수에 user_id를 사용한다.

3. Postings View 작성

:: 게시물 등록

  • 게시물 등록 클래스를 생성해주세요.
  • 게시물을 등록할 때에는 post메소드를 사용합니다.
  • 게시물 생성 시간은 등록하는 현재 시간이어야 합니다.

:: 게시물 표출

  • 등록된 모든 게시물을 나열하는 게시물 표출 클래스를 생성해주세요.
  • 게시물을 나타낼 때에는 get메소드를 사용합니다.
  • 게시물을 나타낼 때에는 등록한 사람, 게시물, 게시된 내용, 게시된 시각이 포함되어야 합니다.
import json

from django.views   import View
from django.http    import JsonResponse

from .models        import Upload as UploadModel 
#AttributeError: type object 'Upload' has no attribute 'objects'
#이 에러가 자꾸나서 스택오버플로우에서 찾은대로 as UploadModel로 갈음해주었다.
from users.models   import User
from users.utils    import login_decorator
#데코레이터는 유저스앱안에 따로 유틸스파일에 들어있다.

class Upload(View):
    @login_decorator #유저가 올바른 토큰을 가져왔다면
    def post(self, request):
        try:
            data = json.loads(request.body)

            if (data["img"] == ""): #이미지가 없으면 에러
                return JsonResponse({"message": "EMPTY_IMAGE"}, status=400)

            UploadModel.objects.create( #디비에 값을 추가
                user_id      = User.objects.get(id = request.user.id),
                #요청을 수행하는 유저의 아이디 
                img        = data["img"],
                text     = data["text"]
            )
            return JsonResponse({"message": "SUCCESS"}, status=201)

        except KeyError:
            return JsonResponse({"message": "KEY_ERROR"}, status=400)

    def get(self, request):
            uploads = UploadModel.objects.all()
            #업로드모델에 따라 객체를 다 가져와서 저장
            results = []

            for upload in uploads: #저장된 객체들을 한 개씩 돌면서
                results.append({
                    "user_id"      : upload.user_id.id,
                    #객체의 유저아이디번호에 해당하는 id
                    "img"        : upload.img,
                    "text"     : upload.text,
                    "created_at" : upload.created_at
                })
            return JsonResponse({"results": results}, status=200)

Decorater의 구조

import jwt

from django.http            import JsonResponse
from django.core.exceptions import ObjectDoesNotExist

from my_settings            import SECRET_KEY
from .models                import User

def login_decorator(func):
    def wrapper(self, request, *args, **kwargs):
        #들어올 수 있는 인자를 모두 받도록 한다
        try:
            token         = request.headers.get("Authorization", None)
            #헤더에서 Authorization(헤더에 있는 속성)을 가져와서 토큰에 저장한다.
            user          = jwt.decode(token, SECRET_KEY, algorithms='HS256')
            #토큰을 시크릿키를 이용해 디코드해서 유저 아이디를 알아내서 유저에 저장한다.
            request.user  = User.objects.get(id = user['id'])
            #유저의 아이디에 해당하는 유저객체를 리퀘스트.유저에 저장한다.

            return func(self, request, *args, **kwargs)
            #받은 인자들을 모두 전달해준다(예를 들어 이미지, 텍스트 등등)

        except jwt.exceptions.DecodeError:
            return JsonResponse({"message" : "INVALID_TOKEN"}, status=400)

        except ObjectDoesNotExist:
            return JsonResponse({"message" : "INVALID_USER"}, status=400)

    return wrapper

4. Urls.py 작성

클라이언트의 요청을 받아서 게시판 뷰를 호출할 수 있도록 urls.py 를 작성해야합니다.

  • ✅ 적절한 url 작성
#상위프로젝트폴더urls.py
from django.urls import path,include

urlpatterns = [
    path("users",include("users.urls")),
    path("upload",include("upload.urls"))
]
#하위앱폴더urls.py
from django.urls import path
from .views      import Upload

urlpatterns = [
    path("", Upload.as_view())
]

POSTMAN을 이용해서 Headers에 Authorization값을 넣고 Body에 JSON형식으로 값을 넣어서 디비에 이미지링크과 텍스트가 잘 입력된 모습을 볼 수 있다. 업로드