[TIL 11일자] 데브코스 데이터엔지니어링

·2023년 4월 24일
0

데브코스

목록 보기
10/55
post-thumbnail
post-custom-banner

📚 오늘 공부한 내용

1. Django Project 생성

1) Python 가상 환경 생성 및 활성화

  • Python의 가상 환경을 생성하기 위해서는 다음과 같은 명령어를 사용해 준다.
py -m venv project-name
  • 이 가상 환경을 활성화하기 위해서는 다음과 같은 명령어를 실행해 준다.
project-name\Scripts\activate.bat

#다시 비활성화를 원할 시 명령어 실행
deactivate 

2) 새로운 Django 프로젝트 생성

django-admin startproject project-name

3) manage.py

  • manage.py는 Django 프로젝트를Terminal에서 조작할 수 있는 명령을 제공한다.
python manage.py runserver
  • 서버 실행 시 다음과 같이 포트 번호가 뜨게 되고 브라우저에서 해당 포트로 접속하면 Djangodefault 페이지가 뜨게 된다.
    (Djangodefault 페이지)

2. Django App 생성

  • 1에서 만들었던 프로젝트에 App을 생성해 보자.
python manage.py startapp app-name
  • 웹페이지주소/RequestURL를 하면 GET method를 통해 Request URL을 찾아 해당하는 APP을 보여 준다.

3. URL 경로 설정

1) mysite(프로젝트 메인) urls.py에서 app 호출

  • urls.py에서 url을 만들 수 있다.
#mysite의 urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('polls/', include('polls.urls')), #만약 polls라는 requestURL을 받으면 polls.urls에서 처리해 주도록 전달
    path('admin/', admin.site.urls),
]

2) polls(호출한 app) urls.py에서 url 경로 설정

  • 이번에는 APP을 생성할 것이기 때문에 생성된 Appurls.py를 생성해 url 패턴을 만들어 준다.
#polls(app-name)의 urls.py
from django.urls import path
from . import views #views가 선언되지 않으면 오류가 남

urlpatterns = [
    path('', views.index, name='index'),  #만약 requestURL이 없으면 views의 index에 간다.
]

3) polls(호출한 app) views.py에 url 호출 시 보여 줄 화면 구현

  • 제대로 호출이 되었는지 안 되었는지 확인을 위해 polls라는 새로 만든 appviews.pyindex에 단순한 코드를 넣어 준다.
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, World.")
  • 다음과 같이 우리가 urls.py에 추가해 준 polls로 들어갔을 때 Hello, World가 표출되는 것을 알 수 있다.

4. 모델 만들기

  • models.py DB를 테이블별로 읽어서 하나의 테이블에 저장된 값을 코드에서 읽을 수 있게 도와준다.
  • 이 기능을 orm이라고도 부른다.
  • 간단하게 설문조사를 하는 모델을 생성해 보자.

1) 사용할 modelmodel.py 생성

#model은 models.Model을 상속받아야 한다.
from django.db import models
class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    #Question의 unique id 저장 
    question = models.ForeignKey(Question, on_delete = models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.InterField(default=0)

2) setting.pyINSTALLED_APPS 추가

  • setting.py에서 INSTALLED_APPSAPP을 정의하는 곳이다.
  • 이곳에 만든 app을 추가해 주는데 만든 APP(polls)apps.py에 있는 config 클래스 이름을 추가해 주면 된다.
INSTALLED_APPS = [
    'polls.apps.PollsConfig', #추가한 app
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

3) 만든 modelmigration하기

  • 만든 modelmigration 하기 위해 다시 Terminal로 가 명령어를 입력해 준다. 이 명령어는 모델의 변경 사항을 담고 있는 마이그레이션 파일을 생성하는 명령어이다.
python manage.py makemigrations app_name
  • 입력해 주면 다음과 같이 models.py에 만들어 둔 두 개의 classmodel로 생성되었음을 알 수 있다.
  • 이때 테이블 구조를 직접 보기 위해서는 다음과 같은 명령어를 입력해 준다.
python manage.py sqlmigrate polls 0001
  • 이후 테이블들이 이렇게 생성됨을 알 수 있다.
  • 마이그레이션을 실행해 변경된 내용을 데이터베이스에 적용하는 명령어는 다음과 같다. 이 단계까지 거치면 최종적으로 Django에 테이블이 생성된 것이다.
python manage.py migrate

5. 모델에 Field 추가

  • Django의 Field 타입은 공식 문서에서 확인할 수 있다.
  • Field에는 많은 종류가 존재한다. 예를 들어 CharField, DateField, TextField 등이 있다. (각자 데이터 타입을 적용할 때.)
    1) models.pyfield를 추가할 모델에 추가
class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')
    is_something = models.BooleanField(default=False)  #boolean 타입의 field를 추가했다.
    average_score = models.FloatField(default=0.0)     #float 타입의 field를 추가했다.

2) field를 모델에 반영하기 위해 migration하기

  • models.py를 수정 후 이를 실제 모델에 반영하기 위해서는 4에서 진행한 방식과 동일하게 migration 해 주어야 한다.
python manage.py makemigrations #변경 사항 확인
python manage.py migrate #변경 사항 DB 반영
  • 이후 제대로 모델이 반영됐는지 확인하기 위해 sqlite3(Django에서 제공하는 SQL 환경)에 접속한다.
  • 접속 시에는 sqlite3 db.sqlite3 명령어를 입력해 준다.
  • 그후 .tables를 하면 다음과 같이 현재 프로젝트의 DB에 생성된 TABLE을 확인할 수 있다.
  • SQL문을 사용하여 각 테이블을 조회할 수도 있다. ;을 사용해 쿼리문을 종료해 준다.
  • 테이블의 구조를 보기를 원한다면 .schema table명을 입력해 준다.
  • SQL 종료를 위해서는 ctrl+C를 해 주면 된다.
  • 만약 모델 상태를 초기 상태로 바꾸어 주기 위해서는 다음과 같은 명령어를 사용해 준다. 당연히 코드가 수정되지 않은 상태로 migration을 하면 현재 상태로 돌아오게 된다. (migration 파일models.py도 바꾸어 주어야 한다.)
python manage.py migrate polls 0001  #polls의 상태를 0001의 초기 상태로 돌려준다

6. 관리자 계정 생성하고 접속하기 (Admin)

  • admin 페이지는 시스템을 관리하는 관리자들이 데이터를 추가하거나 수정하는 페이지를 말한다.

1) admin 계정 만들기

  • admin 계정superuser 계정이기 때문에 사용자에게 부여되면 안 된다.
python manage.py createsuperuser  #admin (superuser 계정을 만든다)

2) django server에 접속하여 로그인

  • Django에서 부여된 포트/admin을 하면 로그인 창이 나오게 된다.
  • 이후 1)의 단계에서 만들었던 admin 계정으로 로그인을 하면 유저와 그룹을 관리할 수 있는 화면이 나온다.
  • User에서 특정 user들을 만들어 줄 수 있고 superuser를 추가할 수도 있다. 그 유저들은 admin 화면에서 로그인 가능하다.

7. 모델 등록하기

  • Django adminmodel들도 등록해서 쉽게 admin에서 등록할 수 있는 방법은 없을까.

1) admin.py에 모델을 등록

from .models import *

# Register your models here.
admin.site.register(Question) #admin 사이트에 Question 모델을 등록한다

2) admin에 접속해 확인

  • 그러면 다음과 같이 Polls의 Questions가 있는 것을 알 수 있고, add를 눌러 데이터를 추가할 수 있다. (테이블 구조를 바꿀 수 있는 게 아니라 데이터를 넣을 수 있는 것이다.)

3) admin에서 데이터 등록

  • add 선택 시 테이블 구조에 맞는 데이터 값을 입력할 수 있는 창이 나온다.
  • 그렇게 추가된 데이터들은 다음과 같이 뜨는데 Question을 대표적으로 어떻게 표시해 줄 것인지에 대해서는 models.py를 통해 수정할 수 있다.
  • models.py를 수정해 준다. def __str__(self)를 통해 수정될 값을 변경해 줄 수 있다.
class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return f'제목: {self.question_text}, 날짜: {self.pub_date}'
  • 그러면 다음과 같이 바뀌게 된다.

8. Django Shell 사용

  • python manage.py shell 명령어를 통해 shell에 접속할 수 있다.
  • 다음과 같이 Django Shell에서 모델을 쓰고 싶을 시에는 따로 import를 해 주어야 함. (Django shell전체 프로젝트를 관점으로 실행되기 때문에)
  • object데이터를 읽어오길 바랄 때는 model.objects.all()을 입력한다.
  • 모든 Question,Choice 오브젝트 가져오려면 .object.all()을 사용한다.
Question.objects.all()
Choice.objects.all()
  • Choice의 첫 번째 데이터를 변수에 담는다.
choice = Choice.objects.all()[0]
choice.id
choice.choice_text
choice.votes
  • Choicemodels.py에서 question이 정의되어 있어 호출만 하면 가지고 올 수 있다. (ForeignKey로 관계를 맺고 있기 때문에.)
choice.question
choice.question.pub_date
choice.question.id
  • Question에서는 models.pychoice를 가지고 올 수 있는 요소가 없다. 그렇기 때문에 choice_set을 사용해서 확인해 준다.
question.choice_set.all()

9. Django shell에서 현재 시간 구하기

  • Django에서는 timezone을 사용해서 시간을 구한다. datetime과 출력 값을 보면 다르다는 것을 알 수 있다.
from datetime import datetime
datetime.now()
#output: datetime.datetime(2023, 4, 25, 2, 52, 9, 115630)
from django.utils import timezone
timezone.now()
#output: datetime.datetime(2023, 4, 24, 17, 52, 24, 443460, tzinfo=datetime.timezone.utc)

10. Django shell에서 데이터 생성 및 수정, 삭제

1) 데이터 생성

  • 변수 하나를 만든 후 추가하고자 하는 데이터를 넣어 주면 된다.
q1 = Question(question_text = "커피 vs 녹차")
q1.pub_date = timezone.now() #현재 시간을 저장해 준 후 

q1.save() #DB에 반영 

DateTime default 값 설정

  • auto_now = true를 하면 데이터가 저장될 때마다 현재 시간이 저장된다.
  • auto_now_add = True를 하면 데이터가 처음 추가될 때 현재 시간이 저장된다.

2) 연결된 테이블의 데이터 추가하기

q3.choice_set.create(choice_text = "b") #set을 연결하여 추가할 수 있음 (create 메소드 활용)
choice_c = Choice(choice_text='c', question=q3) #Choice 변수를 그대로 추가할 수도 있음 (question이라는 key값으로 연결)
choice_c.save() 

3) 데이터 변경하기

q = Question.objects.last() #Question에 저장된 데이터 중 가장 마지막 데이터를 조회 후 변수에 담는다
q.question_text = q.question_text + '???' #변수에 내용을 더해 수정한다.

4) 데이터 삭제하기

choice = Question.objects.last() 
choice.delete() #데이터를 삭제한다

11. Django shell에서 필터링 하기

1) get을 이용한 필터링

  • get은 데이터가 하나인 경우나 아예 존재하지 않는 경우에 대해 오류가 발생한다는 사실을 인지하고 사용해야 한다.
  • 데이터가 존재하지 않는 경우 polls.models.Question.DoesNotExist: Question matching query does not exist. 다음과 같은 오류가 발생한다.
  • 데이터가 여러 개 존재하는 경우 polls.models.Question.MultipleObjectsReturned: get() returned more than one Question -- it returned 2! 다음과 같은 오류가 발생한다.
Question.objects.get(id=1)
q = Question.objects.get(question_text__startswith='녹차') #녹차가 들어오는 질문을 가지고 온다
Question.objects.get(pub_date__year=2023) #2023년에 저장된 데이터를 가지고 온다 

2) filter를 이용한 필터링

  • filter를 사용한다면 아예 존재하지 않는 경우나 여러 개의 데이터가 찾아지는 경우도 QuerySet을 통해 표출된다.
Question.objects.filter(question_text__startswith='가장')

#output: <QuerySet [<Question: 제목: 가장 좋아하는 계절은?, 날짜: 2023-04-24 17:16:45+00:00>, <Question: 제목: 가장 좋아하는 디저트는?, 날짜: 2023-04-24 17:16:58+00:00>]>

3) QuerySetSQL 쿼리 보기

  • QuerySet으로 나오는 output값에 .query를 이용해 SQL 쿼리를 보여 줄 수 있다.
print(Question.objects.filter(question_text__startswith='가장').query)

#output: SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date" FROM "polls_question" WHERE "polls_question"."question_text" LIKE 가장% ESCAPE '\'
  • Question에서 choice_set으로 가면 QuerySet이지만 Choice에서 question으로 갈 때는 Choice에는 하나의 question만 존재하기 때문에 하나의 question만 나온다. 여러 개일 때만 QuerySet이 주어진다.

4) contains() 연산자 활용해서 필터링 하기

  • contains은 질문의 내용에 필터링 할 내용이 포함이 된다면 조회된다.
Question.objects.filter(question_text__contains='휴가')

5) gt() 이용해서 필터링 하기

  • gt()보다 클 때 조회하는 연산자이다.
Choice.objects.filter(votes__gt=0).query
print(Choice.objects.filter(votes__gt=0).query)
#output: SELECT "polls_choice"."id", "polls_choice"."question_id", "polls_choice"."choice_text", "polls_choice"."votes" FROM "polls_choice" WHERE "polls_choice"."votes" > 0 
#그래서 query문으로 빼면 where절에 votes > 0가 나오게 된다.

6) 정규표현식을 사용해 필터링 하기

Question.objects.filter(question_text__regex=r'^휴가.*어디')
print(Question.objects.filter(question_text__regex=r'^휴가.*어디').query)

#output: SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date", "polls_question"."owner_id" FROM "polls_question" WHERE "polls_question"."question_text" REGEXP ^휴가.*어디
#정규표현식을 사용할 수도 있다. 정규표현식을 사용하는 경우 where절에 정규표현식이 포함된 쿼리문이 나오게 된다.

7) 모델 관계 기반의 필터링 하기

  • filters(table명__column명__조건)을 이용해 필터를 해 준다.
print(Choice.objects.filter(question__question_text__startswith='가장').query)

#output: SELECT "polls_choice"."id", "polls_choice"."question_id", "polls_choice"."choice_text", "polls_choice"."votes" FROM "polls_choice" INNER JOIN "polls_question" ON ("polls_choice"."question_id" = "polls_question"."id") WHERE "polls_question"."question_text" LIKE 가장% ESCAPE '\'

** 8) exclude()를 이용해 필터링 하기

  • exclude()를 사용하면 조건에 해당되는 내용이 제외된 상태로 필터링이 된다.
Question.objects.exclude(question_text__startswith='휴가')  #휴가로 시작하는 질문만 제외하고 조회

12. 모델 메소드를 만들어서 활용하기

  • 모델에서 반복적으로 사용하는 기능은 메소드를 만들어서 사용할 수 있다.
  • 최근에 저장된 값에 [NEW]를 추가하는 기능을 메소드를 통해 만들어 보자.

1) 원하는 기능의 메소드를 모델에 추가

  • 최근에 저장된 건지 구분하는 메소드를 모델에 추가해 준다.
  • 이때 datetime.timedelta는 날짜 혹은 시간 사이의 간격을 만들어 주기 위해 사용되며 인자로는 days, hours, minutes 등 조작하고자 하는 시간을 넣을 수 있다.
from django.db import models
from django.utils import timezone
import datetime

class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField(auto_now_add = True)

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

2) [NEW]를 앞에 붙이기 위해 __str__ 수정

  • was_published_recently 메소드를 통해 이 데이터가 최근에 저장된 것인지 아닌지를 구분할 수 있게 되었다.
  • [NEW]를 보여지는 데이터 값으로 붙이기 위해서는 앞서 만든 메소드가 True이면 된다.
class Question(models.Model):
    question_text = models.CharField(max_length = 200)
    pub_date = models.DateTimeField(auto_now_add = True)

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def __str__(self):
        if self.was_published_recently():
            new_badge = '[new]'
        else:
            new_badge = ''
        return f'{new_badge} 제목: {self.question_text}, 날짜: {self.pub_date}'

3) Django shell을 통해 확인하기

from polls.models import *
Question.objects.all()

#output: <QuerySet [<Question: [new] 제목: 가장 좋아하는 계절은?, 날짜: 2023-04-24 17:16:45+00:00>, <Question: [new] 제목: 가장  좋아하는 디저트는?, 날짜: 2023-04-24 17:16:58+00:00>, <Question: [new] 제목: 커피 vs 녹차???, 날짜: 2023-04-24 17:57:35.166408+00:00>, <Question: [new] 제목: 휴가를 가실 계획인가요?, 날짜: 2023-04-24 18:44:47.059743+00:00>, <Question: [new] 제목: 가장 좋아하는 날씨는?, 날짜: 2023-04-24 19:52:14.187249+00:00>]>

🔎 어려웠던 내용 & 새로 알게 된 내용

1. Django Shell 나가는 단축키

  • 대부분의 Django를 명령창에서 사용할 때 종료하는 기능은 ctrl+C인데 Django Shell의 경우 exit()를 쳐서 나가야 한다.

✍ 회고

Django를 사용하기 위한 기본 설명을 들었다. Django 내부에서 데이터를 다루는 내용이 주 강의 내용이었다. Django에서 데이터를 다룰 때 SQL의 기본적인 지식이 있어야 한다고 생각했고 있어서 다행이라고 생각했다. 개인적으로 작성하다 보니 TIL이 이렇게 길어질 줄은 몰랐다. 시간이 될 때 Django만 따로 빼서 포스팅을 정리해야 되겠다고 생각했다.

profile
송의 개발 LOG
post-custom-banner

0개의 댓글