Django:제로부터 시작하는 인스타그램 만들기 - clone instagram #3

     

 

 


 

 

2021.09.15 - [Study/python] - Django:제로부터 시작하는 인스타그램 만들기 - clone instagram 목차

 

피드 목록에 백엔드 소스 추가하기

 

지난 포스팅에서 피드 업로드를 만들어보자~! 하고 끝났는데, 고민해보니 피드 업로드보다는 피드 목록에 대한 백엔드 소스를 추가하는 게 좋을 것 같습니다. 우리가 만든 Jinstagram은 지금 html에서 피드를 생성해서 보여주고 있습니다. 즉, 서버 없이 클라이언트(프론트)에서 알아서 데이터를 생성해서 피드 리스트를 만들고 있죠. 이걸 백엔드 쪽에서 피드 데이터를 내려주도록 바꿔보도록 하겠습니다. 

 

 

MTV (모델 템플릿 뷰)

 

Django는 MTV 구조로 되어있습니다. MTV란 모델, 템플릿, 뷰 3가지를 합쳐서 부르는 말인데요, 우리가 만드는 웹 서비스를 이 3가지로 분리할 수 있습니다. 

 

먼저, 모델은 데이터의 형태를 말합니다. 예를들어 피드를 구성하는 데이터는 어떤 것들이 있을까요? 

 

피드와 추천인을 구성하는 데이터들

피드 - { 본문, 사진, 프로필사진, 아이디, 좋아요 수 }
추천인 - { 프로필사진, 아이디, 추천 이유 }

위 그림처럼 피드라는 것을 구성하는 것은 제목과 본문, 사진, 글쓴이의 프로필 사진, 글쓴이의 아이디 등이 있습니다. 이 요소들을 다 합쳐서 피드 모델이라고 부릅니다. 즉 피드 모델 안에는 피드를 구성하는 데이터 모음이 있는 것이죠. 이걸 코드로 나타내면 아래와 같습니다.

 

//1단계 모델이름과 데이터 나열
모델명 - 피드
본문
사진
프로필사진
아이디
좋아요수
// 2단계 영어로 써보기
class Feed
    content
    image
    profile_image
    user_id
    like_count
// 3단계 python 코드로 변환
class Feed(models.Model):
    content = models.TextField()
    image = models.TextField()
    profile_image = models.TextField()
    user_id = models.TextField()
    like_count = models.IntegerField()
// 3+a단계 개발자처럼 보이기. 편-안-
class Feed(models.Model):
    content       = models.TextField()
    image         = models.TextField()
    profile_image = models.TextField()
    user_id       = models.TextField()
    like_count    = models.IntegerField()

 

django에서 모델은 class로 표기합니다. class는 모델보다 상위개념으로 객체를 뜻하는데 지금 당장은 모르셔도 됩니다 ㅎㅎ

class 모델명(models.Model): 이 기본형입니다. 따라서 피드는 class Feed(models.Model):이고 추천인은 class RecommendPeople(models.Model):로 쓸 수 있겠네요. 자 먼저 Feed모델을 소스에 녹여볼까요? Feed 모델을 만들기 전에 Feed모델을 어디에 넣을지 고민해봅시다. 우리는 앞으로 Feed도 만들고 RecommendPeople도 만들고 만들어야 하는 모델이 많습니다. 그 모델들을 하나의 소스에 모으면 그 양이 엄청 많을 거예요. 수정하기 위해 찾기도 힘들고... ㅎㅎ

 

다행히 장고는 APP(앱)단위로 소스를 관리할 수 있습니다. 사용자가 소스를 그룹으로 묶어서 관리할 수 있죠. 그래서 우리는 일단 content라는 앱을 하나 만들어보겠습니다. 앱을 만드는 것은 아래 명령어를 입력하면 됩니다.

 

python manage.py startapp <앱이름>

content

앱을 만들게 되면 폴더가 생성됩니다. 그리고 폴더를 열어보면..

 

python 소스들이 자동으로 생성됨

자동으로 소스들이 생성되는데 models.py와 views.py가 있습니다. 생성되는 소스는 django버전마다 다를 수 있습니다. 

아무튼 content앱이 생성되었으니 안에 있는 models.py에 모델을 추가해봅시다.

 

models.py

아마 그냥 class Feed부분만 적으면 models에 빨간 줄이 생길 겁니다. models라는 건 django에서 제공하는 기능이기 때문에 "나는 장고에 있는 models를 쓸 것이다"라고 알려줘야 합니다. 그게 바로 첫 번째 줄에 있는 from django.db import models입니다. 

 

그리고 각 요소 옆에 models.TextField()라고 적어논것이 있는데 컴퓨터한테 이 필드가 텍스트로 구성되어 있다고 알려주고 있습니다. 텍스트 말고도 여러 가지 형태가 있는데요, like_count를 보면 혼자 IntegerField()로 되어있습니다. 좋아요 수는 텍스트가 아니라 '숫자'로 이루어져 있기 때문에 숫자를 의미하는 IntegerField로 사용하게 됩니다. 지금은 숫자와 문자만 구별하고 추후 다른 것도 알아가도록 합시다.

 

model을 만들었으면 한가지 해야 하는 것이 있습니다. 바로 데이터베이스(DB)를 만드는 작업입니다. 데이터베이스는 데이터를 엑셀처럼 저장하는 파일이라고 생각하면 편합니다. 우리가 모델을 만듦으로써 DB에는 다음과 같이 모델을 저장할 수 있는 공간이 생깁니다.

 

DB는 엑셀처럼 생겼다.

jin.99가 쓴 피드를 위 DB안에 넣으면 아래와 같을 겁니다.

 

지금은 2번 row에 한줄의 데이터가 있지만 피드 데이터가 쌓이게 되면 3, 4, 5 쭈르륵 데이터가 생기겠죠? 이게 실제로 DB의 모습입니다. 이렇게 데이터가 표(table)처럼 쌓여있어서 DB안에서 모델 이름을 테이블이라고 부릅니다. 즉 우리가 만든 class Feed 모델은 DB에서 Feed 테이블로 만들어집니다. 

 

자 그럼 테이블은 어떻게 만들까요?

아주 간단합니다. 장고가 알아서 만들어주거든요 ㅋㅋㅋ 아래 명령어를 치면 됩니다.

 

python manage.py makemigrations
python manage.py migrate

 

그전에 한가지 중요한 게 있습니다. settings.py에 INSTALLED_APPS에 content을 추가하는 것입니다. 우리가 위에서 startapp을 이용해 앱을 만들었지만 Django에게 우리가 만든 앱을 사용하겠다고 명시해줘야 합니다. 그게 settings.py에 있는 INSTALLED_APPS입니다.

 

content 추가

자 이제 다시 아까 위에서 언급한 명령어를 실행해봅시다.

 

뭐라고 줄줄 나옵니다.

 

makemigrations는 우리가 만든 models.py를 DB에 반영하기 위한 스크립트(명령문)을 작성하는 명령어고, migrate는 그 스크립트를 실행하는 명령어입니다. 이제 테이블이 만들어졌습니다. 어떻게 확인할까요?

 

db.sqlite3

 

프로젝트 폴더에 db.sqlite3 파일이 생긴것을 볼 수 있습니다. Django는 기본적으로 sqlite3을 DB로 사용하고 있습니다. 따로 설정하지 않았다면 무조건 sqlite3을 사용해서 데이터를 관리합니다. 요걸 어떻게 읽을까요?

 

만약 파이참 프로버전을 사용하시면 툴에서 'database' 메뉴를 통해 데이터베이스를 볼 수 있습니다.

전용 database 툴이 내장되어있다.

 

하지만 커뮤니티버전은 이 기능을 지원하지 않는데요, 인터넷에서 꽤 괜찮은 툴을 하나 찾았습니다.

Downloads - DB Browser for SQLite (sqlitebrowser.org)

 

Downloads - DB Browser for SQLite

(Please consider sponsoring us on Patreon 😄) Windows Our latest release (3.12.2) for Windows: Windows PortableApp Note - If for any reason the standard Windows release does not work (e.g. gives an error), try a nightly build (below). Nightly builds ofte

sqlitebrowser.org

 

sqlite 브라우져입니다. mac용과 window용 둘 다 있습니다. (게다가 한글임)

 

설치할 때 따로 체크하지 않으면 바탕화면과 시작 메뉴에 추가되지 않습니다. 아마 C드라이브 Program Files에 가시면 DB Browser for SQLite 폴더가 있을 겁니다. 거기에 DB Brower For SQLite.exe를 실행하면 됩니다.

 

실행화면

 

파일 -> 데이터베이스 열기를 눌러서 우리 프로젝트 경로로 들어가 db.sqlite3를 선택합니다. 그럼 아래와 같이 DB안에 있는 내용들이 쭈욱~ 나옵니다.

 

테이블과 인덱스가 쭈우우욱

 

우리는 Feed라는 모델 하나밖에 안만들었는데 테이블이 12개나 있네요? 

 

그 이유는 Django에서 기본적으로 생성되는 테이블들이 있기 때문입니다. 잘 찾아보면 중간에 우리가 만든 content_feed라는 테이블이 있습니다. model에서 따로 테이블 이름을 지정해주지 않으면 앱이름_모델이름으로 테이블명이 자동으로 생성됩니다. 

 

content_feed를 열어보자

content_feed를 열어보면 위와같이 필드를 확인할 수 있습니다. 우리가 만든 model 그대로 만들어졌죠? 하지만 한 가지 우리가 만들지 않은 필드가 있습니다. 맨 위에 id 필드입니다. Django에서는 model을 만들 때 자동으로 primary key 역할을 하는 id 필드를 생성합니다. 이 id필드는 모델이 추가될 때마다 1번부터 시작해서 고유한 번호를 가지게 됩니다. 이 id필드를 이용해서 우리는 feed를 구별할 수 있습니다. 

 

요 DB Browser에서는 데이터도 수동으로 추가할 수 있습니다. 메뉴에서 '데이터 보기'를 누르면 테이블을 선택할 수 있는데, content_feed를 눌르고, 새 레코드 추가를 누릅니다.

 

새 레코드 추가

 

새 레코드를 추가하면 id가 1이라는 한 줄이 생기게됩니다. 각 빈칸을 더블클릭하면 오른쪽에 값을 채울 수 있는 창이 뜹니다. 여기에 값을 입력하고 적용을 누르면 됩니다. 

데이터 추가

 

다 입력하고 나면 반드시 '변경사항 저장하기'를 누릅니다. 요걸 안 누르면 저장이 안 되고 날아갑니다!! ㅋㅋㅋ

 

변경사항 저장하기

DB에서는 '변경사항 저장하기'와 같은 기능을 commit이라고 부릅니다. 여태까지 작업한 것을 저장한다는 뜻이죠. git에서 사용하는 commit도 동일한 뜻입니다.

 

자 이제 위에서 엑셀로 그렸던 것과 동일한 모양이 나왔습니다. 이렇게 보니까 정말 엑셀하고 닮았죠?

 

엑셀이랑 비슷

 

 

 

 

다시 MTV로 돌아오면 우리는 방금 models.py를 만들었고 지난시간에 views.py와 template/main.html을 만들었습니다. MTV에서 3가지를 모두 다 만들었네요! 앞으로는 이 3가지를 늘려가면서 서비스를 확장할 예정입니다. 이 3가지가 서비스의 핵심이니 어디에 위치하는지 잘 기억해두세요.

 

 

View 이용해서 데이터베이스에 있는 내용 Template으로 옮기기

 

우리가 만든 feed화면은 html에서 id랑 내용, 좋아요수등을 입력했습니다. 이렇게 화면단에서 데이터를 집어넣고 보여주는 것을 '하드코딩'이라고 하는데요. 왜 하드코딩이냐면 계속 실행해도 값이 변하지 않으니까요 ㅎㅎ.

 

여기서 "값이 변한다는게 뭐지?"라고 생각하는 분이 계실 텐데요, 만약 하드코딩을 하지 않고 서버에서 데이터를 받아와서 보여준다면 서버에 있는 데이터에 따라 feed화면이 변하게 됩니다. 예를 들면 위에서 우리는 DB에 데이터를 한건 생성했습니다. 지금 상태에서 DB에 있는 데이터를 읽어와서 feed에 보여준다면 하나의 피드만 보이겠죠? 만약 DB에 데이터를 더 추가해서 10건이 된다면 feed화면에는 10개의 feed가 보일 겁니다. 이렇게 서버에 따라 동적으로 데이터가 변하는 것이 하드코딩에 반대입니다. 생각해보니 딱 집어서 부르는 용어는 없는 것 같네요 ㅋㅋㅋ 왜냐하면 당연한 거니까..? 굳이 붙이자면 '동적 호출'입니다. 

 

그럼 어떻게 models.py로 만든 DB에서 main.html이 있는 곳까지 데이터를 이동시킬 수 있을까요? 이제부터가 View의 역할입니다. 

 

예전에 우리가 만들었던 views.py를 다시 봅시다.

 

from django.shortcuts import render
from rest_framework.views import APIView


class Main(APIView):
    def get(self, request):
        return render(request, 'jinstagram/main.html')

 

너모너모 간단하네요 ㅎㅎ 우리는 render를 통해 브라우저에서 main.html을 읽을 수 있게 했습니다. 이와 같은 방식으로 데이터를 넣어준다면 main.html에서도 model의 데이터를 사용할 수 있습니다. 다음과 같이 소스를 고쳐볼게요.

 

from django.shortcuts import render
from rest_framework.views import APIView
from content.models import Feed


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

 

무엇이 추가되었는지 보이시나요?

 

def get 아래 보면 feed_list = Feed.objects.all()이라는 한 줄이 추가되었습니다. 그리고 return render에 context라는 새로운 항목이 들어갔고요.

feed_list = Feed.objects.all()

이 코드는 앞으로 가장 많이 보게 될 코드입니다. 바로 우리가 만든 모델을 활용하는 코드인데요. models.py에서 Feed라는 모델 만든 거 기억하시죠? 우리가 모델을 만들 때 대문자로 시작했기 때문에 앞으로 대문자로 시작하는 모델명을 쓰면 그것은 우리가 만든 모델 전체를 가리키게 됩니다. 각 모델은 objects라는 걸 뒤에 붙여서 안에 데이터를 다룰 수 있는데요, Feed.objects.all()이라고 하면 Feed라는 모델 안에 있는 모든 데이터를 말합니다. 즉 feed_list 안에 Feed 모델의 모든 데이터를 넣는 코드입니다. 만약 데이터가 여러 개라면 List형태로 만들어지기 때문에 feed_list라고 이름 붙였습니다. feed_list는 아마 아래와 같은 모양일 겁니다.

 

feed_list = [ Feed1, Feed2, Feed3, Feed4.....]

이렇게 Feed들이 리스트로 담긴 feed_list를 render안에 context안에 집어넣었습니다. 근데 그냥 집어넣은 게 아니라 dict로 감싸서 집어넣었는데요, dict는 사전 형태로 key-value의 데이터를 가지고 있습니다. 즉 context에 사전형 데이터를 집어넣을 건데 그 사전형 데이터는 key가 feed_list고 value가 feed_list이 됩니다. context에 넣은 feed_list는 우리가 정의한 html로 넘어가게 되는데요, "render에 우리가 이동하고 싶은 html과 데이터를 각각 넣으면 데이터가 이동한다"라고 생각하면 됩니다.

return render(request, 'jinstagram/main.html', context=dict(feed_list=feed_list))

 

자 그럼 정말 이동되었는지 html에서 사용해볼까요?

 

main.html에서 body 바로 아래 테스트해보자

이전 시간에 만들었던 main.html로 돌아가서 body 태그 바로 아래다가 한번 값을 넣어보겠습니다. context를 통해서 views.py에서 넘어온 데이터는 중괄호 두 개로 사용 가능합니다.

 

{{ context데이터 }}
{{ feed_list}}

 

우리가 feed_list로 넣었기 때문에 feed_list를 입력해서 데이터를 꺼낼 수 있습니다. 하지만 feed_list에는 몇 개가 들어있는지 모르잖아요? 우리가 DB에 데이터를 한건만 넣었기 때문에 하나인 줄 알지만, Django는 모릅니다. 따라서 for문을 통해서 안전하게 하나씩 꺼내봅시다.

 

<body>
<!-- 여기에 테스트 해보자 -->

{% 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 %}


<!-- 상단 내비게이션 바 -->

html에서 python 코드를 쓰기 위해서는 {% %}를 사용하면 됩니다. for문을 사용해서 feed_list안에 feed를 하나씩 꺼냈습니다. for문이 끝나면 항상 {% endfor %}를 해주어야 합니다. for문 안에는 feed 모델 안에 있는 데이터를 하나씩 꺼냈는데요, feed에 id, image, content, profile_image, user_id, like_count 필드가 있었죠? 하나씩 <p> 태그 안에 넣어줬습니다. 그리고 실행하면?!

 

찍힌다

오 내비바 상단에 데이터가 찍히네요!!!

우리가 DB에 넣었던 데이터가 찍히는 것을 알 수 있습니다. 자 데이터가 찍히는 걸 알았으니 우리가 "하드코딩" 해놨던 feed 부분에 python 코드를 붙여보겠습니다.

 

border feed_box 하나가 하나의 feed를 구성한다.

html에서 feed 쪽 소스를 보면 border feed_box class를 가지고 있는 div가 feed 하나를 구성하고 있는 것을 알 수 있습니다. 지금 제가 두 개를 만들어놔서 두 개가 보이는데, 이 부분을 for문을 활용해서 feed의 데이터를 알맞은 곳에 넣게 바꿔야 합니다.

 

요렇게요

자 이러면 feed_list안에 feed만큼 feed_box div가 생깁니다. 그냥 생기기만 하면 의미가 없고 실제 데이터도 연결해야겠죠? feed_box안에서 image, content, profile_image 등 값들의 알맞은 위치를 찾아 {{ }} 를 활용해 넣어줍니다.

 

 

    {% for feed in feed_list %}
    <div class="border feed_box">
      <div class="feed_name">
        <div class="profile_box">
          <img class="profile_img" src="{{ feed.profile_image }}">
        </div>
        <span class="feed_name_txt"> {{ feed.user_id }}</span>
      </div>
      <img class="feed_img" src="{{ feed.image }}">

      <div class="feed_icon">
        <div>
          <span class="material-icons-outlined">
            favorite_border
          </span>
          <span class="material-icons-outlined">
            mode_comment
          </span>
          <span class="material-icons-outlined">
            send
          </span>
        </div>
        <div>
          <span class="material-icons-outlined">
            turned_in_not
          </span>
        </div>
      </div>
      <div class="feed_like">
        <p class="feed_txt"> <b>좋아요 {{ feed.like_count }}개</b></p>
      </div>
      <div class="feed_content">
        <p class="feed_txt"> <b> {{ feed.user_id }} </b> {{ feed.content }}</p>
      </div>
      <div class="feed_reply">
        <span class="feed_txt"> <b> mychew </b> 댓글은 아직 모델을 안만들어서 </span>
        <span class="feed_txt"> <b> cho </b> 항상 이 두개가 나옵니다 ㅋㅋ </span>
      </div>
    </div>
    {% endfor %}

 

중간중간에 중괄호를 활용한 값이 들어간 게 보이시나요? 아직 댓글은 안 만들었기 때문에 댓글은 두 개 고정입니다 ㅋㅋ 자 이제 한번 실행해보세요.

 

모양은 똑같지만 이제 하드코딩이 아닙니다.

 

기존에 있던 데이터로 만들었기 때문에 피드가 똑같이 나옵니다. 하지만 우리는 for문을 활용해 Feed 모델에 있는 모든 데이터를 뿌려주고 있습니다. 따라서 DB에 데이터를 추가하면?? 

 

이것저것 넣어보자

다시 데이터베이스툴로 넘어와서 데이터를 5개 추가로 넣어봤습니다. 내용 생각하는 거랑 이미지 찾기 너무 힘드네요 ㅋㅋㅋㅋ

 

자 이제 6개를 만들었기 때문에 페이지를 새로고침 하면 feed가 6개가 나와야 합니다. 두근두근

 

 

구웃~

 

구우우웃~!

 

자 이걸로 우리는 모델을 만들었고 모델에 데이터를 넣어서 를 통해서 템플릿으로 이동시켰습니다. 대부분의 조회 서비스는 이 구조로 서비스되기 때문에 한번 익혀두시면 다음부터는 빠르게 만드실 수 있습니다.

 

다음 포스팅에서는 화면에서 실제로 Feed를 생성하는 코드를 만들어보겠습니다~!! (진짜루 ㅎㅎ)

 

고생하셨습니다~~~

 

 

 

반응형

댓글

Designed by JB FACTORY