[Django] clone instagram #3

이제부터 실제로 작동시키기 위해 백엔드 부분을 만져보도록 할 것이다.

ORM


디비의 오리지널 방식을 먼저 알아보자.

디비 만들고 코드 따로 만들고 조회하는 것 따로 만들어서 화면에 보여준다.
여기서 조회할때는 SQL을 사용한다.

즉, 오리지널 방식은 코드에서 디비를 select하여 데이터를 가져와 데이터를 채우고 화면에 보여주는 방식이다.

오리지널 방식에서는 코드에서 변수(name,age,gender,email)에 대해 모두 선언을 해주고, 디비에서도 (이름,나이,성별,이메일)을 넣어줘야 한다.

이러한 오리지널 방식에서 디비에 전화번호를 추가해줄 경우,
코드에서 추가해주지 않았을 때 데이터가 누락되는 일이 발생하게 된다.
전화번호라는 데이터를 가져오기 위해서는 코드에서도 phone이라고 이중작업을 해줘야하는 것이다.

이렇게 이중작업을 해야하는 문제때문에 ORM이라는 방식이 생기기 시작한 것이다.


그럼 ORM방식은 무엇이 다를까?

ORM은 객체(object)를 기반으로 디비를 만들어준다.

코드에서 class user 라는 객체에 이름,나이,성별,이메일을 만들어 주면
ORMdbobject를 자동으로 마이그레이션 해준다.
마이그레이션을 통해 디비에는 코드에 있는 object 그대로 user라는 테이블에 저장된다.

따라서 데이터 추가나 수정사항이 있어도 코드와 디비가 자동으로 마이그레이션되기때문에
양쪽을 모두 관리할 필요없이 코드만 관리해주면 된다.

또한 ORMsql쿼리문을 작성하지 않아도 된다. 코드를 작성하면 ORM이 알아서 코드를 sql로 바꿔준다.
장고에서는 이것을 '쿼리셋'이라고 한다.



DB 구상하기


그럼 이제 피드에 대한 데이터베이스를 만들어줘야 한다.

ORMobject를 기반으로 디비를 만들기 때문에 데이터베이스를 만들기 위한 object가 무엇일지 생각해봐야 한다.

데이터베이스는 쉽게 엑셀형식이라고 생각하면 된다. 하나의 column(열)에 하나의 값만 들어갈 수 있다



다음 피드와 댓글의 내용을 보여주기 위한 데이터베이스를 구상해보자면 다음과 같다.

>> 피드 table <<
프로필사진 | 글쓴이아이디 | 사진 | 글내용


>> 댓글 table <<
댓글남긴사람 | 댓글내용

피드를 보여줄 때 댓글까지 보여주고 싶다면,
첫번째 피드에 대한 데이터를 가지고 첫번째 피드를 그려준 다음,
댓글 테이블에서 피드id1로 갖는 데이터들을 모두 가지고 화면에 그려주게 된다.

이렇게 하나의 피드를 그리는데 하나의 테이블만이 필요한 것이 아니라 여러개의 테이블이 필요할 수도 있다.

여러개의 테이블이 필요한 경우에는 고유한 id값을 이용해서 데이터를 서로 연결시킬 수 있다.

db에서는 이러한 고유id값으로
Primary key(기본키)와 Foreign key(외래키)라는 것을 사용한다.


서비스에 따라서 데이터베이스의 구조 즉, 테이블이 어떻게 구성되는지 바뀌기 때문에
원하는 서비스가 어떤건지, 어떠한 기능을 하는지를 잘 알아야 디비의 테이블을 어떻게 구성할 것인지 알 수 있다.



models 만들기


디비를 구상해보았으니 실제로 코드에 객체를 만들어주도록 하겠다.

- content/models.py

class Feed(models.Model):  # Feed라는 객체의 데이터베이스 만들기
    profile = models.TextField()  # 프로필사진    
    user_id = models.TextField()  # 사용자아이디
    image = models.TextField()    # 사진
    content = models.TextField()  # 글내용
    like_count = models.IntegerField()  # 좋아요수

코드를 살펴보면,
TextField()와 같이 디비에 해당 필드가 어떤 데이터형식을 표시하는지 정의해줄 수 있다.


이렇게 Feed라는 객체에 대해 다섯개의 필드를 만들어 준 뒤, 마이그레이션을 해준다.

(venv) python manage.py makemigrations

마이그레이션을 해주면 장고에서 자동으로 사용자가 models에 선언한 클래스(객체)를 모두 찾아서 디비로 만들어줄 작업을 하게된다.


(venv) python manage.py migrate


그럼 디비에 content_feed라는 테이블로 위에서 만들어준 5개의 필드가 만들어지고 추가로 id라는 고유값이 자동으로 만들어진다.



views 만들기


models.pyDB를 만들어 줬으면, 이제 데이터를 어떻게 템플릿으로 전달해줄지 views를 만들줘야 한다.

-content/views.py

from .models import Feed

class Main(APIView):
    def get(self, request):
        feed_list = Feed.objects.all()
                
        return render(request, "instagram/main.html", context=dict(feed_list=feed_list))

코드를 해석해보자면, 다음과 같다.

  • feed_list = Feed.objects.all()
    :Feed 테이블에 있는 모든 데이터를 가져온다
  • return render(request, "instagram/main.html", context=dict(feed_list=feed_list))
    : 데이터베이스에서 가져온 데이터를 담아서 instagram/main.html에 보내준다.

이렇게 뷰에서는 디비에 있는 데이터를 가져와서 템플릿으로 보내주게 된다.



url 연결하기


main/이라는 url을 받았을 때 방금전 뷰에서 만들어준 Main을 호출하기 위해서 url.py파일을 수정해준다.

- instagram/urls.py

from content.views import Main 

urlpatterns = [
    path('admin/', admin.site.urls),
    path('main/', Main.as_view())
]

url을 설정해줌으로써 main/이라는 url을 타고 들어올 경우 content 앱에 있는 viewsMain을 호출하게 된다.



템플릿에 데이터 넣어주기


뷰로부터 넘어온 데이터를 템플릿에 적용시켜주도록 하겠다.

받아온 데이터를 템플릿에 적용시켜 줄때는 다음과 같은 방식을 사용한다.

{% for feed in feed_list %}
  <p>{{ feed.id }}</p>
  <p>{{ feed.image }}</p>
  <p>{{ feed.content }}</p>
  <p>{{ feed.profile_image }}</p>
  <p>{{ feed.user_id }}</p>
  <p>{{ feed.like_count }}</p>
{% endfor %}

반복문이 시작하는 지점에 {% for feed in feed_list %}을 넣어주고, 반복문이 끝나는 지점에 {% endfor %}를 넣어준다.

그리고 받아온 데이터값을 넣어줄 곳에 {{ feed.필드이름 }}을 넣어주면, 알아서 데이터베이스에 있는 값들이 들어오게 된다.

이것을 바탕으로 이전에 작성해준 main.html파일을 수정해보도록 하겠다.

- templates/instagram/main.html

...
<!-- 피드박스 시작 -->
{% for feed in feeds %}
<div class="feed-box">
    <div class="profile">
        <div class="profile-img-box">
            <img class="profile-img"
                src=" {{ feed.profile }} ">
        </div>
        <div class="profile-id">
            {{ feed.user_id }}
        </div>
    </div>

    <div class="feed-img">
        <img id="feed-img"
            src=" {{ feed.image }} ">
    </div>

    <div class="icon">
        <div>
            <span class="material-icons-outlined">favorite_border</span>
            <span class="material-icons-outlined">chat_bubble_outline</span>
            <span class="material-icons-outlined">send</span>
        </div>
        <div>
            <span class="material-icons-outlined">bookmark_border</span>
        </div>
    </div>

    <div class="like">
        django <b>외 {{ feed.like_count }}명</b>이 좋아합니다
    </div>

    <div class="feed-text">
        <b>{{ feed.user_id }}</b> {{ feed.content }}
    </div>

    <div class="comment">
        <div> <b>기덕</b> 장고 화이팅 </div>
        <div> <b>재명</b> 알고리즘 화이팅 </div>
        <div> <b>이성</b> 파이썬 화이팅 </div>
    </div>

    <div class="input-comment">
        <input id="input-comment" type="text" class="form-control" placeholder="댓글 달기...">
    </div>
</div>
{% endfor %}

이때 한가지 수정해줘야할 부분이 있다.
지금은 가장 최근에 추가된 데이터가 피드 아래에 생기고 있다.

원래는 최근에 추가된 데이터가 가장 최신글로 상단에 떠야하기 때문에 이를 수정해줘야한다.

가장 최근에 추가된 데이터의 id값이 가장 클 것이다.
원래는 뷰에서 디비를 가져올때 id값이 작은거 부터
즉, 1 >> 2 >> 3번 순서대로 가져온다.

따라서 이 순서를 역순으로 가져오게 수정해보도록 하겠다.

- content/veiws.py

class Main(APIView):
    def get(self, request):
        feed_list = Feed.objects.all().order_by('-id')

        return render(request, "instagram/main.html", context=dict(feeds=feed_list))

  • .order_by('-id') : id값이 큰것부터 가져옴

이렇게 수정한 뒤 서버를 돌리면 최신글이 최상단에 올라오도록 수정된 것을 확인 할 수 있다.



🔎 참고
강의
강의자료

좋은 웹페이지 즐겨찾기