[0606] 거북이반 리트라이(1~6)

nikevapormax·2022년 6월 6일
0

TIL

목록 보기
40/116
post-thumbnail

😂 거북이반 리트라이

  • 거의 맨날 들으면서 진도를 같이 나갔는데, 오늘 하려니까 url도 헷갈리고 어떤 페이지에 뭐가 있는지 들어가서 찾아봐야 보여서(파일도 몇개 없다!) 시간도 있으니 다시 해버리자 했다.
  • vs code의 가상환경 생성 쪽을 중점적으로 기록할 생각이다. 이젠 다 기억하지만 몇일전에는 가상환경 키는 것도 까먹어서 작동이 안된다고 시간 낭비한 적이 있다.

😭 vs code 파이썬 가상환경 세팅

  • 가상환경 생성
$ python3 -m venv [원하는 가상환경 이름(나는 venv)]
  • 가상환경 실행
    • 가상환경 종료 : deactivate 입력
<mac os>
$ source venv(앞에서 설정한 이름)/bin/activate  

<window>
$ source [가상환경 이름]/Scripts/activate
  • 인터프리터 설정
    • command + shift + p를 눌러 설정창 열기
    • 아래와 같이 표시된 인터프리터 선택(별표)
    • terminal에 pip3 list 눌러 깔려있는 항목 확인
      • 처음이니까 당연히 깔끔해야 됨!
  • django 설치
$ pip3 install django
  • gitignore 설치

    • https://www.toptal.com/developers/gitignore/에서 나의 조건에 맞게 내용을 입력해서 파일 다운 (팀플 진행시에는 그냥 나에게 포함된 내용 다 치면 됨!)
    • 생성버튼을 누르면 다음과 같은 글이 나오는데 복사
    • .gitignore 파일을 생성하고 위 내용 복붙
    • 그리고 우리가 가상환경을 만들었기 때문에 해당 내용에 venv 넣기
      ### Django ###
      *.log
      *.pot
      *.pyc
      __pycache__/
      local_settings.py
      db.sqlite3
      db.sqlite3-journal
      media
      venv
  • git repository와 내 로컬 파일 연결

    • 새로운 레포 생성
      • 레포 주소 복사하기
    • cli를 사용해 레포와 내 로컬 파일 연결
      $ git init
      $ git remote add origin https://github.com/레포 주소~~~
      $ git add .
      $ git commit -m 'initial commit'
      $ 만약 메인 브랜치 이름이 master일 경우 바꾸고 싶다면
        git branch -m master main
        git fetch origin
        git branch -u origin/main main
        git remote set-head origin -a
      $ git push origin main
    • github 확인
      • 쓸데없는 파일이 안올라가고 아주 이쁘게 gitignore 하나만 올라간 것을 볼 수 있음
  • django project 시작하기

    • terminal에 다음과 같은 명령어 입력
      • . 을 붙인다 : 현재 폴더에 프로젝트 생성
      • . 을 뺀다 : 현재 폴더에서 폴더를 하나 더 만들고 프로젝트 생성
      $ django-admin startproject what_should_i_eat_today .
    • manage.py가 현재 폴더에 생성되었으면 잘한 것!
  • 변경사항이 생겼으니 바로 깃 커밋

  • 우리가 설치한 모듈을 requirements.txt로 만들어 관리

    $ pip3 freeze > requirements.txt 

    • 새로운 모듈이 추가될 때마다 하는 것이 좋음!
    • 지금 하나 만들었으니까 바로 깃 커밋 진행
    • 다른 팀원이 해당 프로젝트를 클론해 갈 때 어떤 것이 깔렸는지 알 수 있음
    • pip install -r requirements.txt를 사용하면 깔린 모듈을 한 번에 깔 수 있음!
  • 지금까지 진행한 설정 결과


😭 프로젝트 구조

  • 프로젝트는 app들의 집합
  • what_should_i_eat_today 폴더 안에 있는 파일들
  • __init__.py
    • 파이썬에게 해당 디렉터리를 하나의 파이썬 패키지로 다루도록 지시
  • settings.py
    • 웹사이트의 모든 설정이 포함되어 있는 파일
    • 우리의 프로젝트의 시간대와 언어를 추후 바꿀 예정
  • urls.py
    • url들을 관리하는 파일
  • wsgi.py
    • web server gateway interface
    • 배포를 할 때 사용하는 파일
    • 외부와 우리 프로젝트를 연결할 때 사용되는 중요한 친구
  • asgi.py
    • asynchronous server gateway interface
    • wsgi.py보다 성능이 좋은 친구
    • 비동기식 웹 서버

😭 애플리케이션 생성

  • 실제 요청을 처리하고 페이지를 처리하는 역할
  • 절대적 기준은 없지만 기능별로 많이 생성

- 생성 과정

  • 일반적으로 app의 이름은 복수형으로 생성
    $ python manage.py startapp articles 
  • 해당 코드를 터미널에 입력하고 에러가 안나면 성공
  • app을 생성하였으니 깃 커밋 진행

- 'articles' app 구조 파악

  • admin.py
    • 관리자용 페이지 기능 작성
    • 우리가 만든 모델을 작성하면 관리자 페이지에서 접근 가능
  • apps.py
    • app의 정보가 담겨 있음
    • 우리가 굳이 작업할 것 없음
  • models.py
    • 모델을 작성하는 곳
    • 데이터베이스에 어떤 스키마가 들어가는지 작성
  • tests.py
    • 테스트 코드를 작성하는 곳
    • 기능이 정상작동하는지 검사할 수 있음
    • 테스트 코드를 실행함으로써 수십 수백가지의 테스트를 진행할 수 있음
  • views.py
    • api 로직들이 작성되는 곳
    • 대부분의 코드가 짜여지는 곳

- app 등록

  • what_should_i_eat_today/settings.py에 생성한 app의 등록을 진행
#### 상단 생략 ####

# Application definition

INSTALLED_APPS = [
    'articles',
    
    
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

#### 하단 생략 ####


# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/

LANGUAGE_CODE = 'ko-kr'

TIME_ZONE = 'Asia/Seoul'


#### 하단 생략 ####
  • server 실행
    • 서버가 정상적으로 실행되면 app 설치가 잘된 것!
      $ python manage.py runserver

😭 url 관리

  • django는 flask와 다르게 urls.py라는 파일을 통해 모든 url을 관리
  • 전체 프로젝트에 속하는 urls.py가 있고, 각 app마다 urls.py를 가지고 있음
  • 그래서 우리는 각 app별 urls.py를 전체 프로젝트의 urls.py에 알려주어야 사용할 수 있음

- 연습

  • 현재 우리는 articles app에 있는 views.py의 함수를 url을 연결함으로 인해 사용하도록 할 것이다. 따라서 articles app에서 views.py를 import하도록 할 것이다.
  • 이렇게 할 수 있는 이유는 우리가 앞에서 확인했던 __init__.py로 인해 각 app들이 모듈로서 사용되기 때문이다.
  • what_should_i_eat_today/urls.py
    • 현재의 방식은 app들이 늘어남에 따라 비효율적이므로, 추후 include를 사용해 리팩토링할 예정
from django.contrib import admin
from django.urls import path
from articles import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
]
  • 이렇게 작성하고 해당 url을 작성해 페이지에 들어가보면 되지 않음
    • index/로 들어가면 실행될 index 함수가 정의되지 않아서임!
  • 그래서 우리는 articles/views.py를 수정해야 함
    • path('index/', views.index)의 views.index의 index와 함수 이름이 꼭 반드시 무조건 동일해야 함
    • 함수의 인자와 render의 인자는 꼭 request가 첫 번째임!
from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, 'index.html')
  • 이제 render 안에 들어가 있는 index.html을 생성
    • templates 폴더 안에 생성해야 하며, templates 폴더는 각 app 안에 생성하도록 함
  • index.html을 생성하고 다시 서버를 돌리게 되면 아래의 결과가 나옴

- 연습 2

  • dinner/을 만들어 오늘 저녁으로 뭘 먹을지 작성해보자
  • what_should_i_eat_today/urls.py
from django.contrib import admin
from django.urls import path
from articles import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('dinner/', views.dinner),
]
  • articles/views.py
from django.shortcuts import render

# Create your views here.
def index(request):
    return render(request, 'index.html')


def dinner(request):
    
    return render(request, 'dinner.html')
  • templates/dinner.html을 만든 후, 일단 되나 시험

- 연습 2 / 1차 튜닝

  • articles/views.py
import random
from django.shortcuts import render

# Create your views here.
def dinner(request):
    menus = ['족발', '햄버거', '치킨', '삼겹살']
    pick = random.choice(menus)
    context = {
        'pick': pick,
    }
    return render(request, 'dinner.html', context)
  • templates/dinner.html
<h1>오늘 저녁은 [{{ pick }}]입니다.</h1>

- 변수형 url / 2차 튜닝

  • url을 변수처럼 사용해 동적으로 주소를 만드는 것
  • what_should_i_eat_today/urls.py : dinner url의 개인화 진행
    • <str:name>와 같이 정수인지 문자인지 정해주어야 함
from django.contrib import admin
from django.urls import path
from articles import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('dinner/<str:name>/', views.dinner),
]
  • articles/views.py
    • context에 인자로 받은 name 추가해 프론트로 같이 쏴줌
> import random
from django.shortcuts import render

# Create your views here.
def dinner(request, name):
    menus = ['족발', '햄버거', '치킨', '삼겹살']
    pick = random.choice(menus)
    context = {
        'pick': pick,
        'name': name,
    }
    return render(request, 'dinner.html', context)
  • templates/dinner.html
<h1>오늘 {{ name }}님의 저녁은 [{{ pick }}]입니다.</h1>

- DTL / 3차 튜닝

  • Django Template Language
  • 나중에 가서는 잘 사용하지 않음
    • 현업에서는 프론트와 백앤드 파트가 완전히 분리된 경우가 많기 때문에 잘 사용하지 않음
    • 현재는 이해를 위해 학습
  • 사용 빈도수가 좀 있는 if문과 for문을 중심으로 학습 진행
  • for문과 if문을 활용해 저녁 리스트 작성
  • articles/views.py
import random
from django.shortcuts import render

# Create your views here.
def dinner(request, name):
    menus = [{'name': '족발', 'price': 35000}, 
    {'name': '햄버거', 'price': 9000}, 
    {'name': '치킨', 'price': 18000}, 
    {'name': '삼겹살', 'price': 12000}]
    pick = random.choice(menus)
    context = {
        'pick': pick,
        'name': name,
        'menus': menus,
    }
    return render(request, 'dinner.html', context)
  • templates/dinner.html
    • for문을 활용해 리스트의 모든 내용을 다 불러옴
    • if문을 활용해 조건에 맞는 내용을 출력해줌
    • 작성 시 띄어쓰기를 꼭 준수해야 함!
<h1>오늘 {{ name }}님의 저녁은 [{{ pick.name }}]입니다.</h1>

<h1>메뉴 리스트</h1>
<ul>
    {% for menu in menus %}
        <li>{{ menu.name }}  :  {{ menu.price }} 원</li>
    {% endfor %}
</ul>

{% if pick.price > 20000 %}
    <p>비싸다,,,</p>
{% elif pick.price > 10000 %}
    <p>해볼만하다,,!</p>
{% else %}
    <p>맛있겠다!!</p>
{% endif %}


😭 form 태그

  • 핵심속성인 actionmethod를 잘 작성해야 함
    • action : 어느 페이지로 이동할 것인지
    • method : get인지 post인지 작성
  • form 태그를 사용하면 get과 post만 사용할 수 있어 아래와 같이 작성할 수 밖에 없음
  • 추후에 프론트와 백앤드를 나누게 되면 아래와 같이 설계하도록 해야 함

- 연습

  • review.html에서 보낸 내용을 review_result.html에서 볼 수 있도록 진행
  • request는 요청에 대한 모든 정보를 담고 있는 변수
  • what_should_i_eat_today/urls.py
from django.contrib import admin
from django.urls import path
from articles import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('dinner/<str:name>/', views.dinner),
    path('review/', views.review),
    path('create_review/', views.create_review),
]
  • articles/views.py
#### 상단 생략 ####

def review(request):
    return render(request, 'review.html')


def create_review(request):
    content = request.POST.get('content')
    print(content)
    context = {
        'content': content,
    }
    
    return render(request, 'review_result.html', context)
  • templates/review.html
<form action="/create_review/" method="POST">
    {% csrf_token %}
    <label for="content">보낼 메세지 : </label>
    <input type="text" id="content" name="content" />
    <button type="submit">보내기</button>
</form>

  • templates/review_result.html
<h1>여기서 받은 내용은 {{ content }}야!</h1>

😭 url 재설정

- include 사용

  • 하나의 app을 추가적으로 생성
$ python manage.py startapp foods
  • what_should_i_eat_today/settings.py
#### 상단 생략 ####

# Application definition

INSTALLED_APPS = [
    'articles',
    'foods',
    
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

#### 하단 생략 ####
  • 이렇게 되면 각 app에서 views.py를 작성할 수 있기 때문에 url을 깔끔하게 관리할 필요가 있음
    • 모든 앱들의 url이 한 곳에 다 모이면 구분하기 힘들게 될 것
  • 따라서 include를 사용하도록 함
  • what_should_i_eat_today/urls.py
    • 추후에 만들 foods ap의 url도 아래와 같이 작성하면 됨
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('articles/', include('articles.urls')),
    path('foods/', include('foods.urls')),
]
  • 그리고 articles app에도 urls.py를 만듦
from django.urls import path
from . import views    

urlpatterns = [
    path('index/', views.index),
    path('dinner/<str:name>/', views.dinner),
    path('review/', views.review),
    path('create_review/', views.create_review),
]
  • 이렇게 나누었기 때문에 이제 아래와 같이 url 주소를 입력해 주어야 우리가 원하는 페이지로 이동할 수 있음

- url의 이름 설정

  • articles/urls.py
    • 다음과 같이 path를 작성하면서 name=url이름을 설정해주면 url을 사용하면서 name을 주소대신 사용할 수 있음
    • 이름을 대신 사용하면 우리가 변수를 사용할 때와 같은 편리한 점이 존재
    • 변수를 사용하면 변수 안의 내용이 변경된다해도 문제될 것이 없음
    • 여기서도 같은 개념으로 생각하면 됨!
      url 주소가 변경될 수도 있지만 이름을 사용하게 되면 우리가 해당 파일에서만 주소를 변경하면 모든 곳에 똑같이 적용
  • 마찬가지로 app의 이름도 아래와 같이 선언해줄 수 있음
    • 이렇게 되면 각 app별로 똑같은 이름의 url을 가질 수 있음
      • index.html과 같은 파일은 각 app별로 각각 많이 쓰이기 때문에 이렇게 이름을 설정하게 되면 충돌되지 않고 모두 사용 가능
from django.urls import path
from . import views    

app_name = 'articles'

urlpatterns = [
       path('index/', views.index),
    path('dinner/<str:name>/', views.dinner),
    path('review/', views.review, name='review'),
    path('create_review/', views.create_review, name='create_review'),
]
  • templates/review.html
    • 위에서 선언한 이름을 토대로 url 주소를 다음과 같이 변경함
      {% 'url articles:create_review' %}
    • 앞에 있는 articles는 app의 이름!
<form action="{% url 'articles:create_review' %}" method="POST">
    {% csrf_token %}
    <label for="content">보낼 메세지 : </label>
    <input type="text" id="content" name="content" />
    <button type="submit">보내기</button>
</form>
  • 테스트를 진행 시 신호가 아주 잘가는 것을 볼 수 있음

😭 template 상속

  • django를 만든 사람들의 철학은 지속적으로 들어가는 똑같은 부분을 html 파일에서 반복할 필요가 없다는 것
  • 따라서 base가 되는 파일 아래 다른 파일들을 상황에 따라 이어 붙여 사용함
  • 이를 가능하게 해주는 것이 template 상속
  • templates/base.html 작성
<h1>헤더 부분</h1>

{% block content %}
{% endblock %}

<h1>푸터 부분</h1>
  • templates/dinner.html 변경
{% extends 'base.html' %}

{% block content %}
<h1>오늘 {{ name }}님의 저녁은 [{{ pick.name }}]입니다.</h1>

<h1>메뉴 리스트</h1>
<ul>
    {% for menu in menus %}
        <li>{{ menu.name }}  :  {{ menu.price }} 원</li>
    {% endfor %}
</ul>

{% if pick.price > 20000 %}
    <h2>비싸다,,,</h2>
{% elif pick.price > 10000 %}
    <h2>해볼만하다,,!</h2>
{% else %}
    <h2>맛있겠다!!</h2>
{% endif %}

{% endblock %}
  • 서버를 돌려보면 잘 적용된 것을 알 수 있음
    • base.htmldinner.html에 모두 {% block content %}{% endblock %}이 있고 content라는 이름 또한 같다는 것을 알 수 있음 (반드시 같아야 함)
    • dinner.html에서 {% extends 'base.html' %}을 통해 base.html의 헤더와 푸터 부분을 상속받았으므로 {% block content %}{% endblock %} 안에 있는 내용이 들어가 웹페이지가 아래와 같이 변하는 것
    • 쉽게 생각해서 base.html{% block content %}{% endblock %}에 상황에 맞는 html 파일들의 {% block content %}{% endblock %} 내용들이 들어가게 되는 것!

😭 ORM

  • Object Relational Mapping
  • vs code에서 sqlite3를 사용하기 위해 SQLite Viewer 설치

- model 생성

  • articles/models.py
from django.db import models

# Create your models here.
class Article(models.Model): # 상속
    title = models.CharField(max_length=10)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
  • Model커맨드 + 클릭하게 되면 models 안에 있는 class Model의 정보를 볼 수 있음. 해당 페이지에서 어떤 것을 상속받아 사용할 수 있는지 확인 가능

- migration 진행

  • model을 생성하고 migration을 꼭 진행해야 함
$ python manage.py makemigrations
$ python manage.py migrate

  • migration을 진행한 후, 옆에 탐색기를 보면 해당 파일이 생성됨
    • 0001_initial.py를 누르면 자세한 내용 확인 가능
  • db.sqlite3에 들어가서 확인
    • migration을 한 후 많은 테이블들이 생성된 것을 알 수 있음
      (django의 디폴트값)
  • 터미널에서도 migration이 잘 되었는지 확인 가능
$ python manage.py sqlmigrate [app name] 0001

😭 admin 계정 사용

- superuser 생성

  • terminal에 아래 코드를 입력해 생성
$ python manage.py createsuperuser

  • 이러고 바로 admin 사이트로 직행
  • 하지만 여기에는 우리가 생성한 모델이 없음
  • 당연한 것이 우리는 우리가 생성한 모델을 admin에서 사용한다고 django에게 알려준 적이 없음
  • 따라서 알려주러 고고
  • articles/admin.py
from django.contrib import admin
from .models import Article

# Register your models here.
admin.site.register(Article)

  • 성공적으로 반영된 것을 알 수 있음

- admin에서 CRUD 진행

  • 위의 사진에서 보이듯이 +추가를 눌러 새로운 요소를 입력할 수 있음
  • 다음과 같이 생성 가능하며, 수정, 삭제 또한 가능하다.
  • db에서도 추가된 내용을 확인할 수 있다.

😭 CRUD

- base.html 수정

  • 제대로 된 보일러 플레이트에 내용 작성
  • 이전과 마찬가지로 상속을 위해 {% block content %}{% endblock %} 작성
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- CSS only -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <title>오늘 뭐먹지??</title>
</head>
<body class="container">
    {% block content %}
    {% endblock %}

    <!-- JavaScript Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" 
    integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
</body>
</html>

- 리뷰 리스트 만들기

  • admin 페이지를 통해 채운 더미데이터를 리스트로 뽑아보자
  • articles/views.py
import random
from django.shortcuts import render
from .models import Article

# Create your views here.
def dinner(request, name):
    menus = [{'name': '족발', 'price': 35000}, {'name': '햄버거', 'price': 9000}, {'name': '치킨', 'price': 18000}, {'name': '삼겹살', 'price': 12000}]
    pick = random.choice(menus)
    articles = Article.objects.order_by('-pk')
    context = {
        'pick': pick,
        'name': name,
        'menus': menus,
        'articles': articles,
    }
    return render(request, 'dinner.html', context)
    
#### 하단 생략 ####
  • templates/dinner.html
{% extends 'base.html' %}

{% block content %}
<h1>오늘 {{ name }}님의 저녁은 [{{ pick.name }}]입니다.</h1>

<h1>메뉴 리스트</h1>
<ul>
    {% for menu in menus %}
        <li>{{ menu.name }}  :  {{ menu.price }} 원</li>
    {% endfor %}
</ul>

{% if pick.price > 20000 %}
    <h2>비싸다,,,</h2>
{% elif pick.price > 10000 %}
    <h2>해볼만하다,,!</h2>
{% else %}
    <h2>맛있겠다!!</h2>
{% endif %}
<br />

<h1>리뷰 리스트</h1>
{% for article in articles %}
    <p>글 번호 : {{ article.pk }}</p>
    <p>글 제목 : {{ article.title }}</p>
    <p>글 내용 : {{ article.content }}</p>
    <hr />
{% endfor %}

{% endblock %}

- 글 작성 페이지

  • articles/review.html
{% extends 'base.html' %}

{% block content %}

<form class="form-group" action="{% url 'articles:create_review' %}" method="POST">
    {% csrf_token %}
    <label for="title">Title : </label>
    <input class="form-control" type="text" name="title" /><br />
    <label for="content">Content : </label>
    <textarea class="form-control" name="content" cols="30" rows="5"></textarea><br />
    <button type="submit">보내기</button>
</form>

{% endblock %}

- 글 저장 및 화면에 띄우기

  • articles/views.py
import random
from django.shortcuts import render, redirect
from .models import Article

# Create your views here.

#### 상단 생략 ####


def create_review(request):
    title = request.POST.get('title')
    content = request.POST.get('content')

    article = Article(title=title, content=content)
    article.save()
    
    return redirect('/articles/dinner/messi')

profile
https://github.com/nikevapormax

0개의 댓글